33#include "core/math.h"
44#include "core/option.h"
55#include "guest/aica/aica.h"
6+ #include "guest/bios/bios.h"
67#include "guest/bios/flash.h"
8+ #include "guest/bios/syscalls.h"
79#include "guest/dreamcast.h"
10+ #include "guest/gdrom/gdrom.h"
11+ #include "guest/gdrom/iso.h"
812#include "guest/rom/flash.h"
13+ #include "guest/sh4/sh4.h"
914#include "render/imgui.h"
1015
1116DEFINE_OPTION_STRING (region , "america" , "System region" );
1217DEFINE_OPTION_STRING (language , "english" , "System language" );
1318DEFINE_OPTION_STRING (broadcast , "ntsc" , "System broadcast mode" );
1419
20+ /* system settings */
1521static const char * regions [] = {
1622 "japan" , "america" , "europe" ,
1723};
@@ -24,8 +30,22 @@ static const char *broadcasts[] = {
2430 "ntsc" , "pal" , "pal_m" , "pal_n" ,
2531};
2632
27- struct bios {
28- struct dreamcast * dc ;
33+ /* address of syscall vectors */
34+ enum {
35+ VECTOR_SYSINFO = 0x0c0000b0 ,
36+ VECTOR_FONTROM = 0x0c0000b4 ,
37+ VECTOR_FLASHROM = 0x0c0000b8 ,
38+ VECTOR_GDROM = 0x0c0000bc ,
39+ VECTOR_MENU = 0x0c0000e0 ,
40+ };
41+
42+ /* address of syscall entrypoints */
43+ enum {
44+ SYSCALL_SYSINFO = 0x0c003c00 ,
45+ SYSCALL_FONTROM = 0x0c003b80 ,
46+ SYSCALL_FLASHROM = 0x0c003d00 ,
47+ SYSCALL_GDROM = 0x0c001000 ,
48+ SYSCALL_MENU = 0x0c000800 ,
2949};
3050
3151static uint32_t bios_local_time () {
@@ -148,7 +168,7 @@ static void bios_validate_flash(struct bios *bios) {
148168
149169 /* validate partition 1 (reserved) */
150170 {
151- LOG_INFO ("bios_validate_flash resetting FLASH_PT_RESERVED" );
171+ /* LOG_INFO("bios_validate_flash resetting FLASH_PT_RESERVED"); */
152172
153173 flash_erase_partition (flash , FLASH_PT_RESERVED );
154174 }
@@ -184,6 +204,131 @@ static void bios_validate_flash(struct bios *bios) {
184204 }
185205}
186206
207+ static int bios_boot (struct bios * bios ) {
208+ struct dreamcast * dc = bios -> dc ;
209+ struct flash * flash = dc -> flash ;
210+ struct gdrom * gd = dc -> gdrom ;
211+ struct sh4 * sh4 = dc -> sh4 ;
212+ struct sh4_context * ctx = & sh4 -> ctx ;
213+ struct address_space * space = sh4 -> memory_if -> space ;
214+
215+ const uint32_t BOOT1_ADDR = 0x8c008000 ;
216+ const uint32_t BOOT2_ADDR = 0x8c010000 ;
217+ const uint32_t SYSINFO_ADDR = 0x8c000068 ;
218+ const enum gd_secfmt secfmt = SECTOR_ANY ;
219+ const enum gd_secmask secmask = MASK_DATA ;
220+ const int secsz = 2048 ;
221+ uint8_t tmp [0x10000 ];
222+
223+ LOG_INFO ("bios_boot using hle bootstrap" );
224+
225+ /* load ip.bin bootstrap */
226+ {
227+ int fad = 45150 ;
228+ int n = 16 ;
229+ int r = gdrom_read_sectors (gd , fad , secfmt , secmask , n , tmp , sizeof (tmp ));
230+ if (!r ) {
231+ return 0 ;
232+ }
233+ as_memcpy_to_guest (space , BOOT1_ADDR , tmp , r );
234+ }
235+
236+ /* load 1st_read.bin into ram */
237+ {
238+ static const char * bootfile = "1ST_READ.BIN" ;
239+
240+ /* read primary volume descriptor */
241+ int fad = 45150 + ISO_PVD_SECTOR ;
242+ int n = 1 ;
243+ int r = gdrom_read_sectors (gd , fad , secfmt , secmask , n , tmp , sizeof (tmp ));
244+ if (!r ) {
245+ return 0 ;
246+ }
247+
248+ struct iso_pvd * pvd = (struct iso_pvd * )tmp ;
249+ CHECK (pvd -> type == 1 );
250+ CHECK (memcmp (pvd -> id , "CD001" , 5 ) == 0 );
251+ CHECK (pvd -> version == 1 );
252+
253+ /* check root directory for the bootfile */
254+ struct iso_dir * root = & pvd -> root_directory_record ;
255+ int len = align_up (root -> size .le , secsz );
256+ fad = GDROM_PREGAP + root -> extent .le ;
257+ n = len / secsz ;
258+ r = gdrom_read_sectors (gd , fad , secfmt , secmask , n , tmp , sizeof (tmp ));
259+ if (!r ) {
260+ return 0 ;
261+ }
262+
263+ uint8_t * ptr = tmp ;
264+ uint8_t * end = tmp + len ;
265+
266+ while (ptr < end ) {
267+ struct iso_dir * dir = (struct iso_dir * )ptr ;
268+ const char * filename = (const char * )(ptr + sizeof (* dir ));
269+
270+ if (memcmp (filename , bootfile , strlen (bootfile )) == 0 ) {
271+ break ;
272+ }
273+
274+ /* dir entries always begin on an even byte */
275+ ptr = (uint8_t * )filename + dir -> name_len ;
276+ ptr = (uint8_t * )align_up ((intptr_t )ptr , (intptr_t )2 );
277+ }
278+
279+ if (ptr == end ) {
280+ LOG_WARNING ("bios_boot failed to find '%s'" , bootfile );
281+ return 0 ;
282+ }
283+
284+ /* copy the bootfile into ram */
285+ struct iso_dir * dir = (struct iso_dir * )ptr ;
286+ fad = GDROM_PREGAP + dir -> extent .le ;
287+ n = align_up (dir -> size .le , secsz ) / secsz ;
288+ r = gdrom_copy_sectors (gd , fad , secfmt , secmask , n , space , BOOT2_ADDR );
289+ if (!r ) {
290+ return 0 ;
291+ }
292+
293+ LOG_INFO ("bios_boot found '%s' at fad=%d size=%d" , bootfile , fad ,
294+ dir -> size .le );
295+ }
296+
297+ /* write system info */
298+ {
299+ uint8_t data [24 ] = {0 };
300+
301+ /* read system id from 0x0001a056 */
302+ flash_read (flash , 0x1a056 , & data [0 ], 8 );
303+
304+ /* read system properties from 0x0001a000 */
305+ flash_read (flash , 0x1a000 , & data [8 ], 5 );
306+
307+ /* read system settings */
308+ struct flash_syscfg_block syscfg ;
309+ int r = flash_read_block (flash , FLASH_PT_USER , FLASH_USER_SYSCFG , & syscfg );
310+ CHECK_EQ (r , 1 );
311+
312+ memcpy (& data [16 ], & syscfg .time_lo , 8 );
313+
314+ as_memcpy_to_guest (space , SYSINFO_ADDR , data , sizeof (data ));
315+ }
316+
317+ /* write out syscall addresses to vectors */
318+ {
319+ as_write32 (space , VECTOR_FONTROM , SYSCALL_FONTROM );
320+ as_write32 (space , VECTOR_SYSINFO , SYSCALL_SYSINFO );
321+ as_write32 (space , VECTOR_FLASHROM , SYSCALL_FLASHROM );
322+ as_write32 (space , VECTOR_GDROM , SYSCALL_GDROM );
323+ as_write32 (space , VECTOR_MENU , SYSCALL_MENU );
324+ }
325+
326+ /* start executing at license screen code inside of ip.bin */
327+ ctx -> pc = 0xac008300 ;
328+
329+ return 1 ;
330+ }
331+
187332void bios_debug_menu (struct bios * bios ) {
188333 int changed = 0 ;
189334
@@ -238,11 +383,69 @@ void bios_debug_menu(struct bios *bios) {
238383 }
239384}
240385
386+ int bios_invalid_instr (struct bios * bios ) {
387+ struct dreamcast * dc = bios -> dc ;
388+ struct sh4_context * ctx = & dc -> sh4 -> ctx ;
389+ uint32_t pc = ctx -> pc & 0x1cffffff ;
390+
391+ if (pc == 0x0 ) {
392+ return bios_boot (bios );
393+ }
394+
395+ int handled = 1 ;
396+
397+ switch (pc ) {
398+ case SYSCALL_FONTROM :
399+ bios_fontrom_vector (bios );
400+ break ;
401+
402+ case SYSCALL_SYSINFO :
403+ bios_sysinfo_vector (bios );
404+ break ;
405+
406+ case SYSCALL_FLASHROM :
407+ bios_flashrom_vector (bios );
408+ break ;
409+
410+ case SYSCALL_GDROM :
411+ bios_gdrom_vector (bios );
412+ break ;
413+
414+ case SYSCALL_MENU :
415+ bios_menu_vector (bios );
416+ break ;
417+
418+ default :
419+ handled = 0 ;
420+ break ;
421+ }
422+
423+ return handled ;
424+ }
425+
241426int bios_init (struct bios * bios ) {
242427 bios_validate_flash (bios );
243428
244429 bios_override_flash_settings (bios );
245430
431+ /* this code enables a "hybrid" hle mode. in this mode, syscalls are patched
432+ to trap into their hle handlers, but the real bios can still be ran to
433+ test if bugs exist in the syscall emulation or bootstrap emulation */
434+ #if 0
435+ /* write out invalid instructions at syscall entry points. note, the boot rom
436+ does a bootstrap on startup which copies the boot rom into system ram. due
437+ to this, the invalid instructions are written to the original rom, not the
438+ system ram (or else, they would be overwritten by the bootstrap process) */
439+ struct boot * boot = bios -> dc -> boot ;
440+ uint16_t invalid = 0x0 ;
441+
442+ boot_write (boot , SYSCALL_FONTROM , & invalid , 2 );
443+ boot_write (boot , SYSCALL_SYSINFO , & invalid , 2 );
444+ boot_write (boot , SYSCALL_FLASHROM , & invalid , 2 );
445+ boot_write (boot , SYSCALL_GDROM , & invalid , 2 );
446+ /*boot_write(boot, SYSCALL_MENU, &invalid, 2);*/
447+ #endif
448+
246449 return 1 ;
247450}
248451
0 commit comments