diff --git a/app/src/main/cpp/core/arm/cpu.cpp b/app/src/main/cpp/core/arm/cpu.cpp index fba51d03..8e17234a 100644 --- a/app/src/main/cpp/core/arm/cpu.cpp +++ b/app/src/main/cpp/core/arm/cpu.cpp @@ -1,5 +1,39 @@ #include "cpu.h" +// TODO: Handle Unicorn errors namespace core { + Cpu::Cpu() { + uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); + uc_hook hook{}; + uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)HookInterrupt, this, 0, -1); + } + + void Cpu::Run(uint64_t address) { + uc_emu_start(uc, address, 1ULL << 63, 0, 0); + } + + uint64_t Cpu::GetRegister(uint32_t regid) { + uint64_t registerValue; + uc_reg_read(uc, regid, ®isterValue); + return registerValue; + } + + void Cpu::SetRegister(uint32_t regid, uint64_t value) { + uc_reg_write(uc, regid, &value); + } + + void Cpu::HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data) { + if (intno == 2) { + uint32_t instr{}; + uc_mem_read(uc, GetRegister(UC_ARM64_REG_PC) - 4, &instr, 4); + + uint32_t svcId = instr >> 5 & 0xFF; + + // TODO: Handle SVCs + } else { + syslog(LOG_ERR, "Unhandled interrupt #%i", intno); + uc_close(uc); + } + } } \ No newline at end of file diff --git a/app/src/main/cpp/core/arm/cpu.h b/app/src/main/cpp/core/arm/cpu.h index d57a6c69..d941235a 100644 --- a/app/src/main/cpp/core/arm/cpu.h +++ b/app/src/main/cpp/core/arm/cpu.h @@ -1,10 +1,20 @@ #pragma once - +#include #include namespace core { class Cpu { - private: + public: + Cpu(); + ~Cpu() { uc_close(uc); }; + + void Run(uint64_t address); + + uint64_t GetRegister(uint32_t regid); + void SetRegister(uint32_t regid, uint64_t value); + uc_engine *uc; + private: + void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data); }; } \ No newline at end of file diff --git a/app/src/main/cpp/core/arm/memory.cpp b/app/src/main/cpp/core/arm/memory.cpp index 2da5a448..367a9b40 100644 --- a/app/src/main/cpp/core/arm/memory.cpp +++ b/app/src/main/cpp/core/arm/memory.cpp @@ -3,19 +3,17 @@ #include #include "memory.h" -namespace core::mem { - std::vector memRegions; +namespace core::memory { + std::vector memoryRegions; bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label) { void* ptr = mmap((void*)(address), size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0); - if(!ptr) - return false; + if (!ptr) return false; // Skipping this until the CPU implementation is working - if(uc) { + if (uc) { uc_err err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, ptr); - if(err) - { + if (err) { syslog(LOG_ERR, "Memory map failed: %s", uc_strerror(err)); return false; } @@ -23,20 +21,21 @@ namespace core::mem { syslog(LOG_INFO, "Successfully mapped region '%s' to 0x%x", label.c_str(), address); - memRegions.push_back({label, address, size, ptr}); - + memoryRegions.push_back({label, address, size, ptr}); return true; } // TODO: Boundary checks void Write(void* data, uint64_t offset, size_t size) { std::memcpy((void*)(offset), data, size); } - void WriteU8(uint8_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 1); } + + void WriteU8 (uint8_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 1); } void WriteU16(uint16_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 2); } void WriteU32(uint32_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 4); } void WriteU64(uint64_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 8); } void Read(void* destination, uint64_t offset, size_t size) { std::memcpy(destination, (void*)(offset), size); } - uint8_t ReadU8(uint64_t offset) { uint8_t value; Read(reinterpret_cast(&value), offset, 1); return value; } + + uint8_t ReadU8 (uint64_t offset) { uint8_t value; Read(reinterpret_cast(&value), offset, 1); return value; } uint16_t ReadU16(uint64_t offset) { uint16_t value; Read(reinterpret_cast(&value), offset, 2); return value; } uint32_t ReadU32(uint64_t offset) { uint32_t value; Read(reinterpret_cast(&value), offset, 4); return value; } uint64_t ReadU64(uint64_t offset) { uint64_t value; Read(reinterpret_cast(&value), offset, 8); return value; } diff --git a/app/src/main/cpp/core/arm/memory.h b/app/src/main/cpp/core/arm/memory.h index 48568e7d..17077a00 100644 --- a/app/src/main/cpp/core/arm/memory.h +++ b/app/src/main/cpp/core/arm/memory.h @@ -2,26 +2,28 @@ #include #include -#define MEM_BASE 0x80000000 +#define BASE_ADDRESS 0x80000000 -namespace core::mem { +namespace core::memory { struct MemoryRegion { std::string label; - uint64_t address; - size_t size; - void* ptr; + uint64_t address; + size_t size; + void* ptr; }; - bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label=""); + bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label = {}); void Write(void* data, uint64_t offset, size_t size); - void WriteU8(uint8_t value, uint64_t offset); + + void WriteU8 (uint8_t value, uint64_t offset); void WriteU16(uint16_t value, uint64_t offset); void WriteU32(uint32_t value, uint64_t offset); void WriteU64(uint64_t value, uint64_t offset); void Read(void* destination, uint64_t offset, size_t size); - uint8_t ReadU8(uint64_t offset); + + uint8_t ReadU8 (uint64_t offset); uint16_t ReadU16(uint64_t offset); uint32_t ReadU32(uint64_t offset); uint64_t ReadU64(uint64_t offset); diff --git a/app/src/main/cpp/core/hos/kernel/svc.cpp b/app/src/main/cpp/core/hos/kernel/svc.cpp new file mode 100644 index 00000000..e69de29b diff --git a/app/src/main/cpp/core/hos/loaders/nro.cpp b/app/src/main/cpp/core/hos/loaders/nro.cpp index 1138b8f3..7a033772 100644 --- a/app/src/main/cpp/core/hos/loaders/nro.cpp +++ b/app/src/main/cpp/core/hos/loaders/nro.cpp @@ -19,35 +19,34 @@ namespace core::loader { bool LoadNro(std::string file) { syslog(LOG_INFO, "Loading NRO file %s\n", file.c_str()); - NroHeader h; - ReadDataFromFile(file, reinterpret_cast(&h), 0x0, sizeof(NroHeader)); - if (h.magic != 0x304F524E) { - syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", h.magic); + NroHeader header; + ReadDataFromFile(file, reinterpret_cast(&header), 0x0, sizeof(NroHeader)); + if (header.magic != 0x304F524E) { + syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", header.magic); return false; } std::vector text, ro, data; - text.resize(h.segments[0].size); - ro.resize(h.segments[1].size); - data.resize(h.segments[2].size); + text.resize(header.segments[0].size); + ro.resize (header.segments[1].size); + data.resize(header.segments[2].size); - ReadDataFromFile(file, reinterpret_cast(text.data()), h.segments[0].fileOffset, h.segments[0].size); - ReadDataFromFile(file, reinterpret_cast(ro.data()), h.segments[1].fileOffset, h.segments[1].size); - ReadDataFromFile(file, reinterpret_cast(data.data()), h.segments[2].fileOffset, h.segments[2].size); + ReadDataFromFile(file, reinterpret_cast(text.data()), header.segments[0].fileOffset, header.segments[0].size); + ReadDataFromFile(file, reinterpret_cast(ro.data()), header.segments[1].fileOffset, header.segments[1].size); + ReadDataFromFile(file, reinterpret_cast(data.data()), header.segments[2].fileOffset, header.segments[2].size); - if( !mem::Map(nullptr, MEM_BASE, h.segments[0].size, ".text") || - !mem::Map(nullptr, MEM_BASE + h.segments[0].size, h.segments[1].size, ".ro") || - !mem::Map(nullptr, MEM_BASE + h.segments[0].size + h.segments[1].size, h.segments[2].size, ".data") || - !mem::Map(nullptr, MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size, h.bssSize, ".bss")) { + if( !memory::Map(nullptr, BASE_ADDRESS, header.segments[0].size, ".text") || + !memory::Map(nullptr, BASE_ADDRESS + header.segments[0].size, header.segments[1].size, ".ro") || + !memory::Map(nullptr, BASE_ADDRESS + header.segments[0].size + header.segments[1].size, header.segments[2].size, ".data") || + !memory::Map(nullptr, BASE_ADDRESS + header.segments[0].size + header.segments[1].size + header.segments[2].size, header.bssSize, ".bss")) { syslog(LOG_ERR, "Failed mapping regions for executable"); return false; } - mem::Write(text.data(), MEM_BASE, text.size()); - mem::Write(ro.data(), MEM_BASE + h.segments[0].size, ro.size()); - mem::Write(data.data(), MEM_BASE + h.segments[0].size + h.segments[1].size, data.size()); - + memory::Write(text.data(), BASE_ADDRESS, text.size()); + memory::Write(ro.data(), BASE_ADDRESS + header.segments[0].size, ro.size()); + memory::Write(data.data(), BASE_ADDRESS + header.segments[0].size + header.segments[1].size, data.size()); return true; } } \ No newline at end of file diff --git a/app/src/main/cpp/include/unicorn/unicorn.h b/app/src/main/cpp/include/unicorn/unicorn.h index a53cce0d..531ce1e8 100644 --- a/app/src/main/cpp/include/unicorn/unicorn.h +++ b/app/src/main/cpp/include/unicorn/unicorn.h @@ -681,7 +681,7 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context); /* Free the memory allocated by uc_context_alloc & uc_mem_regions. - @mem: memory allocated by uc_context_alloc (returned in *context), or + @memory: memory allocated by uc_context_alloc (returned in *context), or by uc_mem_regions (returned in *regions) @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum