4 * "Fake" BIOS functions, for operation without the actual BIOS.
6 * Copyright (c) 2005-2010 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
23 #include "dreamcast.h"
24 #include "bootstrap.h"
26 #include "drivers/cdrom/cdrom.h"
27 #include "drivers/cdrom/isofs.h"
28 #include "gdrom/gdrom.h"
30 gboolean bios_boot_gdrom_disc( void );
32 /* Definitions from KOS */
33 #define COMMAND_QUEUE_LENGTH 16
35 #define GD_CMD_PIOREAD 16 /* readcd */
36 #define GD_CMD_DMAREAD 17 /* readcd */
37 #define GD_CMD_GETTOC 18
38 #define GD_CMD_GETTOC2 19 /* toc2 */
39 #define GD_CMD_PLAY 20 /* playcd */
40 #define GD_CMD_PLAY2 21 /* playcd */
41 #define GD_CMD_PAUSE 22 /* No params */
42 #define GD_CMD_RELEASE 23 /* No params */
43 #define GD_CMD_INIT 24 /* No params */
44 #define GD_CMD_SEEK 27
45 #define GD_CMD_READ 28
46 #define GD_CMD_STOP 33 /* No params */
47 #define GD_CMD_GETSCD 34
48 #define GD_CMD_GETSES 35
50 #define GD_CMD_STATUS_NONE 0
51 #define GD_CMD_STATUS_ACTIVE 1
52 #define GD_CMD_STATUS_DONE 2
53 #define GD_CMD_STATUS_ABORT 3
54 #define GD_CMD_STATUS_ERROR 4
57 #define GD_ERROR_NO_DISC 2
58 #define GD_ERROR_DISC_CHANGE 6
59 #define GD_ERROR_SYSTEM 1
61 struct gdrom_toc2_params {
66 struct gdrom_readcd_params {
73 struct gdrom_playcd_params {
79 typedef union gdrom_cmd_params {
80 struct gdrom_toc2_params toc2;
81 struct gdrom_readcd_params readcd;
82 struct gdrom_playcd_params playcd;
83 } *gdrom_cmd_params_t;
88 typedef struct gdrom_queue_entry {
91 union gdrom_cmd_params params;
93 } *gdrom_queue_entry_t;
95 static struct gdrom_queue_entry gdrom_cmd_queue[COMMAND_QUEUE_LENGTH];
97 static struct bios_gdrom_status {
102 void bios_gdrom_init( void )
104 memset( &gdrom_cmd_queue, 0, sizeof(gdrom_cmd_queue) );
107 void bios_gdrom_run_command( gdrom_queue_entry_t cmd )
109 DEBUG( "BIOS GD command %d", cmd->cmd_code );
110 cdrom_error_t status = CDROM_ERROR_OK;
112 switch( cmd->cmd_code ) {
115 cmd->status = GD_CMD_STATUS_DONE;
118 ptr = mem_get_region( cmd->params.toc2.buffer );
119 status = gdrom_read_toc( ptr );
120 if( status == CDROM_ERROR_OK ) {
121 /* Convert data to little-endian */
122 struct gdrom_toc *toc = (struct gdrom_toc *)ptr;
123 for( unsigned i=0; i<99; i++ ) {
124 toc->track[i] = ntohl(toc->track[i]);
126 toc->first = ntohl(toc->first);
127 toc->last = ntohl(toc->last);
128 toc->leadout = ntohl(toc->leadout);
133 ptr = mem_get_region( cmd->params.readcd.buffer );
134 status = gdrom_read_cd( cmd->params.readcd.lba,
135 cmd->params.readcd.count, 0x28, ptr, NULL );
138 WARN( "Unknown BIOS GD command %d\n", cmd->cmd_code );
139 cmd->status = GD_CMD_STATUS_ERROR;
140 cmd->result[0] = GD_ERROR_SYSTEM;
146 cmd->status = GD_CMD_STATUS_DONE;
147 cmd->result[0] = GD_ERROR_OK;
149 case CDROM_ERROR_NODISC:
150 cmd->status = GD_CMD_STATUS_ERROR;
151 cmd->result[0] = GD_ERROR_NO_DISC;
154 cmd->status = GD_CMD_STATUS_ERROR;
155 cmd->result[0] = GD_ERROR_SYSTEM;
159 uint32_t bios_gdrom_enqueue( uint32_t cmd, sh4addr_t data )
162 for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) {
163 if( gdrom_cmd_queue[i].status != GD_CMD_STATUS_ACTIVE ) {
164 gdrom_cmd_queue[i].status = GD_CMD_STATUS_ACTIVE;
165 gdrom_cmd_queue[i].cmd_code = cmd;
169 mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.readcd, data, sizeof(struct gdrom_readcd_params) );
172 mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.toc2, data, sizeof(struct gdrom_toc2_params) );
176 mem_copy_from_sh4( (unsigned char *)&gdrom_cmd_queue[i].params.playcd, data, sizeof(struct gdrom_playcd_params) );
185 void bios_gdrom_run_queue( void )
188 for( i=0; i<COMMAND_QUEUE_LENGTH; i++ ) {
189 if( gdrom_cmd_queue[i].status == GD_CMD_STATUS_ACTIVE ) {
190 bios_gdrom_run_command( &gdrom_cmd_queue[i] );
195 gdrom_queue_entry_t bios_gdrom_get_command( uint32_t id )
197 if( id >= COMMAND_QUEUE_LENGTH ||
198 gdrom_cmd_queue[id].status == GD_CMD_STATUS_NONE )
200 return &gdrom_cmd_queue[id];
204 * Address of the system information block (in the flash rom). Also repeats
205 * at FLASH_SYSINFO_SEGMENT+0xA0
207 #define FLASH_SYSINFO_SEGMENT 0x0021a000
208 #define FLASH_CONFIG_SEGMENT 0x0021c000
209 #define FLASH_CONFIG_LENGTH 0x00004000
210 #define FLASH_PARTITION_MAGIC "KATANA_FLASH____"
213 * Locate the active config block. FIXME: This isn't completely correct, but it works
214 * under at least some circumstances.
216 static char *bios_find_flash_config( sh4addr_t segment, uint32_t length )
218 char *start = mem_get_region(segment);
219 char *p = start + 0x80;
220 char *end = p + length;
223 if( memcmp( start, FLASH_PARTITION_MAGIC, 16 ) != 0 )
224 return NULL; /* Missing magic */
226 if( p[0] == 0x05 && p[1] == 0 ) {
235 * Syscall information courtesy of Marcus Comstedt
237 static void bios_sysinfo_vector( uint32_t syscallid )
239 char *flash_segment, *flash_config;
241 DEBUG( "BIOS SYSINFO: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
243 switch( sh4r.r[7] ) {
244 case 0: /* SYSINFO_INIT */
245 /* Initialize the region 8c000068 .. 8c00007f from the flash rom
246 * uint64_t system_id;
247 * char [5] system_props;
248 * char [3] zero_pad (?)
251 flash_segment = mem_get_region(FLASH_SYSINFO_SEGMENT);
252 flash_config = bios_find_flash_config(FLASH_CONFIG_SEGMENT,FLASH_CONFIG_LENGTH);
253 dest = mem_get_region( 0x8c000068 );
254 memset( dest, 0, 24 );
255 memcpy( dest, flash_segment + 0x56, 8 );
256 memcpy( dest + 8, flash_segment, 5 );
257 if( flash_config != NULL ) {
258 memcpy( dest+16, flash_config+2, 8 );
261 case 2: /* SYSINFO_ICON */
262 /* Not supported yet */
264 case 3: /* SYSINFO_ID */
265 sh4r.r[0] = 0x8c000068;
270 static void bios_flashrom_vector( uint32_t syscallid )
273 DEBUG( "BIOS FLASHROM: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
275 switch( sh4r.r[7] ) {
276 case 0: /* FLASHROM_INFO */
278 case 1: /* FLASHROM_READ */
281 case 2: /* FLASHROM_WRITE */
283 case 3: /* FLASHROM_DELETE */
288 static void bios_romfont_vector( uint32_t syscallid )
290 DEBUG( "BIOS ROMFONT: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
291 /* Not implemented */
294 static void bios_gdrom_vector( uint32_t syscallid )
296 gdrom_queue_entry_t cmd;
298 DEBUG( "BIOS GDROM: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
300 switch( sh4r.r[6] ) {
302 switch( sh4r.r[7] ) {
303 case 0: /* Send command */
304 sh4r.r[0] = bios_gdrom_enqueue( sh4r.r[4], sh4r.r[5] );
306 case 1: /* Check command */
307 cmd = bios_gdrom_get_command( sh4r.r[4] );
309 sh4r.r[0] = GD_CMD_STATUS_NONE;
311 sh4r.r[0] = cmd->status;
312 if( cmd->status == GD_CMD_STATUS_ERROR &&
314 mem_copy_to_sh4( sh4r.r[5], (sh4ptr_t)&cmd->result, sizeof(cmd->result) );
318 case 2: /* Mainloop */
319 bios_gdrom_run_queue();
324 case 4: /* Drive status */
325 if( sh4r.r[4] != 0 ) {
326 mem_copy_to_sh4( sh4r.r[4], (sh4ptr_t)&bios_gdrom_status,
327 sizeof(bios_gdrom_status) );
331 case 8: /* Abort command */
332 cmd = bios_gdrom_get_command( sh4r.r[4] );
333 if( cmd == NULL || cmd->status != GD_CMD_STATUS_ACTIVE ) {
336 cmd->status = GD_CMD_STATUS_ABORT;
342 case 10: /* Set mode */
354 static void bios_menu_vector( uint32_t syscallid )
356 DEBUG( "BIOS MENU: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] );
358 switch( sh4r.r[4] ) {
360 WARN( "Entering main program" );
363 WARN( "Program aborted to DC menu");
369 void bios_boot( uint32_t syscallid )
371 /* Initialize hardware */
372 /* Boot disc if present */
373 if( !bios_boot_gdrom_disc() ) {
378 void bios_install( void )
381 syscall_add_hook_vector( 0xB0, 0x8C0000B0, bios_sysinfo_vector );
382 syscall_add_hook_vector( 0xB4, 0x8C0000B4, bios_romfont_vector );
383 syscall_add_hook_vector( 0xB8, 0x8C0000B8, bios_flashrom_vector );
384 syscall_add_hook_vector( 0xBC, 0x8C0000BC, bios_gdrom_vector );
385 syscall_add_hook_vector( 0xE0, 0x8C0000E0, bios_menu_vector );
388 #define MIN_ISO_SECTORS 32
390 static gboolean bios_load_ipl( cdrom_disc_t disc, cdrom_track_t track, const char *program_name,
391 unsigned char *buffer, gboolean unscramble )
395 IsoImageFilesystem *iso = iso_filesystem_new_from_track( disc, track, NULL );
397 ERROR( "Disc is not bootable (invalid ISO9660 filesystem)" );
400 IsoFileSource *file = NULL;
401 int status = iso->get_by_path(iso, program_name, &file );
403 ERROR( "Disc is not bootable (initial program '%s' not found)", program_name );
404 iso_filesystem_unref(iso);
409 if( iso_file_source_stat(file, &st) == 1 ) {
410 if( st.st_size > (0x8D000000 - BINARY_LOAD_ADDR) ) {
411 ERROR( "Disc is not bootable (Initial program is too large to fit into memory)" );
413 } else if( iso_file_source_open(file) == 1 ) {
416 char *tmp = g_malloc(st.st_size);
417 len = iso_file_source_read(file, tmp, st.st_size);
418 bootprogram_unscramble(buffer, tmp, st.st_size);
421 len = iso_file_source_read(file, buffer, st.st_size);
424 if( len != st.st_size ) {
425 ERROR( "Disc is not bootable (Unable to read initial program '%s')", program_name );
428 iso_file_source_close(file);
431 ERROR( "Disc is not bootable (Unable to get size of initial program '%s')", program_name );
435 iso_file_source_unref(file);
436 iso_filesystem_unref(iso);
440 gboolean bios_boot_gdrom_disc( void )
442 cdrom_disc_t disc = gdrom_get_current_disc();
444 int status = gdrom_get_drive_status();
445 if( status == CDROM_DISC_NONE ) {
446 ERROR( "No disc in drive" );
450 /* Find the bootable data track (if present) */
451 cdrom_track_t track = gdrom_disc_get_boot_track(disc);
452 if( track == NULL ) {
453 ERROR( "Disc is not bootable" );
456 uint32_t lba = track->lba;
457 uint32_t sectors = cdrom_disc_get_track_size(disc,track);
458 if( sectors < MIN_ISO_SECTORS ) {
459 ERROR( "Disc is not bootable" );
462 /* Load the initial bootstrap into DC ram at 8c008000 */
463 size_t length = BOOTSTRAP_SIZE;
464 unsigned char *bootstrap = mem_get_region(BOOTSTRAP_LOAD_ADDR);
465 if( cdrom_disc_read_sectors( disc, track->lba, BOOTSTRAP_SIZE/2048,
466 CDROM_READ_DATA|CDROM_READ_MODE2_FORM1, bootstrap, &length ) !=
468 ERROR( "Disc is not bootable" );
472 /* Check the magic just to be sure */
473 dc_bootstrap_head_t metadata = (dc_bootstrap_head_t)bootstrap;
474 if( memcmp( metadata->magic, BOOTSTRAP_MAGIC, BOOTSTRAP_MAGIC_SIZE ) != 0 ) {
475 ERROR( "Disc is not bootable (missing dreamcast bootstrap)" );
479 /* Get the initial program from the bootstrap (usually 1ST_READ.BIN) */
480 char program_name[18] = "/";
481 memcpy(program_name+1, metadata->boot_file, 16);
482 program_name[17] = '\0';
483 for( int i=16; i >= 0 && program_name[i] == ' '; i-- ) {
484 program_name[i] = '\0';
487 /* Bootstrap is good. Now find the program in the actual filesystem... */
488 unsigned char *program = mem_get_region(BINARY_LOAD_ADDR);
489 gboolean isGDROM = (disc->disc_type == CDROM_DISC_GDROM );
490 if( !bios_load_ipl( disc, track, program_name, program, !isGDROM ) )
492 asic_enable_ide_interface(isGDROM);
493 dreamcast_program_loaded( "", BOOTSTRAP_ENTRY_ADDR );
.