diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 0001316e..1ea2ffb6 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -9,7 +9,8 @@ include_directories(${source_DIR}/include) add_library(lightswitch SHARED ${source_DIR}/lightswitch.cpp ${source_DIR}/core/arm/cpu.cpp + ${source_DIR}/core/arm/memory.cpp ${source_DIR}/core/hos/loaders/nro.cpp ) -target_link_libraries(lightswitch ${source_DIR}/lib/${ANDROID_ABI}/libunicorn.a) \ No newline at end of file +target_link_libraries(lightswitch ${source_DIR}/lib/${ANDROID_ABI}/libunicorn.a) diff --git a/app/src/main/cpp/core/arm/memory.cpp b/app/src/main/cpp/core/arm/memory.cpp new file mode 100644 index 00000000..5f6f8d12 --- /dev/null +++ b/app/src/main/cpp/core/arm/memory.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include "memory.h" + +std::vector memRegions; + +namespace mem { + 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; + + // Skipping this until the CPU implementation is working + if(uc) { + uc_err err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, ptr); + if(err) + { + syslog(LOG_ERR, "Memory map failed: %s", uc_strerror(err)); + return false; + } + } + + syslog(LOG_INFO, "Successfully mapped region '%s' to 0x%x", label.c_str(), address); + + memRegions.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 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; } + 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; } +} \ No newline at end of file diff --git a/app/src/main/cpp/core/arm/memory.h b/app/src/main/cpp/core/arm/memory.h new file mode 100644 index 00000000..2d76cd15 --- /dev/null +++ b/app/src/main/cpp/core/arm/memory.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +#define MEM_BASE 0x80000000 + +namespace mem { + struct MemoryRegion { + std::string label; + uint64_t address; + size_t size; + void* ptr; + }; + + 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 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); + uint16_t ReadU16(uint64_t offset); + uint32_t ReadU32(uint64_t offset); + uint64_t ReadU64(uint64_t offset); +} \ No newline at end of file diff --git a/app/src/main/cpp/core/hos/loaders/nro.cpp b/app/src/main/cpp/core/hos/loaders/nro.cpp index 7fd0fdc6..07d24e97 100644 --- a/app/src/main/cpp/core/hos/loaders/nro.cpp +++ b/app/src/main/cpp/core/hos/loaders/nro.cpp @@ -1,13 +1,10 @@ #include -#include #include #include #include +#include "../../arm/memory.h" #include "nro.h" -// TODO: Move memory to it's own file -#define MEM_BASE 0x80000000 - void ReadDataFromFile(std::string file, char* output, uint32_t offset, size_t size) { std::ifstream f(file, std::ios::binary | std::ios::beg); @@ -34,30 +31,22 @@ namespace loader { ro.resize(h.segments[1].size); data.resize(h.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()), 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); - - if(!mmap((void*)(MEM_BASE), - h.segments[0].size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) || - !mmap((void*)(MEM_BASE + h.segments[0].size), - h.segments[1].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) || - !mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size), - h.segments[2].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0) || - !mmap((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size), - h.bssSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0)) { + 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")) { syslog(LOG_ERR, "Failed mapping regions for executable"); return false; } - std::memcpy((void*)(MEM_BASE), text.data(), text.size()); - std::memcpy((void*)(MEM_BASE + h.segments[0].size), ro.data(), ro.size()); - std::memcpy((void*)(MEM_BASE + h.segments[0].size + h.segments[1].size), data.data(), data.size()); + 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()); return true; }