#include #include #include #include namespace FxOS { OS::OS(Target &t): m_target {t} { if(!t.covers(0x80000000)) throw std::runtime_error("OS requires a target with ROM"); /* OS files are all at least 1 MB large */ if(!t.covers(0x80000000, 1000000)) throw std::runtime_error("OS requires target with >1MB ROM"); /* Detect OS type by heuristic */ if(t.read_str(0x80010000, 8).value == "CASIOWIN") this->type = FX; else if(t.read_str(0x80020000, 8).value == "CASIOWIN") this->type = CG; else throw std::runtime_error("Cannot determine OS type (FX/CG)"); parse_header(); parse_syscall_table(); parse_footer(); } void OS::parse_header() { Target &t = m_target; if(this->type == FX) { /* Bootcode timestamp at the very end of the bootcode */ this->bootcode_timestamp = t.read_str(0x8000ffb0, 14); this->bootcode_checksum = t.read_u32(0x8000fffc); this->version = t.read_str(0x80010020, 10); /* Serial numer at 0xffd0... sometimes? */ this->serial_number = t.read_str(0x8000ffd0, 8); } else if(this->type == CG) { this->bootcode_timestamp = t.read_str(0x8001ffb0, 14); this->bootcode_checksum = t.read_u32(0x8001fffc); this->version = t.read_str(0x80020020, 10); this->serial_number = t.read_str(0x8001ffd0, 8); } } //--- // Syscall resolution //--- int OS::syscall_count() const noexcept { return m_syscall_table.size(); } uint32_t OS::syscall(int id) const { return m_syscall_table[id]; } int OS::find_syscall(uint32_t entry) const noexcept { try { return m_syscall_addresses.at(entry); } catch(std::out_of_range &e) { return -1; } } uint32_t OS::syscall_table_address() const noexcept { uint32_t address = (this->type == FX) ? 0x8001007c : 0x8002007c; return m_target.read_u32(address); } void OS::parse_syscall_table() { Target &t = m_target; /* Traverse the syscall table */ uint32_t syscall_table = syscall_table_address(); int id = 0; while(1) { uint32_t entry = t.read_u32(syscall_table + 4 * id); MemoryRegion const *r = MemoryRegion::region_for(entry); if(!r) break; m_syscall_table.push_back(entry); m_syscall_addresses[entry] = id; id++; } } //--- // Footer search //--- void OS::parse_footer() { Target &t = m_target; /* Find the footer address (occurrence of "CASIOABSLangdata") */ uint32_t start = MemoryRegion::ROM.start; uint32_t end = MemoryRegion::ROM.end; this->footer = t.search(start, end, "CASIOABSLangdata", 16); if(this->footer == end) { this->footer = -1; this->timestamp = std::string(""); this->langdata = 0; return; } uint32_t addr = this->footer + 8; this->langdata = 0; while(!memcmp(t.translate(addr, 8), "Langdata", 8)) { this->langdata++; addr += 0x30; } this->timestamp = t.read_str(addr, 14); this->checksum = t.read_u32(addr + 0x18); } } /* namespace FxOS */