filename | src/bios.c |
changeset | 1107:7b279d10f46f |
prev | 1103:de9ad2c0cf56 |
next | 1298:d0eb2307b847 |
author | nkeynes |
date | Fri Aug 24 08:53:50 2012 +1000 (11 years ago) |
permissions | -rw-r--r-- |
last change | Move the generated prologue/epilogue code out into a common entry stub (reduces space requirements) and pre-save all saved registers. Change FASTCALL to use 3 regs instead of 2 since we can now keep everything in regs. |
file | annotate | diff | log | raw |
nkeynes@87 | 1 | /** |
nkeynes@561 | 2 | * $Id$ |
nkeynes@87 | 3 | * |
nkeynes@87 | 4 | * "Fake" BIOS functions, for operation without the actual BIOS. |
nkeynes@87 | 5 | * |
nkeynes@1100 | 6 | * Copyright (c) 2005-2010 Nathan Keynes. |
nkeynes@87 | 7 | * |
nkeynes@87 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@87 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@87 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@87 | 11 | * (at your option) any later version. |
nkeynes@87 | 12 | * |
nkeynes@87 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@87 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@87 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@87 | 16 | * GNU General Public License for more details. |
nkeynes@87 | 17 | */ |
nkeynes@87 | 18 | |
nkeynes@87 | 19 | #include "dream.h" |
nkeynes@87 | 20 | #include "mem.h" |
nkeynes@102 | 21 | #include "syscall.h" |
nkeynes@1100 | 22 | #include "asic.h" |
nkeynes@422 | 23 | #include "dreamcast.h" |
nkeynes@1099 | 24 | #include "bootstrap.h" |
nkeynes@564 | 25 | #include "sh4/sh4.h" |
nkeynes@1099 | 26 | #include "drivers/cdrom/cdrom.h" |
nkeynes@1107 | 27 | #include "drivers/cdrom/isofs.h" |
nkeynes@1099 | 28 | #include "gdrom/gdrom.h" |
nkeynes@87 | 29 | |
nkeynes@1103 | 30 | gboolean bios_boot_gdrom_disc( void ); |
nkeynes@1103 | 31 | |
nkeynes@1100 | 32 | /* Definitions from KOS */ |
nkeynes@87 | 33 | #define COMMAND_QUEUE_LENGTH 16 |
nkeynes@87 | 34 | |
nkeynes@1100 | 35 | #define GD_CMD_PIOREAD 16 /* readcd */ |
nkeynes@1100 | 36 | #define GD_CMD_DMAREAD 17 /* readcd */ |
nkeynes@87 | 37 | #define GD_CMD_GETTOC 18 |
nkeynes@1100 | 38 | #define GD_CMD_GETTOC2 19 /* toc2 */ |
nkeynes@1100 | 39 | #define GD_CMD_PLAY 20 /* playcd */ |
nkeynes@1100 | 40 | #define GD_CMD_PLAY2 21 /* playcd */ |
nkeynes@1100 | 41 | #define GD_CMD_PAUSE 22 /* No params */ |
nkeynes@1100 | 42 | #define GD_CMD_RELEASE 23 /* No params */ |
nkeynes@1100 | 43 | #define GD_CMD_INIT 24 /* No params */ |
nkeynes@87 | 44 | #define GD_CMD_SEEK 27 |
nkeynes@87 | 45 | #define GD_CMD_READ 28 |
nkeynes@1100 | 46 | #define GD_CMD_STOP 33 /* No params */ |
nkeynes@87 | 47 | #define GD_CMD_GETSCD 34 |
nkeynes@87 | 48 | #define GD_CMD_GETSES 35 |
nkeynes@87 | 49 | |
nkeynes@1100 | 50 | #define GD_CMD_STATUS_NONE 0 |
nkeynes@87 | 51 | #define GD_CMD_STATUS_ACTIVE 1 |
nkeynes@1100 | 52 | #define GD_CMD_STATUS_DONE 2 |
nkeynes@1100 | 53 | #define GD_CMD_STATUS_ABORT 3 |
nkeynes@1100 | 54 | #define GD_CMD_STATUS_ERROR 4 |
nkeynes@87 | 55 | |
nkeynes@87 | 56 | #define GD_ERROR_OK 0 |
nkeynes@87 | 57 | #define GD_ERROR_NO_DISC 2 |
nkeynes@87 | 58 | #define GD_ERROR_DISC_CHANGE 6 |
nkeynes@87 | 59 | #define GD_ERROR_SYSTEM 1 |
nkeynes@87 | 60 | |
nkeynes@1101 | 61 | struct gdrom_toc2_params { |
nkeynes@1101 | 62 | uint32_t session; |
nkeynes@1101 | 63 | sh4addr_t buffer; |
nkeynes@1101 | 64 | }; |
nkeynes@1101 | 65 | |
nkeynes@1101 | 66 | struct gdrom_readcd_params { |
nkeynes@1101 | 67 | cdrom_lba_t lba; |
nkeynes@1101 | 68 | cdrom_count_t count; |
nkeynes@1101 | 69 | sh4addr_t buffer; |
nkeynes@1101 | 70 | uint32_t unknown; |
nkeynes@1101 | 71 | }; |
nkeynes@1101 | 72 | |
nkeynes@1101 | 73 | struct gdrom_playcd_params { |
nkeynes@1101 | 74 | cdrom_lba_t start; |
nkeynes@1101 | 75 | cdrom_lba_t end; |
nkeynes@1101 | 76 | uint32_t repeat; |
nkeynes@1101 | 77 | }; |
nkeynes@1101 | 78 | |
nkeynes@1100 | 79 | typedef union gdrom_cmd_params { |
nkeynes@1101 | 80 | struct gdrom_toc2_params toc2; |
nkeynes@1101 | 81 | struct gdrom_readcd_params readcd; |
nkeynes@1101 | 82 | struct gdrom_playcd_params playcd; |
nkeynes@1100 | 83 | } *gdrom_cmd_params_t; |
nkeynes@1100 | 84 | |
nkeynes@1100 | 85 | |
nkeynes@1100 | 86 | |
nkeynes@1100 | 87 | |
nkeynes@1100 | 88 | typedef struct gdrom_queue_entry { |
nkeynes@87 | 89 | int status; |
nkeynes@87 | 90 | uint32_t cmd_code; |
nkeynes@1101 | 91 | union gdrom_cmd_params params; |
nkeynes@87 | 92 | uint32_t result[4]; |
nkeynes@1100 | 93 | } *gdrom_queue_entry_t; |
nkeynes@87 | 94 | |
nkeynes@1100 | 95 | static struct gdrom_queue_entry gdrom_cmd_queue[COMMAND_QUEUE_LENGTH]; |
nkeynes@87 | 96 | |
nkeynes@87 | 97 | static struct bios_gdrom_status { |
nkeynes@87 | 98 | uint32_t status; |
nkeynes@87 | 99 | uint32_t disk_type; |
nkeynes@87 | 100 | } bios_gdrom_status; |
nkeynes@87 | 101 | |
nkeynes@1101 | 102 | void bios_gdrom_init( void ) |
nkeynes@1101 | 103 | { |
nkeynes@1101 | 104 | memset( &gdrom_cmd_queue, 0, sizeof(gdrom_cmd_queue) ); |
nkeynes@1101 | 105 | } |
nkeynes@1101 | 106 | |
nkeynes@1100 | 107 | void bios_gdrom_run_command( gdrom_queue_entry_t cmd ) |
nkeynes@87 | 108 | { |
nkeynes@87 | 109 | DEBUG( "BIOS GD command %d", cmd->cmd_code ); |
nkeynes@1101 | 110 | cdrom_error_t status = CDROM_ERROR_OK; |
nkeynes@1101 | 111 | sh4ptr_t ptr; |
nkeynes@87 | 112 | switch( cmd->cmd_code ) { |
nkeynes@87 | 113 | case GD_CMD_INIT: |
nkeynes@736 | 114 | /* *shrug* */ |
nkeynes@736 | 115 | cmd->status = GD_CMD_STATUS_DONE; |
nkeynes@736 | 116 | break; |
nkeynes@1101 | 117 | case GD_CMD_GETTOC2: |
nkeynes@1101 | 118 | ptr = mem_get_region( cmd->params.toc2.buffer ); |
nkeynes@1101 | 119 | status = gdrom_read_toc( ptr ); |
nkeynes@1101 | 120 | if( status == CDROM_ERROR_OK ) { |
nkeynes@1101 | 121 | /* Convert data to little-endian */ |
nkeynes@1101 | 122 | struct gdrom_toc *toc = (struct gdrom_toc *)ptr; |
nkeynes@1101 | 123 | for( unsigned i=0; i<99; i++ ) { |
nkeynes@1101 | 124 | toc->track[i] = ntohl(toc->track[i]); |
nkeynes@1101 | 125 | } |
nkeynes@1101 | 126 | toc->first = ntohl(toc->first); |
nkeynes@1101 | 127 | toc->last = ntohl(toc->last); |
nkeynes@1101 | 128 | toc->leadout = ntohl(toc->leadout); |
nkeynes@1101 | 129 | } |
nkeynes@1101 | 130 | break; |
nkeynes@1101 | 131 | case GD_CMD_PIOREAD: |
nkeynes@1101 | 132 | case GD_CMD_DMAREAD: |
nkeynes@1101 | 133 | ptr = mem_get_region( cmd->params.readcd.buffer ); |
nkeynes@1101 | 134 | status = gdrom_read_cd( cmd->params.readcd.lba, |
nkeynes@1101 | 135 | cmd->params.readcd.count, 0x28, ptr, NULL ); |
nkeynes@1101 | 136 | break; |
nkeynes@1101 | 137 | default: |
nkeynes@1101 | 138 | WARN( "Unknown BIOS GD command %d\n", cmd->cmd_code ); |
nkeynes@1101 | 139 | cmd->status = GD_CMD_STATUS_ERROR; |
nkeynes@1101 | 140 | cmd->result[0] = GD_ERROR_SYSTEM; |
nkeynes@1101 | 141 | return; |
nkeynes@1101 | 142 | } |
nkeynes@1101 | 143 | |
nkeynes@1101 | 144 | switch( status ) { |
nkeynes@1101 | 145 | case CDROM_ERROR_OK: |
nkeynes@1101 | 146 | cmd->status = GD_CMD_STATUS_DONE; |
nkeynes@1101 | 147 | cmd->result[0] = GD_ERROR_OK; |
nkeynes@1101 | 148 | break; |
nkeynes@1101 | 149 | case CDROM_ERROR_NODISC: |
nkeynes@1101 | 150 | cmd->status = GD_CMD_STATUS_ERROR; |
nkeynes@1101 | 151 | cmd->result[0] = GD_ERROR_NO_DISC; |
nkeynes@1101 | 152 | break; |
nkeynes@87 | 153 | default: |
nkeynes@736 | 154 | cmd->status = GD_CMD_STATUS_ERROR; |
nkeynes@736 | 155 | cmd->result[0] = GD_ERROR_SYSTEM; |
nkeynes@87 | 156 | } |
nkeynes@87 | 157 | } |
nkeynes@87 | 158 | |
nkeynes@1101 | 159 | uint32_t bios_gdrom_enqueue( uint32_t cmd, sh4addr_t data ) |
nkeynes@87 | 160 | { |
nkeynes@87 | 161 | int i; |
nkeynes@87 | 162 | for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) { |
nkeynes@736 | 163 | if( gdrom_cmd_queue[i].status != GD_CMD_STATUS_ACTIVE ) { |
nkeynes@736 | 164 | gdrom_cmd_queue[i].status = GD_CMD_STATUS_ACTIVE; |
nkeynes@736 | 165 | gdrom_cmd_queue[i].cmd_code = cmd; |
nkeynes@1101 | 166 | switch( cmd ) { |
nkeynes@1101 | 167 | case GD_CMD_PIOREAD: |
nkeynes@1101 | 168 | case GD_CMD_DMAREAD: |
nkeynes@1101 | 169 | mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.readcd, data, sizeof(struct gdrom_readcd_params) ); |
nkeynes@1101 | 170 | break; |
nkeynes@1101 | 171 | case GD_CMD_GETTOC2: |
nkeynes@1101 | 172 | mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.toc2, data, sizeof(struct gdrom_toc2_params) ); |
nkeynes@1101 | 173 | break; |
nkeynes@1101 | 174 | case GD_CMD_PLAY: |
nkeynes@1101 | 175 | case GD_CMD_PLAY2: |
nkeynes@1101 | 176 | mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.playcd, data, sizeof(struct gdrom_playcd_params) ); |
nkeynes@1101 | 177 | break; |
nkeynes@1101 | 178 | } |
nkeynes@736 | 179 | return i; |
nkeynes@736 | 180 | } |
nkeynes@87 | 181 | } |
nkeynes@87 | 182 | return -1; |
nkeynes@87 | 183 | } |
nkeynes@87 | 184 | |
nkeynes@87 | 185 | void bios_gdrom_run_queue( void ) |
nkeynes@87 | 186 | { |
nkeynes@87 | 187 | int i; |
nkeynes@87 | 188 | for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) { |
nkeynes@736 | 189 | if( gdrom_cmd_queue[i].status == GD_CMD_STATUS_ACTIVE ) { |
nkeynes@736 | 190 | bios_gdrom_run_command( &gdrom_cmd_queue[i] ); |
nkeynes@736 | 191 | } |
nkeynes@87 | 192 | } |
nkeynes@87 | 193 | } |
nkeynes@87 | 194 | |
nkeynes@1100 | 195 | gdrom_queue_entry_t bios_gdrom_get_command( uint32_t id ) |
nkeynes@87 | 196 | { |
nkeynes@87 | 197 | if( id >= COMMAND_QUEUE_LENGTH || |
nkeynes@736 | 198 | gdrom_cmd_queue[id].status == GD_CMD_STATUS_NONE ) |
nkeynes@736 | 199 | return NULL; |
nkeynes@87 | 200 | return &gdrom_cmd_queue[id]; |
nkeynes@87 | 201 | } |
nkeynes@87 | 202 | |
nkeynes@87 | 203 | /** |
nkeynes@1102 | 204 | * Address of the system information block (in the flash rom). Also repeats |
nkeynes@1102 | 205 | * at FLASH_SYSINFO_SEGMENT+0xA0 |
nkeynes@87 | 206 | */ |
nkeynes@1102 | 207 | #define FLASH_SYSINFO_SEGMENT 0x0021a000 |
nkeynes@1102 | 208 | #define FLASH_CONFIG_SEGMENT 0x0021c000 |
nkeynes@1102 | 209 | #define FLASH_CONFIG_LENGTH 0x00004000 |
nkeynes@1102 | 210 | #define FLASH_PARTITION_MAGIC "KATANA_FLASH____" |
nkeynes@87 | 211 | |
nkeynes@1102 | 212 | /** |
nkeynes@1102 | 213 | * Locate the active config block. FIXME: This isn't completely correct, but it works |
nkeynes@1102 | 214 | * under at least some circumstances. |
nkeynes@1102 | 215 | */ |
nkeynes@1102 | 216 | static char *bios_find_flash_config( sh4addr_t segment, uint32_t length ) |
nkeynes@1102 | 217 | { |
nkeynes@1102 | 218 | char *start = mem_get_region(segment); |
nkeynes@1102 | 219 | char *p = start + 0x80; |
nkeynes@1102 | 220 | char *end = p + length; |
nkeynes@1102 | 221 | char *result = NULL; |
nkeynes@1102 | 222 | |
nkeynes@1102 | 223 | if( memcmp( start, FLASH_PARTITION_MAGIC, 16 ) != 0 ) |
nkeynes@1102 | 224 | return NULL; /* Missing magic */ |
nkeynes@1102 | 225 | while( p < end ) { |
nkeynes@1102 | 226 | if( p[0] == 0x05 && p[1] == 0 ) { |
nkeynes@1102 | 227 | result = p; |
nkeynes@1102 | 228 | } |
nkeynes@1102 | 229 | p += 0x40; |
nkeynes@1102 | 230 | } |
nkeynes@1102 | 231 | return result; |
nkeynes@1102 | 232 | } |
nkeynes@1102 | 233 | |
nkeynes@1102 | 234 | /** |
nkeynes@1102 | 235 | * Syscall information courtesy of Marcus Comstedt |
nkeynes@1102 | 236 | */ |
nkeynes@1102 | 237 | static void bios_sysinfo_vector( uint32_t syscallid ) |
nkeynes@1102 | 238 | { |
nkeynes@1102 | 239 | char *flash_segment, *flash_config; |
nkeynes@1102 | 240 | char *dest; |
nkeynes@1102 | 241 | DEBUG( "BIOS SYSINFO: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] ); |
nkeynes@1102 | 242 | |
nkeynes@1102 | 243 | switch( sh4r.r[7] ) { |
nkeynes@1102 | 244 | case 0: /* SYSINFO_INIT */ |
nkeynes@1102 | 245 | /* Initialize the region 8c000068 .. 8c00007f from the flash rom |
nkeynes@1102 | 246 | * uint64_t system_id; |
nkeynes@1102 | 247 | * char [5] system_props; |
nkeynes@1102 | 248 | * char [3] zero_pad (?) |
nkeynes@1102 | 249 | * char [8] settings; |
nkeynes@1102 | 250 | **/ |
nkeynes@1102 | 251 | flash_segment = mem_get_region(FLASH_SYSINFO_SEGMENT); |
nkeynes@1102 | 252 | flash_config = bios_find_flash_config(FLASH_CONFIG_SEGMENT,FLASH_CONFIG_LENGTH); |
nkeynes@1102 | 253 | dest = mem_get_region( 0x8c000068 ); |
nkeynes@1102 | 254 | memset( dest, 0, 24 ); |
nkeynes@1102 | 255 | memcpy( dest, flash_segment + 0x56, 8 ); |
nkeynes@1102 | 256 | memcpy( dest + 8, flash_segment, 5 ); |
nkeynes@1102 | 257 | if( flash_config != NULL ) { |
nkeynes@1102 | 258 | memcpy( dest+16, flash_config+2, 8 ); |
nkeynes@1102 | 259 | } |
nkeynes@1102 | 260 | break; |
nkeynes@1102 | 261 | case 2: /* SYSINFO_ICON */ |
nkeynes@1102 | 262 | /* Not supported yet */ |
nkeynes@1102 | 263 | break; |
nkeynes@1102 | 264 | case 3: /* SYSINFO_ID */ |
nkeynes@1102 | 265 | sh4r.r[0] = 0x8c000068; |
nkeynes@1102 | 266 | break; |
nkeynes@1102 | 267 | } |
nkeynes@1102 | 268 | } |
nkeynes@1102 | 269 | |
nkeynes@1102 | 270 | static void bios_flashrom_vector( uint32_t syscallid ) |
nkeynes@1102 | 271 | { |
nkeynes@1102 | 272 | char *dest; |
nkeynes@1102 | 273 | DEBUG( "BIOS FLASHROM: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] ); |
nkeynes@1102 | 274 | |
nkeynes@1102 | 275 | switch( sh4r.r[7] ) { |
nkeynes@1102 | 276 | case 0: /* FLASHROM_INFO */ |
nkeynes@1102 | 277 | break; |
nkeynes@1102 | 278 | case 1: /* FLASHROM_READ */ |
nkeynes@1102 | 279 | |
nkeynes@1102 | 280 | break; |
nkeynes@1102 | 281 | case 2: /* FLASHROM_WRITE */ |
nkeynes@1102 | 282 | break; |
nkeynes@1102 | 283 | case 3: /* FLASHROM_DELETE */ |
nkeynes@1102 | 284 | break; |
nkeynes@1102 | 285 | } |
nkeynes@1102 | 286 | } |
nkeynes@1102 | 287 | |
nkeynes@1102 | 288 | static void bios_romfont_vector( uint32_t syscallid ) |
nkeynes@1102 | 289 | { |
nkeynes@1102 | 290 | DEBUG( "BIOS ROMFONT: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] ); |
nkeynes@1102 | 291 | /* Not implemented */ |
nkeynes@1102 | 292 | } |
nkeynes@1102 | 293 | |
nkeynes@1102 | 294 | static void bios_gdrom_vector( uint32_t syscallid ) |
nkeynes@87 | 295 | { |
nkeynes@1100 | 296 | gdrom_queue_entry_t cmd; |
nkeynes@87 | 297 | |
nkeynes@1102 | 298 | DEBUG( "BIOS GDROM: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] ); |
nkeynes@1102 | 299 | |
nkeynes@1102 | 300 | switch( sh4r.r[6] ) { |
nkeynes@1102 | 301 | case 0: /* GD-Rom */ |
nkeynes@1102 | 302 | switch( sh4r.r[7] ) { |
nkeynes@1102 | 303 | case 0: /* Send command */ |
nkeynes@1102 | 304 | sh4r.r[0] = bios_gdrom_enqueue( sh4r.r[4], sh4r.r[5] ); |
nkeynes@1102 | 305 | break; |
nkeynes@1102 | 306 | case 1: /* Check command */ |
nkeynes@1102 | 307 | cmd = bios_gdrom_get_command( sh4r.r[4] ); |
nkeynes@1102 | 308 | if( cmd == NULL ) { |
nkeynes@1102 | 309 | sh4r.r[0] = GD_CMD_STATUS_NONE; |
nkeynes@1102 | 310 | } else { |
nkeynes@1102 | 311 | sh4r.r[0] = cmd->status; |
nkeynes@1102 | 312 | if( cmd->status == GD_CMD_STATUS_ERROR && |
nkeynes@1102 | 313 | sh4r.r[5] != 0 ) { |
nkeynes@1102 | 314 | mem_copy_to_sh4( sh4r.r[5], (sh4ptr_t)&cmd->result, sizeof(cmd->result) ); |
nkeynes@736 | 315 | } |
nkeynes@736 | 316 | } |
nkeynes@736 | 317 | break; |
nkeynes@1102 | 318 | case 2: /* Mainloop */ |
nkeynes@1102 | 319 | bios_gdrom_run_queue(); |
nkeynes@736 | 320 | break; |
nkeynes@1102 | 321 | case 3: /* Init */ |
nkeynes@1102 | 322 | bios_gdrom_init(); |
nkeynes@1102 | 323 | break; |
nkeynes@1102 | 324 | case 4: /* Drive status */ |
nkeynes@1102 | 325 | if( sh4r.r[4] != 0 ) { |
nkeynes@1102 | 326 | mem_copy_to_sh4( sh4r.r[4], (sh4ptr_t)&bios_gdrom_status, |
nkeynes@1102 | 327 | sizeof(bios_gdrom_status) ); |
nkeynes@1102 | 328 | } |
nkeynes@1102 | 329 | sh4r.r[0] = 0; |
nkeynes@1102 | 330 | break; |
nkeynes@1102 | 331 | case 8: /* Abort command */ |
nkeynes@1102 | 332 | cmd = bios_gdrom_get_command( sh4r.r[4] ); |
nkeynes@1102 | 333 | if( cmd == NULL || cmd->status != GD_CMD_STATUS_ACTIVE ) { |
nkeynes@1102 | 334 | sh4r.r[0] = -1; |
nkeynes@1102 | 335 | } else { |
nkeynes@1102 | 336 | cmd->status = GD_CMD_STATUS_ABORT; |
nkeynes@1102 | 337 | sh4r.r[0] = 0; |
nkeynes@1102 | 338 | } |
nkeynes@1102 | 339 | break; |
nkeynes@1102 | 340 | case 9: /* Reset */ |
nkeynes@1102 | 341 | break; |
nkeynes@1102 | 342 | case 10: /* Set mode */ |
nkeynes@1102 | 343 | sh4r.r[0] = 0; |
nkeynes@1102 | 344 | break; |
nkeynes@736 | 345 | } |
nkeynes@736 | 346 | break; |
nkeynes@1102 | 347 | case -1: /* Misc */ |
nkeynes@1102 | 348 | break; |
nkeynes@1102 | 349 | default: /* ??? */ |
nkeynes@1102 | 350 | break; |
nkeynes@1102 | 351 | } |
nkeynes@1102 | 352 | } |
nkeynes@1102 | 353 | |
nkeynes@1102 | 354 | static void bios_menu_vector( uint32_t syscallid ) |
nkeynes@1102 | 355 | { |
nkeynes@1102 | 356 | DEBUG( "BIOS MENU: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] ); |
nkeynes@1102 | 357 | |
nkeynes@1102 | 358 | switch( sh4r.r[4] ) { |
nkeynes@1102 | 359 | case 0: |
nkeynes@1102 | 360 | WARN( "Entering main program" ); |
nkeynes@1102 | 361 | break; |
nkeynes@1102 | 362 | case 1: |
nkeynes@1102 | 363 | WARN( "Program aborted to DC menu"); |
nkeynes@1102 | 364 | dreamcast_stop(); |
nkeynes@1102 | 365 | break; |
nkeynes@87 | 366 | } |
nkeynes@87 | 367 | } |
nkeynes@102 | 368 | |
nkeynes@1099 | 369 | void bios_boot( uint32_t syscallid ) |
nkeynes@1099 | 370 | { |
nkeynes@1099 | 371 | /* Initialize hardware */ |
nkeynes@1099 | 372 | /* Boot disc if present */ |
nkeynes@1103 | 373 | if( !bios_boot_gdrom_disc() ) { |
nkeynes@1100 | 374 | dreamcast_stop(); |
nkeynes@1100 | 375 | } |
nkeynes@1099 | 376 | } |
nkeynes@1099 | 377 | |
nkeynes@102 | 378 | void bios_install( void ) |
nkeynes@102 | 379 | { |
nkeynes@102 | 380 | bios_gdrom_init(); |
nkeynes@1102 | 381 | syscall_add_hook_vector( 0xB0, 0x8C0000B0, bios_sysinfo_vector ); |
nkeynes@1102 | 382 | syscall_add_hook_vector( 0xB4, 0x8C0000B4, bios_romfont_vector ); |
nkeynes@1102 | 383 | syscall_add_hook_vector( 0xB8, 0x8C0000B8, bios_flashrom_vector ); |
nkeynes@1102 | 384 | syscall_add_hook_vector( 0xBC, 0x8C0000BC, bios_gdrom_vector ); |
nkeynes@1102 | 385 | syscall_add_hook_vector( 0xE0, 0x8C0000E0, bios_menu_vector ); |
nkeynes@102 | 386 | } |
nkeynes@1099 | 387 | |
nkeynes@1099 | 388 | #define MIN_ISO_SECTORS 32 |
nkeynes@1099 | 389 | |
nkeynes@1107 | 390 | static gboolean bios_load_ipl( cdrom_disc_t disc, cdrom_track_t track, const char *program_name, |
nkeynes@1107 | 391 | unsigned char *buffer, gboolean unscramble ) |
nkeynes@1107 | 392 | { |
nkeynes@1107 | 393 | gboolean rv = TRUE; |
nkeynes@1107 | 394 | |
nkeynes@1107 | 395 | IsoImageFilesystem *iso = iso_filesystem_new_from_track( disc, track, NULL ); |
nkeynes@1107 | 396 | if( iso == NULL ) { |
nkeynes@1107 | 397 | ERROR( "Disc is not bootable (invalid ISO9660 filesystem)" ); |
nkeynes@1107 | 398 | return FALSE; |
nkeynes@1107 | 399 | } |
nkeynes@1107 | 400 | IsoFileSource *file = NULL; |
nkeynes@1107 | 401 | int status = iso->get_by_path(iso, program_name, &file ); |
nkeynes@1107 | 402 | if( status != 1 ) { |
nkeynes@1107 | 403 | ERROR( "Disc is not bootable (initial program '%s' not found)", program_name ); |
nkeynes@1107 | 404 | iso_filesystem_unref(iso); |
nkeynes@1107 | 405 | return FALSE; |
nkeynes@1107 | 406 | } |
nkeynes@1107 | 407 | |
nkeynes@1107 | 408 | struct stat st; |
nkeynes@1107 | 409 | if( iso_file_source_stat(file, &st) == 1 ) { |
nkeynes@1107 | 410 | if( st.st_size > (0x8D000000 - BINARY_LOAD_ADDR) ) { |
nkeynes@1107 | 411 | ERROR( "Disc is not bootable (Initial program is too large to fit into memory)" ); |
nkeynes@1107 | 412 | rv = FALSE; |
nkeynes@1107 | 413 | } else if( iso_file_source_open(file) == 1 ) { |
nkeynes@1107 | 414 | size_t len; |
nkeynes@1107 | 415 | if( unscramble ) { |
nkeynes@1107 | 416 | char *tmp = g_malloc(st.st_size); |
nkeynes@1107 | 417 | len = iso_file_source_read(file, tmp, st.st_size); |
nkeynes@1107 | 418 | bootprogram_unscramble(buffer, tmp, st.st_size); |
nkeynes@1107 | 419 | g_free(tmp); |
nkeynes@1107 | 420 | } else { |
nkeynes@1107 | 421 | len = iso_file_source_read(file, buffer, st.st_size); |
nkeynes@1107 | 422 | } |
nkeynes@1107 | 423 | |
nkeynes@1107 | 424 | if( len != st.st_size ) { |
nkeynes@1107 | 425 | ERROR( "Disc is not bootable (Unable to read initial program '%s')", program_name ); |
nkeynes@1107 | 426 | rv = FALSE; |
nkeynes@1107 | 427 | } |
nkeynes@1107 | 428 | iso_file_source_close(file); |
nkeynes@1107 | 429 | } |
nkeynes@1107 | 430 | } else { |
nkeynes@1107 | 431 | ERROR( "Disc is not bootable (Unable to get size of initial program '%s')", program_name ); |
nkeynes@1107 | 432 | rv = FALSE; |
nkeynes@1107 | 433 | } |
nkeynes@1107 | 434 | |
nkeynes@1107 | 435 | iso_file_source_unref(file); |
nkeynes@1107 | 436 | iso_filesystem_unref(iso); |
nkeynes@1107 | 437 | return rv; |
nkeynes@1107 | 438 | } |
nkeynes@1107 | 439 | |
nkeynes@1099 | 440 | gboolean bios_boot_gdrom_disc( void ) |
nkeynes@1099 | 441 | { |
nkeynes@1099 | 442 | cdrom_disc_t disc = gdrom_get_current_disc(); |
nkeynes@1099 | 443 | |
nkeynes@1099 | 444 | int status = gdrom_get_drive_status(); |
nkeynes@1099 | 445 | if( status == CDROM_DISC_NONE ) { |
nkeynes@1099 | 446 | ERROR( "No disc in drive" ); |
nkeynes@1099 | 447 | return FALSE; |
nkeynes@1099 | 448 | } |
nkeynes@1099 | 449 | |
nkeynes@1099 | 450 | /* Find the bootable data track (if present) */ |
nkeynes@1099 | 451 | cdrom_track_t track = gdrom_disc_get_boot_track(disc); |
nkeynes@1099 | 452 | if( track == NULL ) { |
nkeynes@1099 | 453 | ERROR( "Disc is not bootable" ); |
nkeynes@1099 | 454 | return FALSE; |
nkeynes@1099 | 455 | } |
nkeynes@1099 | 456 | uint32_t lba = track->lba; |
nkeynes@1099 | 457 | uint32_t sectors = cdrom_disc_get_track_size(disc,track); |
nkeynes@1099 | 458 | if( sectors < MIN_ISO_SECTORS ) { |
nkeynes@1099 | 459 | ERROR( "Disc is not bootable" ); |
nkeynes@1099 | 460 | return FALSE; |
nkeynes@1099 | 461 | } |
nkeynes@1099 | 462 | /* Load the initial bootstrap into DC ram at 8c008000 */ |
nkeynes@1099 | 463 | size_t length = BOOTSTRAP_SIZE; |
nkeynes@1099 | 464 | unsigned char *bootstrap = mem_get_region(BOOTSTRAP_LOAD_ADDR); |
nkeynes@1099 | 465 | if( cdrom_disc_read_sectors( disc, track->lba, BOOTSTRAP_SIZE/2048, |
nkeynes@1099 | 466 | CDROM_READ_DATA|CDROM_READ_MODE2_FORM1, bootstrap, &length ) != |
nkeynes@1099 | 467 | CDROM_ERROR_OK ) { |
nkeynes@1099 | 468 | ERROR( "Disc is not bootable" ); |
nkeynes@1099 | 469 | return FALSE; |
nkeynes@1099 | 470 | } |
nkeynes@1099 | 471 | |
nkeynes@1099 | 472 | /* Check the magic just to be sure */ |
nkeynes@1099 | 473 | dc_bootstrap_head_t metadata = (dc_bootstrap_head_t)bootstrap; |
nkeynes@1099 | 474 | if( memcmp( metadata->magic, BOOTSTRAP_MAGIC, BOOTSTRAP_MAGIC_SIZE ) != 0 ) { |
nkeynes@1099 | 475 | ERROR( "Disc is not bootable (missing dreamcast bootstrap)" ); |
nkeynes@1099 | 476 | return FALSE; |
nkeynes@1099 | 477 | } |
nkeynes@1099 | 478 | |
nkeynes@1099 | 479 | /* Get the initial program from the bootstrap (usually 1ST_READ.BIN) */ |
nkeynes@1107 | 480 | char program_name[18] = "/"; |
nkeynes@1107 | 481 | memcpy(program_name+1, metadata->boot_file, 16); |
nkeynes@1107 | 482 | program_name[17] = '\0'; |
nkeynes@1107 | 483 | for( int i=16; i >= 0 && program_name[i] == ' '; i-- ) { |
nkeynes@1099 | 484 | program_name[i] = '\0'; |
nkeynes@1099 | 485 | } |
nkeynes@1099 | 486 | |
nkeynes@1099 | 487 | /* Bootstrap is good. Now find the program in the actual filesystem... */ |
nkeynes@1107 | 488 | unsigned char *program = mem_get_region(BINARY_LOAD_ADDR); |
nkeynes@1107 | 489 | gboolean isGDROM = (disc->disc_type == CDROM_DISC_GDROM ); |
nkeynes@1107 | 490 | if( !bios_load_ipl( disc, track, program_name, program, !isGDROM ) ) |
nkeynes@1099 | 491 | return FALSE; |
nkeynes@1107 | 492 | asic_enable_ide_interface(isGDROM); |
nkeynes@1100 | 493 | dreamcast_program_loaded( "", BOOTSTRAP_ENTRY_ADDR ); |
nkeynes@1100 | 494 | return TRUE; |
nkeynes@1099 | 495 | } |
.