mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-23 01:19:16 +01:00
Add CPU class
This commit is contained in:
parent
39b591bcfd
commit
75c608fd25
@ -1,5 +1,39 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
|
// TODO: Handle Unicorn errors
|
||||||
namespace core {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,10 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <syslog.h>
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
namespace core {
|
namespace core {
|
||||||
class Cpu {
|
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;
|
uc_engine *uc;
|
||||||
|
private:
|
||||||
|
void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -3,19 +3,17 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
namespace core::mem {
|
namespace core::memory {
|
||||||
std::vector<MemoryRegion> memRegions;
|
std::vector<MemoryRegion> memoryRegions;
|
||||||
|
|
||||||
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* 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)
|
if (!ptr) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Skipping this until the CPU implementation is working
|
// 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);
|
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));
|
syslog(LOG_ERR, "Memory map failed: %s", uc_strerror(err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -23,19 +21,20 @@ namespace core::mem {
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
memRegions.push_back({label, address, size, ptr});
|
memoryRegions.push_back({label, address, size, ptr});
|
||||||
|
|
||||||
return true;
|
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); }
|
||||||
|
|
||||||
void WriteU8 (uint8_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 1); }
|
void WriteU8 (uint8_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 1); }
|
||||||
void WriteU16(uint16_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 2); }
|
void WriteU16(uint16_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 2); }
|
||||||
void WriteU32(uint32_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 4); }
|
void WriteU32(uint32_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 4); }
|
||||||
void WriteU64(uint64_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 8); }
|
void WriteU64(uint64_t value, uint64_t offset) { Write(reinterpret_cast<void*>(&value), offset, 8); }
|
||||||
|
|
||||||
void Read(void* destination, uint64_t offset, size_t size) { std::memcpy(destination, (void*)(offset), size); }
|
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<void*>(&value), offset, 1); return value; }
|
uint8_t ReadU8 (uint64_t offset) { uint8_t value; Read(reinterpret_cast<void*>(&value), offset, 1); return value; }
|
||||||
uint16_t ReadU16(uint64_t offset) { uint16_t value; Read(reinterpret_cast<void*>(&value), offset, 2); return value; }
|
uint16_t ReadU16(uint64_t offset) { uint16_t value; Read(reinterpret_cast<void*>(&value), offset, 2); return value; }
|
||||||
uint32_t ReadU32(uint64_t offset) { uint32_t value; Read(reinterpret_cast<void*>(&value), offset, 4); return value; }
|
uint32_t ReadU32(uint64_t offset) { uint32_t value; Read(reinterpret_cast<void*>(&value), offset, 4); return value; }
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
#define MEM_BASE 0x80000000
|
#define BASE_ADDRESS 0x80000000
|
||||||
|
|
||||||
namespace core::mem {
|
namespace core::memory {
|
||||||
struct MemoryRegion {
|
struct MemoryRegion {
|
||||||
std::string label;
|
std::string label;
|
||||||
uint64_t address;
|
uint64_t address;
|
||||||
@ -12,15 +12,17 @@ namespace core::mem {
|
|||||||
void* ptr;
|
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 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 WriteU16(uint16_t value, uint64_t offset);
|
||||||
void WriteU32(uint32_t value, uint64_t offset);
|
void WriteU32(uint32_t value, uint64_t offset);
|
||||||
void WriteU64(uint64_t value, uint64_t offset);
|
void WriteU64(uint64_t value, uint64_t offset);
|
||||||
|
|
||||||
void Read(void* destination, uint64_t offset, size_t size);
|
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);
|
uint16_t ReadU16(uint64_t offset);
|
||||||
uint32_t ReadU32(uint64_t offset);
|
uint32_t ReadU32(uint64_t offset);
|
||||||
|
0
app/src/main/cpp/core/hos/kernel/svc.cpp
Normal file
0
app/src/main/cpp/core/hos/kernel/svc.cpp
Normal file
@ -19,35 +19,34 @@ namespace core::loader {
|
|||||||
bool LoadNro(std::string file) {
|
bool LoadNro(std::string file) {
|
||||||
syslog(LOG_INFO, "Loading NRO file %s\n", file.c_str());
|
syslog(LOG_INFO, "Loading NRO file %s\n", file.c_str());
|
||||||
|
|
||||||
NroHeader h;
|
NroHeader header;
|
||||||
ReadDataFromFile(file, reinterpret_cast<char *>(&h), 0x0, sizeof(NroHeader));
|
ReadDataFromFile(file, reinterpret_cast<char *>(&header), 0x0, sizeof(NroHeader));
|
||||||
if (h.magic != 0x304F524E) {
|
if (header.magic != 0x304F524E) {
|
||||||
syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", h.magic);
|
syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", header.magic);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint32_t> text, ro, data;
|
std::vector<uint32_t> text, ro, data;
|
||||||
text.resize(h.segments[0].size);
|
text.resize(header.segments[0].size);
|
||||||
ro.resize(h.segments[1].size);
|
ro.resize (header.segments[1].size);
|
||||||
data.resize(h.segments[2].size);
|
data.resize(header.segments[2].size);
|
||||||
|
|
||||||
ReadDataFromFile(file, reinterpret_cast<char *>(text.data()), h.segments[0].fileOffset, h.segments[0].size);
|
ReadDataFromFile(file, reinterpret_cast<char *>(text.data()), header.segments[0].fileOffset, header.segments[0].size);
|
||||||
ReadDataFromFile(file, reinterpret_cast<char *>(ro.data()), h.segments[1].fileOffset, h.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()), h.segments[2].fileOffset, h.segments[2].size);
|
ReadDataFromFile(file, reinterpret_cast<char *>(data.data()), header.segments[2].fileOffset, header.segments[2].size);
|
||||||
|
|
||||||
if( !mem::Map(nullptr, MEM_BASE, h.segments[0].size, ".text") ||
|
if( !memory::Map(nullptr, BASE_ADDRESS, header.segments[0].size, ".text") ||
|
||||||
!mem::Map(nullptr, MEM_BASE + h.segments[0].size, h.segments[1].size, ".ro") ||
|
!memory::Map(nullptr, BASE_ADDRESS + header.segments[0].size, header.segments[1].size, ".ro") ||
|
||||||
!mem::Map(nullptr, MEM_BASE + h.segments[0].size + h.segments[1].size, h.segments[2].size, ".data") ||
|
!memory::Map(nullptr, BASE_ADDRESS + header.segments[0].size + header.segments[1].size, header.segments[2].size, ".data") ||
|
||||||
!mem::Map(nullptr, MEM_BASE + h.segments[0].size + h.segments[1].size + h.segments[2].size, h.bssSize, ".bss")) {
|
!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");
|
syslog(LOG_ERR, "Failed mapping regions for executable");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mem::Write(text.data(), MEM_BASE, text.size());
|
memory::Write(text.data(), BASE_ADDRESS, text.size());
|
||||||
mem::Write(ro.data(), MEM_BASE + h.segments[0].size, ro.size());
|
memory::Write(ro.data(), BASE_ADDRESS + header.segments[0].size, ro.size());
|
||||||
mem::Write(data.data(), MEM_BASE + h.segments[0].size + h.segments[1].size, data.size());
|
memory::Write(data.data(), BASE_ADDRESS + header.segments[0].size + header.segments[1].size, data.size());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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.
|
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)
|
by uc_mem_regions (returned in *regions)
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
|
Loading…
Reference in New Issue
Block a user