Fix Cyuubi's CPU implementation

This commit is contained in:
Ryan Teal 2019-07-02 20:40:35 +01:00
parent 67b2ee3ea5
commit 5cece7daed
No known key found for this signature in database
GPG Key ID: 8DBEE0F12C7E2D23
5 changed files with 69 additions and 55 deletions

View File

@ -1,57 +1,83 @@
#include <sys/mman.h>
#include "cpu.h" #include "cpu.h"
#include "memory.h" #include "memory.h"
// TODO: Handle Unicorn errors // TODO: Handle Unicorn errors
namespace core { namespace core::cpu {
Cpu* currentContext; uc_engine *uc;
void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data); void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data);
Cpu::Cpu() { uint64_t GetRegister(uint32_t regid);
void SetRegister(uint32_t regid, uint64_t value);
bool Initialize() {
uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
uc_hook hook{}; uc_hook hook{};
uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)HookInterrupt, this, 1, 0); uc_hook_add(uc, &hook, UC_HOOK_INTR, (void *) HookInterrupt, 0, 1, 0);
// Map stack memory // Map stack memory
memory::Map(uc, 0x3000000, 0x1000000, "stack"); if (!memory::Map(0x3000000, 0x1000000, "stack")) return false;
SetRegister(UC_ARM64_REG_SP, 0x3100000); SetRegister(UC_ARM64_REG_SP, 0x3100000);
memory::Map(uc, 0x2000000, 0x1000, "tls"); // Map TLS memory
if (!memory::Map(0x2000000, 0x1000, "tls")) return false;
SetRegister(UC_ARM64_REG_TPIDRRO_EL0, 0x2000000); SetRegister(UC_ARM64_REG_TPIDRRO_EL0, 0x2000000);
currentContext = this; return true;
} }
void Cpu::Run(uint64_t address) { void Run(uint64_t address) {
uc_err err = uc_emu_start(uc, address, 1ULL << 63, 0, 0); uc_err err = uc_emu_start(uc, address, 1ULL << 63, 0, 0);
if(err) if (err)
syslog(LOG_ERR, "uc_emu_start failed: %s", uc_strerror(err)); syslog(LOG_ERR, "uc_emu_start failed: %s", uc_strerror(err));
} }
uint64_t Cpu::GetRegister(uint32_t regid) { uint64_t GetRegister(uint32_t regid) {
uint64_t registerValue; uint64_t registerValue;
uc_reg_read(uc, regid, &registerValue); uc_reg_read(uc, regid, &registerValue);
return registerValue; return registerValue;
} }
void Cpu::SetRegister(uint32_t regid, uint64_t value) { void SetRegister(uint32_t regid, uint64_t value) {
uc_reg_write(uc, regid, &value); uc_reg_write(uc, regid, &value);
} }
void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data) { void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data) {
syslog(LOG_WARNING, "Interrupt called at x%x", currentContext->GetRegister(UC_ARM64_REG_PC));
if (intno == 2) { if (intno == 2) {
uint32_t instr{}; uint32_t instr{};
uc_mem_read(uc, currentContext->GetRegister(UC_ARM64_REG_PC) - 4, &instr, 4); uc_mem_read(uc, GetRegister(UC_ARM64_REG_PC) - 4, &instr, 4);
uint32_t svcId = instr >> 5 & 0xFF; uint32_t svcId = instr >> 5 & 0xFF;
// TODO: Handle SVCs // TODO: Handle SVCs
syslog(LOG_DEBUG, "SVC 0x%x called!", svcId); syslog(LOG_DEBUG, "SVC 0x%x called!", svcId);
uc_close(uc);
} else { } else {
syslog(LOG_ERR, "Unhandled interrupt #%i", intno); syslog(LOG_ERR, "Unhandled interrupt #%i", intno);
uc_close(uc); uc_close(uc);
} }
} }
}
Cpu* CpuContext() { return currentContext; }
// FIXME: Move this back to memory.cpp - zephyren25
namespace core::memory {
bool Map(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) {
syslog(LOG_ERR, "Failed mapping region '%s'", label.c_str());
return false;
}
uc_err err = uc_mem_map_ptr(core::cpu::uc, address, size, UC_PROT_ALL, (void*)(address));
if (err) {
syslog(LOG_ERR, "UC map failed: %s", uc_strerror(err));
return false;
}
syslog(LOG_DEBUG, "Successfully mapped region '%s' to 0x%x", label.c_str(), address);
return true;
}
} }

View File

@ -2,21 +2,12 @@
#include <syslog.h> #include <syslog.h>
#include <unicorn/unicorn.h> #include <unicorn/unicorn.h>
namespace core { namespace core::cpu {
class Cpu { bool Initialize();
public: void Run(uint64_t address);
Cpu();
~Cpu() { uc_close(uc); };
void Run(uint64_t address); uint64_t GetRegister(uint32_t regid);
void SetRegister(uint32_t regid, uint64_t value);
uint64_t GetRegister(uint32_t regid); // bool MapUnicorn(uint64_t address, size_t size);
void SetRegister(uint32_t regid, uint64_t value);
uc_engine *uc;
// private:
// void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data);
};
Cpu* CpuContext();
} }

View File

@ -4,26 +4,24 @@
#include "memory.h" #include "memory.h"
namespace core::memory { namespace core::memory {
std::vector<MemoryRegion> memoryRegions; // std::vector<MemoryRegion> memoryRegions;
//
bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label) { // bool Map(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); // void* ptr = mmap((void*)(address), size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0);
if (!ptr) return false; // if (!ptr) {
// syslog(LOG_ERR, "Failed mapping region '%s'", label.c_str());
// Skipping this until the CPU implementation is working // return false;
if (uc) { // }
uc_err err = uc_mem_map_ptr(uc, address, size, UC_PROT_ALL, ptr); //
if (err) { // syslog(LOG_INFO, "Mapping region '%s' to 0x%x, pointer %x", label.c_str(), address, (uint64_t)ptr);
syslog(LOG_ERR, "Memory map failed: %s", uc_strerror(err)); //
return false; // if (core::cpu::MapUnicorn(address, size, ptr)) return false;
} //
} // syslog(LOG_INFO, "Successfully mapped region '%s' to 0x%x", label.c_str(), address);
//
syslog(LOG_INFO, "Successfully mapped region '%s' to 0x%x", label.c_str(), address); // memoryRegions.push_back({label, address, size, ptr});
// return true;
memoryRegions.push_back({label, address, size, ptr}); // }
return true;
}
// TODO: Boundary checks // TODO: Boundary checks
void Write(void* data, uint64_t offset, size_t size) { std::memcpy((void*)(offset), data, size); } void Write(void* data, uint64_t offset, size_t size) { std::memcpy((void*)(offset), data, size); }

View File

@ -12,7 +12,7 @@ namespace core::memory {
void* ptr; void* ptr;
}; };
bool Map(uc_engine* uc, uint64_t address, size_t size, std::string label = {}); bool Map(uint64_t address, size_t size, std::string label = {});
void Write(void* data, uint64_t offset, size_t size); void Write(void* data, uint64_t offset, size_t size);

View File

@ -36,11 +36,10 @@ namespace core::loader {
ReadDataFromFile(file, reinterpret_cast<char *>(ro.data()), header.segments[1].fileOffset, header.segments[1].size); ReadDataFromFile(file, reinterpret_cast<char *>(ro.data()), header.segments[1].fileOffset, header.segments[1].size);
ReadDataFromFile(file, reinterpret_cast<char *>(data.data()), header.segments[2].fileOffset, header.segments[2].size); ReadDataFromFile(file, reinterpret_cast<char *>(data.data()), header.segments[2].fileOffset, header.segments[2].size);
uc_engine* uc = core::CpuContext()->uc; if( !memory::Map(BASE_ADDRESS, header.segments[0].size, ".text") ||
if( !memory::Map(uc, BASE_ADDRESS, header.segments[0].size, ".text") || !memory::Map(BASE_ADDRESS + header.segments[0].size, header.segments[1].size, ".ro") ||
!memory::Map(uc, BASE_ADDRESS + header.segments[0].size, header.segments[1].size, ".ro") || !memory::Map(BASE_ADDRESS + header.segments[0].size + header.segments[1].size, header.segments[2].size, ".data") ||
!memory::Map(uc, BASE_ADDRESS + header.segments[0].size + header.segments[1].size, header.segments[2].size, ".data") || !memory::Map(BASE_ADDRESS + header.segments[0].size + header.segments[1].size + header.segments[2].size, header.bssSize, ".bss")) {
!memory::Map(uc, 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"); syslog(LOG_ERR, "Failed mapping regions for executable");
return false; return false;