mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 11:51:47 +01:00
Code clean up by friendly neighborhood Cyuubi
This commit is contained in:
parent
985f2e67a2
commit
7dd04afdcf
@ -6,26 +6,18 @@
|
||||
#include "switch/device.h"
|
||||
#include "switch/common.h"
|
||||
|
||||
std::thread *game_thread;
|
||||
|
||||
void signal_handle(int sig_no) {
|
||||
throw lightSwitch::exception("A signal has been raised: " + std::to_string(sig_no));
|
||||
}
|
||||
std::thread *emu_thread;
|
||||
|
||||
void thread_main(std::string rom_path, std::string pref_path, std::string log_path) {
|
||||
auto log = std::make_shared<lightSwitch::Logger>(log_path);
|
||||
log->write(lightSwitch::Logger::INFO, "Launching ROM {0}", rom_path);
|
||||
// long long i = 0;
|
||||
// while(true){
|
||||
// log->write(lightSwitch::Logger::INFO, "#{0}", i);
|
||||
// sleep(1);
|
||||
// i++;
|
||||
// }
|
||||
|
||||
auto settings = std::make_shared<lightSwitch::Settings>(pref_path);
|
||||
try {
|
||||
lightSwitch::device device(log, settings);
|
||||
device.run(rom_path);
|
||||
log->write(lightSwitch::Logger::INFO, "Emulation has ended!");
|
||||
|
||||
log->write(lightSwitch::Logger::INFO, "Emulation has ended.");
|
||||
} catch (std::exception &e) {
|
||||
log->write(lightSwitch::Logger::ERROR, e.what());
|
||||
} catch (...) {
|
||||
@ -40,10 +32,11 @@ Java_emu_lightswitch_MainActivity_loadFile(JNIEnv *env, jobject instance, jstrin
|
||||
const char *rom_path = env->GetStringUTFChars(rom_path_, 0);
|
||||
const char *pref_path = env->GetStringUTFChars(pref_path_, 0);
|
||||
const char *log_path = env->GetStringUTFChars(log_path_, 0);
|
||||
// std::signal(SIGABRT, signal_handle);
|
||||
if (game_thread) pthread_kill(game_thread->native_handle(), SIGABRT);
|
||||
|
||||
if (emu_thread) pthread_kill(emu_thread->native_handle(), SIGABRT);
|
||||
|
||||
// Running on UI thread is not a good idea, any crashes and such will be propagated
|
||||
game_thread = new std::thread(thread_main, std::string(rom_path, strlen(rom_path)), std::string(pref_path, strlen(pref_path)), std::string(log_path, strlen(log_path)));
|
||||
emu_thread = new std::thread(thread_main, std::string(rom_path, strlen(rom_path)), std::string(pref_path, strlen(pref_path)), std::string(log_path, strlen(log_path)));
|
||||
env->ReleaseStringUTFChars(rom_path_, rom_path);
|
||||
env->ReleaseStringUTFChars(pref_path_, pref_path);
|
||||
env->ReleaseStringUTFChars(log_path_, log_path);
|
||||
|
@ -63,9 +63,8 @@ namespace lightSwitch {
|
||||
|
||||
struct device_state {
|
||||
std::shared_ptr<hw::Cpu> cpu;
|
||||
std::shared_ptr<hw::Memory> mem;
|
||||
std::shared_ptr<hw::Memory> memory;
|
||||
std::shared_ptr<Settings> settings;
|
||||
std::shared_ptr<Logger> logger;
|
||||
};
|
||||
//typedef std::shared_ptr<device_state_struct> device_state;
|
||||
}
|
@ -23,7 +23,6 @@ namespace lightSwitch {
|
||||
|
||||
namespace instr {
|
||||
// https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction
|
||||
// For some reason if value is set to uint16_t it isn't read correctly ?
|
||||
struct brk {
|
||||
brk(uint16_t val) {
|
||||
start = 0x0; // First 5 bits of an BRK instruction are 0
|
||||
@ -35,9 +34,9 @@ namespace lightSwitch {
|
||||
return (start == 0x0 && end == 0x6A1);
|
||||
}
|
||||
|
||||
uint8_t start:5;
|
||||
uint32_t value:16;
|
||||
uint16_t end:11;
|
||||
uint8_t start : 5;
|
||||
uint32_t value : 16;
|
||||
uint16_t end : 11;
|
||||
};
|
||||
|
||||
// https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call
|
||||
@ -46,9 +45,9 @@ namespace lightSwitch {
|
||||
return (start == 0x1 && end == 0x6A0);
|
||||
}
|
||||
|
||||
uint8_t start:5;
|
||||
uint32_t value:16;
|
||||
uint16_t end:11;
|
||||
uint8_t start : 5;
|
||||
uint32_t value : 16;
|
||||
uint16_t end : 11;
|
||||
};
|
||||
|
||||
// https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register
|
||||
@ -57,16 +56,12 @@ namespace lightSwitch {
|
||||
return (end == 0xD53);
|
||||
}
|
||||
|
||||
uint8_t Xt:5;
|
||||
uint32_t Sreg:15;
|
||||
uint16_t end:12;
|
||||
uint8_t dst_reg : 5;
|
||||
uint32_t src_reg : 15;
|
||||
uint16_t end : 12;
|
||||
};
|
||||
};
|
||||
|
||||
enum xreg {
|
||||
x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30
|
||||
};
|
||||
enum wreg {
|
||||
w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24, w25, w26, w27, w28, w29, w30
|
||||
};
|
||||
enum xreg { x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30 };
|
||||
enum wreg { w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24, w25, w26, w27, w28, w29, w30 };
|
||||
}
|
@ -10,27 +10,18 @@ namespace lightSwitch {
|
||||
std::shared_ptr<hw::Memory> memory;
|
||||
os::OS os;
|
||||
device_state state;
|
||||
const std::map<std::string, int> ext_case = {
|
||||
{"nro", 1},
|
||||
{"NRO", 1}
|
||||
};
|
||||
public:
|
||||
device(std::shared_ptr<Logger> &logger, std::shared_ptr<Settings> &settings) : cpu(new hw::Cpu()), memory(new hw::Memory()), state{cpu, memory, settings, logger}, os({cpu, memory, settings, logger}) {};
|
||||
|
||||
void run(std::string rom_file) {
|
||||
try {
|
||||
switch (ext_case.at(rom_file.substr(rom_file.find_last_of('.') + 1))) {
|
||||
case 1: {
|
||||
loader::NroLoader loader(rom_file, state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cpu->Execute(hw::Memory::text, memory, os.SvcHandler, &state);
|
||||
} catch (std::out_of_range &e) {
|
||||
throw exception("The ROM extension wasn't recognized.");
|
||||
}
|
||||
std::string rom_ext = rom_file.substr(rom_file.find_last_of('.') + 1);
|
||||
std::transform(rom_ext.begin(), rom_ext.end(), rom_ext.begin(),
|
||||
[](unsigned char c){ return std::tolower(c); });
|
||||
|
||||
if (rom_ext == "nro") loader::NroLoader loader(rom_file, state);
|
||||
else throw exception("Unsupported ROM extension.");
|
||||
|
||||
cpu->Execute(hw::Memory::text, memory, os.SvcHandler, &state);
|
||||
}
|
||||
};
|
||||
};
|
@ -8,30 +8,30 @@ namespace lightSwitch::hw {
|
||||
|
||||
long *Cpu::ReadMemory(uint64_t address) { // Return a single word (32-bit)
|
||||
status = ptrace(PTRACE_PEEKDATA, child, address, NULL);
|
||||
if (status == -1) throw std::runtime_error("Cannot read memory");
|
||||
if (status == -1) throw std::runtime_error("Cannot read memory!");
|
||||
return &status;
|
||||
}
|
||||
|
||||
void Cpu::WriteMemory(uint64_t address) { // Write a single word (32-bit)
|
||||
status = ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &iov);
|
||||
if (status == -1) throw std::runtime_error("Cannot write memory");
|
||||
if (status == -1) throw std::runtime_error("Cannot write memory!");
|
||||
}
|
||||
|
||||
void Cpu::ReadRegisters() { // Read all registers into 'regs'
|
||||
iov = {®s, sizeof(regs)};
|
||||
status = ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, &iov);
|
||||
if (status == -1) throw std::runtime_error("Cannot read registers");
|
||||
if (status == -1) throw std::runtime_error("Cannot read registers!");
|
||||
}
|
||||
|
||||
void Cpu::WriteRegisters() { // Write all registers from 'regs'
|
||||
iov = {®s, sizeof(regs)};
|
||||
status = ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, &iov);
|
||||
if (status == -1) throw std::runtime_error("Cannot write registers");
|
||||
if (status == -1) throw std::runtime_error("Cannot write registers!");
|
||||
}
|
||||
|
||||
void Cpu::ResumeProcess() { // Resumes a process stopped due to a signal
|
||||
status = ptrace(PTRACE_CONT, child, NULL, NULL);
|
||||
if (status == -1) throw std::runtime_error("Cannot resume process");
|
||||
if (status == -1) throw std::runtime_error("Cannot resume process!");
|
||||
}
|
||||
|
||||
void Cpu::WriteBreakpoint(uint64_t address_, uint64_t size) {
|
||||
@ -39,13 +39,20 @@ namespace lightSwitch::hw {
|
||||
for (uint64_t iter = 0; iter < size; iter++) {
|
||||
auto instr_svc = reinterpret_cast<instr::svc *>(address + iter);
|
||||
auto instr_mrs = reinterpret_cast<instr::mrs *>(address + iter);
|
||||
|
||||
if (instr_svc->verify()) {
|
||||
// syslog(LOG_WARNING, "Found SVC call: 0x%X, At location 0x%X", instr_svc->value, ((uint64_t)address)+iter);
|
||||
#ifdef NDEBUG
|
||||
syslog(LOG_WARNING, "Found SVC call: 0x%X, At location 0x%X", instr_svc->value, ((uint64_t)address)+iter);
|
||||
#endif
|
||||
|
||||
instr::brk brk(static_cast<uint16_t>(instr_svc->value));
|
||||
address[iter] = *reinterpret_cast<uint32_t *>(&brk);
|
||||
} else if (instr_mrs->verify() && instr_mrs->Sreg == constant::tpidrro_el0) {
|
||||
// syslog(LOG_WARNING, "Found MRS call: 0x%X, At location 0x%X", instr_mrs->Xt, ((uint64_t)address)+iter);
|
||||
instr::brk brk(static_cast<uint16_t>(constant::svc_last + 1 + instr_mrs->Xt));
|
||||
} else if (instr_mrs->verify() && instr_mrs->src_reg == constant::tpidrro_el0) {
|
||||
#ifdef NDEBUG
|
||||
syslog(LOG_WARNING, "Found MRS call: 0x%X, At location 0x%X", instr_mrs->dst_reg, ((uint64_t)address)+iter);
|
||||
#endif
|
||||
|
||||
instr::brk brk(static_cast<uint16_t>(constant::svc_last + 1 + instr_mrs->dst_reg));
|
||||
address[iter] = *reinterpret_cast<uint32_t *>(&brk);
|
||||
}
|
||||
}
|
||||
@ -53,22 +60,31 @@ namespace lightSwitch::hw {
|
||||
|
||||
void Cpu::Execute(Memory::Region region, std::shared_ptr<Memory> memory, std::function<void(uint16_t, void *)> svc_handler, void *device) {
|
||||
tls = memory->region_map.at(hw::Memory::tls).address;
|
||||
hw::Memory::RegionData rom = memory->region_map.at(hw::Memory::text);
|
||||
WriteBreakpoint(rom.address, rom.size);
|
||||
child = ExecuteChild(rom.address);
|
||||
|
||||
hw::Memory::RegionData exec = memory->region_map.at(hw::Memory::text);
|
||||
WriteBreakpoint(exec.address, exec.size);
|
||||
|
||||
child = ExecuteChild(exec.address);
|
||||
|
||||
int stat = 0;
|
||||
while (waitpid(child, &stat, 0)) {
|
||||
if (WIFSTOPPED(stat)) {
|
||||
ReadRegisters();
|
||||
//syslog(LOG_INFO, "PC is at 0x%X", regs.pc);
|
||||
|
||||
#ifdef NDEBUG
|
||||
syslog(LOG_INFO, "PC is at 0x%X", regs.pc);
|
||||
#endif
|
||||
|
||||
if (!regs.pc || regs.pc == 0xBADC0DE) break;
|
||||
|
||||
// We store the instruction value as the immediate value. 0x0 to 0x7F are SVC, 0x80 to 0x9E is MRS for TPIDRRO_EL0.
|
||||
auto instr = reinterpret_cast<instr::brk *>(ReadMemory(regs.pc));
|
||||
if (instr->verify()) {
|
||||
if (instr->value <= constant::svc_last) {
|
||||
svc_handler(static_cast<uint16_t>(instr->value), device);
|
||||
syslog(LOG_ERR, "SVC has been called 0x%X", instr->value);
|
||||
if (stop) break;
|
||||
|
||||
if (halt) break;
|
||||
} else if (instr->value > constant::svc_last && instr->value <= constant::svc_last + constant::num_regs) {
|
||||
// Catch MRS that reads the value of TPIDRRO_EL0 (TLS)
|
||||
// https://switchbrew.org/wiki/Thread_Local_Storage
|
||||
@ -76,27 +92,30 @@ namespace lightSwitch::hw {
|
||||
syslog(LOG_ERR, "MRS has been called 0x%X", instr->value - (constant::svc_last + 1));
|
||||
} else syslog(LOG_ERR, "Received unhandled BRK 0x%X", instr->value);
|
||||
}
|
||||
|
||||
regs.pc += 4; // Increment program counter by a single instruction (32 bits)
|
||||
WriteRegisters();
|
||||
} else if (WIFEXITED(stat))
|
||||
break;
|
||||
} else if (WIFEXITED(stat)) break;
|
||||
|
||||
ResumeProcess();
|
||||
}
|
||||
|
||||
kill(child, SIGABRT);
|
||||
child = 0;
|
||||
stop = false;
|
||||
halt = false; // TODO: Global variable
|
||||
}
|
||||
|
||||
pid_t Cpu::ExecuteChild(uint64_t address) {
|
||||
pid_t pid = fork();
|
||||
if (!pid) {
|
||||
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
|
||||
asm volatile("BR %0"::"r"(address));
|
||||
asm volatile("br %0" :: "r"(address));
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
void Cpu::StopExecution() { stop = true; }
|
||||
void Cpu::StopExecution() { halt = true; }
|
||||
|
||||
uint64_t Cpu::GetRegister(xreg reg_id) {
|
||||
return regs.regs[reg_id];
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace lightSwitch::hw {
|
||||
class Cpu {
|
||||
private:
|
||||
bool stop = false;
|
||||
bool halt = false;
|
||||
long status = 0;
|
||||
pid_t child;
|
||||
iovec iov;
|
||||
|
@ -13,19 +13,23 @@ namespace lightSwitch::hw {
|
||||
void *ptr = mmap((void *) address, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON | MAP_FIXED, 0, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
throw exception("An occurred while mapping region: " + std::string(strerror(errno)));
|
||||
|
||||
region_map.insert(std::pair<Region, RegionData>(region, {address, size}));
|
||||
}
|
||||
|
||||
void Memory::Remap(Region region, size_t size) {
|
||||
RegionData region_data = region_map.at(region);
|
||||
|
||||
void *ptr = mremap(reinterpret_cast<void *>(region_data.address), region_data.size, size, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
throw exception("An occurred while remapping region: " + std::string(strerror(errno)));
|
||||
|
||||
region_map[region].size = size;
|
||||
}
|
||||
|
||||
void Memory::Unmap(Region region) {
|
||||
RegionData region_data = region_map.at(region);
|
||||
|
||||
int err = munmap(reinterpret_cast<void *>(region_data.address), region_data.size);
|
||||
if (err == -1)
|
||||
throw exception("An occurred while unmapping region: " + std::string(strerror(errno)));
|
||||
|
@ -6,7 +6,7 @@ namespace lightSwitch::loader {
|
||||
NroHeader header{};
|
||||
ReadOffset((uint32_t *) &header, 0x0, sizeof(NroHeader));
|
||||
if (header.magic != constant::nro_magic)
|
||||
throw exception(fmt::format("Invalid NRO magic 0x{0:x}", header.magic));
|
||||
throw exception(fmt::format("Invalid NRO magic! 0x{0:X}", header.magic));
|
||||
|
||||
auto text = new uint32_t[header.text.size]();
|
||||
auto ro = new uint32_t[header.ro.size]();
|
||||
@ -16,18 +16,25 @@ namespace lightSwitch::loader {
|
||||
ReadOffset(ro, header.ro.offset, header.ro.size);
|
||||
ReadOffset(data, header.data.offset, header.data.size);
|
||||
|
||||
state.mem->Map(constant::base_addr, header.text.size, hw::Memory::text);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .text to 0x{0:x}, size is 0x{1:x}.", constant::base_addr, header.text.size);
|
||||
state.mem->Map(constant::base_addr + header.text.size, header.ro.size, hw::Memory::rodata);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .ro to 0x{0:x}, size is 0x{1:x}.", constant::base_addr + header.text.size, header.ro.size);
|
||||
state.mem->Map(constant::base_addr + header.text.size + header.ro.size, header.data.size, hw::Memory::data);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .data to 0x{0:x}, size is 0x{1:x}.", constant::base_addr + header.text.size + header.ro.size, header.data.size);
|
||||
state.mem->Map(constant::base_addr + header.text.size + header.ro.size + header.data.size, header.bssSize, hw::Memory::bss);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .bss to 0x{0:x}, size is 0x{1:x}.", constant::base_addr + header.text.size + header.ro.size + header.data.size, header.bssSize);
|
||||
state.memory->Map(constant::base_addr, header.text.size, hw::Memory::text);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .text @ 0x{0:X}, Size = 0x{1:X}",
|
||||
constant::base_addr, header.text.size);
|
||||
|
||||
state.mem->Write(text, constant::base_addr, header.text.size);
|
||||
state.mem->Write(ro, constant::base_addr + header.text.size, header.ro.size);
|
||||
state.mem->Write(data, constant::base_addr + header.text.size + header.ro.size, header.data.size);
|
||||
state.memory->Map(constant::base_addr + header.text.size, header.ro.size, hw::Memory::rodata);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .ro @ 0x{0:X}, Size = 0x{1:X}",
|
||||
constant::base_addr + header.text.size, header.ro.size);
|
||||
|
||||
state.memory->Map(constant::base_addr + header.text.size + header.ro.size, header.data.size, hw::Memory::data);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .data @ 0x{0:X}, Size = 0x{1:X}",
|
||||
constant::base_addr + header.text.size + header.ro.size, header.data.size);
|
||||
|
||||
state.memory->Map(constant::base_addr + header.text.size + header.ro.size + header.data.size, header.bssSize, hw::Memory::bss);
|
||||
state.logger->write(Logger::DEBUG, "Successfully mapped region .bss @ 0x{0:X}, Size = 0x{1:X}",
|
||||
constant::base_addr + header.text.size + header.ro.size + header.data.size, header.bssSize);
|
||||
|
||||
state.memory->Write(text, constant::base_addr, header.text.size);
|
||||
state.memory->Write(ro, constant::base_addr + header.text.size, header.ro.size);
|
||||
state.memory->Write(data, constant::base_addr + header.text.size + header.ro.size, header.data.size);
|
||||
|
||||
delete[] text;
|
||||
delete[] ro;
|
||||
|
@ -13,12 +13,12 @@ namespace lightSwitch::os::ipc {
|
||||
data_pos = ((data_pos - 1) & ~(15U)) + 16; // ceil data_pos with multiples 16
|
||||
data_ptr = &tls_ptr[data_pos + sizeof(command_struct)];
|
||||
|
||||
state.logger->write(Logger::DEBUG, "Type: 0x{:x}", (uint8_t) req_info->type);
|
||||
state.logger->write(Logger::DEBUG, "Type: 0x{:X}", (uint8_t) req_info->type);
|
||||
state.logger->write(Logger::DEBUG, "X descriptors: {}", (uint8_t) req_info->x_no);
|
||||
state.logger->write(Logger::DEBUG, "A descriptors: {}", (uint8_t) req_info->a_no);
|
||||
state.logger->write(Logger::DEBUG, "B descriptors: {}", (uint8_t) req_info->b_no);
|
||||
state.logger->write(Logger::DEBUG, "W descriptors: {}", (uint8_t) req_info->w_no);
|
||||
state.logger->write(Logger::DEBUG, "Raw data offset: 0x{:x}", data_pos);
|
||||
state.logger->write(Logger::DEBUG, "Raw data offset: 0x{:X}", data_pos);
|
||||
state.logger->write(Logger::DEBUG, "Raw data size: {}", (uint16_t) req_info->data_sz);
|
||||
state.logger->write(Logger::DEBUG, "Payload Command ID: {}", *((uint32_t *) &tls_ptr[data_pos + 8]));
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace lightSwitch::os {
|
||||
if (svc::svcTable[svc])
|
||||
(*svc::svcTable[svc])(state);
|
||||
else {
|
||||
state.logger->write(Logger::ERROR, "Unimplemented SVC 0x{0:x}", svc);
|
||||
state.logger->write(Logger::ERROR, "Unimplemented SVC 0x{0:X}", svc);
|
||||
state.cpu->StopExecution();
|
||||
}
|
||||
}
|
||||
|
@ -7,28 +7,35 @@
|
||||
namespace lightSwitch::os::svc {
|
||||
void ConnectToNamedPort(device_state &state) {
|
||||
char port[constant::port_size]{0};
|
||||
state.mem->Read(port, state.cpu->GetRegister(xreg::x1), constant::port_size);
|
||||
state.memory->Read(port, state.cpu->GetRegister(xreg::x1), constant::port_size);
|
||||
|
||||
if (std::strcmp(port, "sm:") == 0)
|
||||
state.cpu->SetRegister(wreg::w1, constant::sm_handle);
|
||||
else {
|
||||
state.logger->write(Logger::ERROR, "svcConnectToNamedPort tried connecting to invalid port \"{0}\"", port);
|
||||
state.cpu->StopExecution();
|
||||
}
|
||||
|
||||
state.cpu->SetRegister(wreg::w0, 0);
|
||||
}
|
||||
|
||||
void SendSyncRequest(device_state &state) {
|
||||
state.logger->write(Logger::DEBUG, "svcSendSyncRequest called for handle 0x{0:x}.", state.cpu->GetRegister(xreg::x0));
|
||||
state.logger->write(Logger::DEBUG, "svcSendSyncRequest called for handle 0x{0:X}.", state.cpu->GetRegister(xreg::x0));
|
||||
|
||||
uint8_t tls[constant::tls_ipc_size];
|
||||
state.mem->Read(&tls, constant::tls_addr, constant::tls_ipc_size);
|
||||
state.memory->Read(&tls, constant::tls_addr, constant::tls_ipc_size);
|
||||
|
||||
ipc::IpcRequest request(tls, state);
|
||||
|
||||
state.cpu->SetRegister(wreg::w0, 0);
|
||||
}
|
||||
|
||||
void OutputDebugString(device_state &state) {
|
||||
std::string debug(state.cpu->GetRegister(xreg::x1), '\0');
|
||||
state.mem->Read((void *) debug.data(), state.cpu->GetRegister(xreg::x0), state.cpu->GetRegister(xreg::x1));
|
||||
state.logger->write(Logger::INFO, "ROM Output: {0}", debug.c_str());
|
||||
state.memory->Read((void *) debug.data(), state.cpu->GetRegister(xreg::x0), state.cpu->GetRegister(xreg::x1));
|
||||
|
||||
state.logger->write(Logger::INFO, "svcOutputDebugString: {0}", debug.c_str());
|
||||
|
||||
state.cpu->SetRegister(wreg::w0, 0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user