mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-29 13:03:37 +01:00
25db504c22
Almost-complete implementation of fxos, the disassembler in particular is now able to detect syscalls and register addresses on the fly, plus support for SH4-only instructions.
91 lines
2.3 KiB
C
91 lines
2.3 KiB
C
#include <endian.h>
|
|
#include <string.h>
|
|
|
|
#include <fxos.h>
|
|
#include <errors.h>
|
|
#include <util.h>
|
|
|
|
/* os_load(): Load an OS file and find out basic properties */
|
|
int os_load(char const *path, struct os *os)
|
|
{
|
|
if(!path || !os) return 1;
|
|
|
|
os->data = map(path, &os->fd, &os->len);
|
|
if(!os->data) return 1;
|
|
if(os->len < 0x10080)
|
|
{
|
|
err("too small for the OS format I know (min. 0x10080 bytes)",
|
|
os->len);
|
|
return 1;
|
|
}
|
|
|
|
/* Get the OS version */
|
|
|
|
memcpy(os->version, os->data + 0x10020, 14);
|
|
os->version[14] = 0;
|
|
|
|
/* Guess the MPU type (or assume SH7305). Until version 03.00, the last
|
|
digit of the version number indicated the presence of an SH7305 */
|
|
|
|
os->mpu = MPU_SH7305;
|
|
if(!strncmp(os->version, "02.", 3) && os->version[13] == '0')
|
|
os->mpu = MPU_SH7705;
|
|
|
|
/* Find the syscall table address */
|
|
|
|
memcpy(&os->syscall_table, os->data + 0x1007c, 4);
|
|
os->syscall_table = be32toh(os->syscall_table);
|
|
|
|
/* Count the number of valid syscall entries */
|
|
|
|
os->syscalls = 0;
|
|
while(memory_region(os_syscall(os, os->syscalls))) os->syscalls++;
|
|
|
|
/* Find the footer address (last occurrence of "CASIOABSLangdata") */
|
|
|
|
char const *signature = "CASIOABSLangdata";
|
|
void *occ = NULL, *next = memmem(os->data, os->len, signature, 16);
|
|
void *end = os->data + os->len;
|
|
|
|
while(next)
|
|
{
|
|
occ = next;
|
|
next = memmem(next + 1, end - (next + 1), signature, 16);
|
|
}
|
|
|
|
os->footer = (occ) ? (occ - os->data) : (uint32_t)-1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* os_syscall(): Get the address of a syscall entry */
|
|
uint32_t os_syscall(struct os const *os, int syscall)
|
|
{
|
|
uint32_t table_entry = (os->syscall_table & 0x1fffffff) + 4 * syscall;
|
|
if(table_entry + 4 > os->len) return (uint32_t)-1;
|
|
|
|
uint32_t address;
|
|
memcpy(&address, os->data + table_entry, 4);
|
|
address = be32toh(address);
|
|
|
|
return address;
|
|
}
|
|
|
|
/* os_syscall_find(): Find a syscall which points to an address */
|
|
int os_syscall_find(struct os const *os, uint32_t entry)
|
|
{
|
|
/* Try to make this slightly quicker */
|
|
uint32_t table_entry = (os->syscall_table & 0x1fffffff);
|
|
entry = htobe32(entry);
|
|
|
|
uint32_t *entries = os->data + table_entry;
|
|
for(int i = 0; i < os->syscalls; i++) if(entries[i] == entry) return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* os_free(): Free an OS file opened with os_load() */
|
|
void os_free(struct os const *os)
|
|
{
|
|
if(os && os->data) unmap(os->data, os->fd, os->len);
|
|
}
|