fxos/lib/os.cpp

140 lines
2.8 KiB
C++

#include <fxos/os.h>
#include <fxos/target.h>
#include <fxos/memory.h>
#include <cstring>
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 */