flycast/core/reios/reios.cpp

376 lines
8.4 KiB
C++
Raw Normal View History

/*
Extremely primitive bios replacement
2014-12-30 00:57:13 +00:00
Many thanks to Lars Olsson (jlo@ludd.luth.se) for bios decompile work
http://www.ludd.luth.se/~jlo/dc/bootROM.c
http://www.ludd.luth.se/~jlo/dc/bootROM.h
http://www.ludd.luth.se/~jlo/dc/security_stuff.c
*/
#include "reios.h"
#include "gdrom_hle.h"
#include "hw/sh4/sh4_mem.h"
#include <map>
2014-12-30 00:57:13 +00:00
#define dc_bios_syscall_system 0x8C0000B0
#define dc_bios_syscall_font 0x8C0000B4
#define dc_bios_syscall_flashrom 0x8C0000B8
#define dc_bios_syscall_gd 0x8C0000BC
#define dc_bios_syscall_misc 0x8c0000E0
//At least one game (ooga) uses this directly
#define dc_bios_entrypoint_gd_do_bioscall 0x8c0010F0
#define SYSINFO_ID_ADDR 0x8C001010
u8* biosrom;
u8* flashrom;
bool reios_locate_bootfile(const char* bootfile="1ST_READ.BIN") {
u8* temp = new u8[2048 * 1024];
libGDR_ReadSector(temp, 45150 + 16, 1024, 2048);
for (int i = 0; i < 2048 * 1023; i++) {
if (memcmp(temp+i, bootfile, strlen(bootfile)) == 0){
printf("Found %s at %06X\n", bootfile, i);
printf("filename len: %d\n", temp[i - 1]);
printf("file LBA: %d, %d\n", (u32&)temp[i - 33 + 2], (u32&)temp[i - 33 + 2 + 4]);
printf("file LEN: %d, %d\n", (u32&)temp[i - 33 + 10], (u32&)temp[i - 33 + 10 + 4]);
u32 lba = (u32&)temp[i - 33 + 2]; //should use the big endian one, but i'm lazy
u32 len = (u32&)temp[i - 33 + 10]; //should use the big endian one, but i'm lazy
libGDR_ReadSector(GetMemPtr(0x8c010000, 0), lba + 150, (len + 2047) / 2048, 2048);
delete[] temp;
return true;
}
}
delete[] temp;
return false;
}
char reios_bootfile[32];
const char* reios_locate_ip() {
libGDR_ReadSector(GetMemPtr(0x8c008000, 0), 45150, 16, 2048);
memset(reios_bootfile, 0, sizeof(reios_bootfile));
memcpy(reios_bootfile, GetMemPtr(0x8c008060, 0), 16);
for (int i = 15; i >= 0; i--) {
if (reios_bootfile[i] != ' ')
break;
reios_bootfile[i] = 0;
}
sh4rcb.cntx.pc = 0x8c008300;
return reios_bootfile;
}
void reios_sys_system() {
//printf("reios_sys_system\n");
u32 cmd = Sh4cntx.r[7];
switch (cmd) {
case 0: //SYSINFO_INIT
Sh4cntx.r[0] = 0;
break;
case 2: //SYSINFO_ICON
{
printf("SYSINFO_ICON\n");
/*
r4 = icon number (0-9, but only 5-9 seems to really be icons)
r5 = destination buffer (704 bytes in size)
*/
Sh4cntx.r[0] = 704;
}
break;
case 3: //SYSINFO_ID
{
WriteMem32(SYSINFO_ID_ADDR + 0, 0xe1e2e3e4);
WriteMem32(SYSINFO_ID_ADDR + 4, 0xe5e6e7e8);
Sh4cntx.r[0] = SYSINFO_ID_ADDR;
}
break;
default:
printf("unhandled: reios_sys_system\n");
break;
}
}
void reios_sys_font() {
printf("reios_sys_font\n");
}
void reios_sys_flashrom() {
//printf("reios_sys_flashrom\n");
u32 cmd = Sh4cntx.r[7];
u32 flashrom_info[][2] = {
{ 0 * 1024, 8 * 1024 },
{ 8 * 1024, 8 * 1024 },
{ 16 * 1024, 16 * 1024 },
{ 32 * 1024, 32 * 1024 },
{ 64 * 1024, 64 * 1024 },
};
switch (cmd) {
case 0: // FLASHROM_INFO
{
/*
r4 = partition number(0 - 4)
r5 = pointer to two 32 bit integers to receive the result.
The first will be the offset of the partition start, in bytes from the start of the flashrom.
The second will be the size of the partition, in bytes.
#define FLASHROM_PT_SYSTEM 0 /< \brief Factory settings (read-only, 8K)
#define FLASHROM_PT_RESERVED 1 /< \brief reserved (all 0s, 8K)
#define FLASHROM_PT_BLOCK_1 2 /< \brief Block allocated (16K)
#define FLASHROM_PT_SETTINGS 3 /< \brief Game settings (block allocated, 32K)
#define FLASHROM_PT_BLOCK_2 4 /< \brief Block allocated (64K)
*/
u32 part = Sh4cntx.r[4];
u32 dest = Sh4cntx.r[5];
u32* pDst = (u32*)GetMemPtr(dest, 8);
if (part <= 4) {
pDst[0] = flashrom_info[part][0];
pDst[1] = flashrom_info[part][1];
Sh4cntx.r[0] = 0;
}
else {
Sh4cntx.r[0] = -1;
}
}
break;
case 1: //FLASHROM_READ
{
/*
r4 = read start position, in bytes from the start of the flashrom
r5 = pointer to destination buffer
r6 = number of bytes to read
*/
u32 offs = Sh4cntx.r[4];
u32 dest = Sh4cntx.r[5];
u32 size = Sh4cntx.r[6];
memcpy(GetMemPtr(dest, size), flashrom + offs, size);
Sh4cntx.r[0] = size;
}
break;
case 2: //FLASHROM_WRITE
{
/*
r4 = write start position, in bytes from the start of the flashrom
r5 = pointer to source buffer
r6 = number of bytes to write
*/
u32 offs = Sh4cntx.r[4];
u32 src = Sh4cntx.r[5];
u32 size = Sh4cntx.r[6];
u8* pSrc = GetMemPtr(src, size);
for (int i = 0; i < size; i++) {
flashrom[offs + i] &= pSrc[i];
}
}
break;
case 3: //FLASHROM_DELETE
{
u32 offs = Sh4cntx.r[4];
u32 dest = Sh4cntx.r[5];
u32 part = 5;
for (int i = 0; i <= 4; i++) {
if (offs >= flashrom_info[i][0] && offs < (flashrom_info[i][0] + flashrom_info[i][1])) {
part = i;
break;
}
}
if (part <= 4) {
memset(flashrom + flashrom_info[part][0], 0xFF, flashrom_info[part][1]);
Sh4cntx.r[0] = 0;
}
else {
Sh4cntx.r[0] = -1;
}
}
break;
default:
printf("reios_sys_flashrom: not handled, %d\n", cmd);
}
}
void reios_sys_gd() {
gdrom_hle_op();
}
2014-12-30 00:57:13 +00:00
/*
- gdGdcReqCmd, 0
- gdGdcGetCmdStat, 1
- gdGdcExecServer, 2
- gdGdcInitSystem, 3
- gdGdcGetDrvStat, 4
*/
void gd_do_bioscall()
{
//looks like the "real" entrypoint for this on a dreamcast
gdrom_hle_op();
return;
/*
int func1, func2, arg1, arg2;
*/
switch (Sh4cntx.r[7]) {
case 0: //gdGdcReqCmd, wth is r6 ?
GD_HLE_Command(Sh4cntx.r[4], Sh4cntx.r[5]);
Sh4cntx.r[0] = 0xf344312e;
break;
case 1: //gdGdcGetCmdStat, r4 -> id as returned by gdGdcReqCmd, r5 -> buffer to get status in ram, r6 ?
Sh4cntx.r[0] = 0; //All good, no status info
break;
case 2: //gdGdcExecServer
//nop? returns something, though.
//Bios seems to be based on a cooperative threading model
//this is the "context" switch entry point
break;
case 3: //gdGdcInitSystem
//nop? returns something, though.
break;
case 4: //gdGdcGetDrvStat
/*
Looks to same as GDROM_CHECK_DRIVE
*/
WriteMem32(Sh4cntx.r[4] + 0, 0x02); // STANDBY
WriteMem32(Sh4cntx.r[4] + 4, 0x80); // CDROM | 0x80 for GDROM
Sh4cntx.r[0] = 0; // RET SUCCESS
break;
default:
printf("gd_do_bioscall: (%d) %d, %d, %d\n", Sh4cntx.r[4], Sh4cntx.r[5], Sh4cntx.r[6], Sh4cntx.r[7]);
break;
}
//gdGdcInitSystem
}
void reios_sys_misc() {
printf("reios_sys_misc - r7: 0x%08X, r4 0x%08X, r5 0x%08X, r6 0x%08X\n", Sh4cntx.r[7], Sh4cntx.r[4], Sh4cntx.r[5], Sh4cntx.r[6]);
Sh4cntx.r[0] = 0;
}
typedef void hook_fp();
u32 hook_addr(hook_fp* fn);
void setup_syscall(u32 hook_addr, u32 syscall_addr) {
WriteMem32(syscall_addr, hook_addr);
WriteMem32(hook_addr, REIOS_OPCODE);
}
void reios_boot() {
//setup syscalls
//find boot file
//boot it
memset(GetMemPtr(0x8C000000, 0), 0xFF, 64 * 1024);
setup_syscall(hook_addr(&reios_sys_system), dc_bios_syscall_system);
setup_syscall(hook_addr(&reios_sys_font), dc_bios_syscall_font);
setup_syscall(hook_addr(&reios_sys_flashrom), dc_bios_syscall_flashrom);
setup_syscall(hook_addr(&reios_sys_gd), dc_bios_syscall_gd);
setup_syscall(hook_addr(&reios_sys_misc), dc_bios_syscall_misc);
2014-12-30 00:57:13 +00:00
WriteMem32(dc_bios_entrypoint_gd_do_bioscall, REIOS_OPCODE);
//Infinitive loop for arm !
WriteMem32(0x80800000, 0xEAFFFFFE);
const char* bootfile = reios_locate_ip();
if (!reios_locate_bootfile(bootfile))
msgboxf("Failed to locate bootfile", MBX_ICONERROR);
}
map<u32, hook_fp*> hooks;
map<hook_fp*, u32> hooks_rev;
void register_hook(u32 pc, hook_fp* fn) {
hooks[pc] = fn;
hooks_rev[fn] = pc;
}
void DYNACALL reios_trap(u32 op) {
verify(op == REIOS_OPCODE);
u32 pc = sh4rcb.cntx.pc - 2;
sh4rcb.cntx.pc = sh4rcb.cntx.pr;
//printf("reios: dispatch %08X\n", pc);
hooks[pc]();
}
u32 hook_addr(hook_fp* fn) {
auto pos = hooks_rev.find(fn);
return pos != hooks_rev.end() ? pos->second : 0;
}
bool reios_init(u8* rom, u8* flash) {
biosrom = rom;
flashrom = flash;
u16* rom16 = (u16*)rom;
rom16[0] = REIOS_OPCODE;
register_hook(0xA0000000, reios_boot);
register_hook(0x8C001000, reios_sys_system);
register_hook(0x8C001002, reios_sys_font);
register_hook(0x8C001004, reios_sys_flashrom);
register_hook(0x8C001006, reios_sys_gd);
register_hook(0x8C001008, reios_sys_misc);
2014-12-30 00:57:13 +00:00
register_hook(dc_bios_entrypoint_gd_do_bioscall, &gd_do_bioscall);
return true;
}
void reios_reset() {
}
void reios_term() {
}