/** * Syscall information courtesy of Marcus Comstedt */ static void bios_sysinfo_vector( uint32_t syscallid ) { char *flash_segment, *flash_config; char *dest; DEBUG( "BIOS SYSINFO: r4 = %08X, r5 = %08X, r6 = %08x, r7= %08X", sh4r.r[4], sh4r.r[5], sh4r.r[6], sh4r.r[7] ); switch( sh4r.r[7] ) { case 0: /* SYSINFO_INIT */ /* Initialize the region 8c000068 .. 8c00007f from the flash rom * uint64_t system_id; * char [5] system_props; * char [3] zero_pad (?) * char [8] settings; **/ flash_segment = mem_get_region(FLASH_SYSINFO_SEGMENT); flash_config = bios_find_flash_config(FLASH_CONFIG_SEGMENT,FLASH_CONFIG_LENGTH); dest = mem_get_region( 0x8c000068 ); memset( dest, 0, 24 ); memcpy( dest, flash_segment + 0x56, 8 ); memcpy( dest + 8, flash_segment, 5 ); if( flash_config != NULL ) { memcpy( dest+16, flash_config+2, 8 ); } break; case 2: /* SYSINFO_ICON */ /* Not supported yet */ break; case 3: /* SYSINFO_ID */ sh4r.r[0] = 0x8c000068; break; } }
gboolean bios_boot_gdrom_disc( void ) { cdrom_disc_t disc = gdrom_get_current_disc(); int status = gdrom_get_drive_status(); if( status == CDROM_DISC_NONE ) { ERROR( "No disc in drive" ); return FALSE; } /* Find the bootable data track (if present) */ cdrom_track_t track = gdrom_disc_get_boot_track(disc); if( track == NULL ) { ERROR( "Disc is not bootable" ); return FALSE; } uint32_t lba = track->lba; uint32_t sectors = cdrom_disc_get_track_size(disc,track); if( sectors < MIN_ISO_SECTORS ) { ERROR( "Disc is not bootable" ); return FALSE; } /* Load the initial bootstrap into DC ram at 8c008000 */ size_t length = BOOTSTRAP_SIZE; unsigned char *bootstrap = mem_get_region(BOOTSTRAP_LOAD_ADDR); if( cdrom_disc_read_sectors( disc, track->lba, BOOTSTRAP_SIZE/2048, CDROM_READ_DATA|CDROM_READ_MODE2_FORM1, bootstrap, &length ) != CDROM_ERROR_OK ) { ERROR( "Disc is not bootable" ); return FALSE; } /* Check the magic just to be sure */ dc_bootstrap_head_t metadata = (dc_bootstrap_head_t)bootstrap; if( memcmp( metadata->magic, BOOTSTRAP_MAGIC, BOOTSTRAP_MAGIC_SIZE ) != 0 ) { ERROR( "Disc is not bootable (missing dreamcast bootstrap)" ); return FALSE; } /* Get the initial program from the bootstrap (usually 1ST_READ.BIN) */ char program_name[18] = "/"; memcpy(program_name+1, metadata->boot_file, 16); program_name[17] = '\0'; for( int i=16; i >= 0 && program_name[i] == ' '; i-- ) { program_name[i] = '\0'; } /* Bootstrap is good. Now find the program in the actual filesystem... */ unsigned char *program = mem_get_region(BINARY_LOAD_ADDR); gboolean isGDROM = (disc->disc_type == CDROM_DISC_GDROM ); if( !bios_load_ipl( disc, track, program_name, program, !isGDROM ) ) return FALSE; asic_enable_ide_interface(isGDROM); dreamcast_program_loaded( "", BOOTSTRAP_ENTRY_ADDR ); return TRUE; }
void bios_gdrom_run_command( gdrom_queue_entry_t cmd ) { DEBUG( "BIOS GD command %d", cmd->cmd_code ); cdrom_error_t status = CDROM_ERROR_OK; sh4ptr_t ptr; switch( cmd->cmd_code ) { case GD_CMD_INIT: /* *shrug* */ cmd->status = GD_CMD_STATUS_DONE; break; case GD_CMD_GETTOC2: ptr = mem_get_region( cmd->params.toc2.buffer ); status = gdrom_read_toc( ptr ); if( status == CDROM_ERROR_OK ) { /* Convert data to little-endian */ struct gdrom_toc *toc = (struct gdrom_toc *)ptr; for( unsigned i=0; i<99; i++ ) { toc->track[i] = ntohl(toc->track[i]); } toc->first = ntohl(toc->first); toc->last = ntohl(toc->last); toc->leadout = ntohl(toc->leadout); } break; case GD_CMD_PIOREAD: case GD_CMD_DMAREAD: ptr = mem_get_region( cmd->params.readcd.buffer ); status = gdrom_read_cd( cmd->params.readcd.lba, cmd->params.readcd.count, 0x28, ptr, NULL ); break; default: WARN( "Unknown BIOS GD command %d\n", cmd->cmd_code ); cmd->status = GD_CMD_STATUS_ERROR; cmd->result[0] = GD_ERROR_SYSTEM; return; } switch( status ) { case CDROM_ERROR_OK: cmd->status = GD_CMD_STATUS_DONE; cmd->result[0] = GD_ERROR_OK; break; case CDROM_ERROR_NODISC: cmd->status = GD_CMD_STATUS_ERROR; cmd->result[0] = GD_ERROR_NO_DISC; break; default: cmd->status = GD_CMD_STATUS_ERROR; cmd->result[0] = GD_ERROR_SYSTEM; } }
void *sbrk(int incr) { struct process_info *ppi = fd32_get_current_pi(); BYTE *prev_heap_end = NULL; DWORD memlimit = ppi->memlimit; if (memlimit != 0) { prev_heap_end = (BYTE *)memlimit; if (incr > 0) { if (mem_get_region(memlimit, incr) == -1) { message("Ermmm... SBRK problem: cannot memget(%lx %x)\n", memlimit, incr); mem_dump(); return 0; } } else if (incr < 0) { mem_free(memlimit + incr, -incr); } /* Change the memlimit */ ppi->memlimit += incr; } else { message("sbrk error: Memory Limit == 0!\n"); fd32_abort(); } return prev_heap_end; }
void sort_dma_transfer( ) { sh4addr_t table_addr = MMIO_READ( ASIC, SORTDMATBL ); sh4addr_t data_addr = MMIO_READ( ASIC, SORTDMADATA ); int table_size = MMIO_READ( ASIC, SORTDMATSIZ ); int addr_shift = MMIO_READ( ASIC, SORTDMAASIZ ) ? 5 : 0; int count = 1; uint32_t *table32 = (uint32_t *)mem_get_region( table_addr ); uint16_t *table16 = (uint16_t *)table32; uint32_t next = table_size ? (*table32++) : (uint32_t)(*table16++); while(1) { next &= 0x07FFFFFF; if( next == 1 ) { next = table_size ? (*table32++) : (uint32_t)(*table16++); count++; continue; } else if( next == 2 ) { asic_event( EVENT_SORT_DMA ); break; } uint32_t *data = (uint32_t *)mem_get_region(data_addr + (next<<addr_shift)); if( data == NULL ) { break; } uint32_t *poly = pvr2_ta_find_polygon_context(data, 128); if( poly == NULL ) { asic_event( EVENT_SORT_DMA_ERR ); break; } uint32_t size = poly[6] & 0xFF; if( size == 0 ) { size = 0x100; } next = poly[7]; pvr2_ta_write( (unsigned char *)data, size<<5 ); } MMIO_WRITE( ASIC, SORTDMACNT, count ); MMIO_WRITE( ASIC, SORTDMACTL, 0 ); }
/** * Locate the active config block. FIXME: This isn't completely correct, but it works * under at least some circumstances. */ static char *bios_find_flash_config( sh4addr_t segment, uint32_t length ) { char *start = mem_get_region(segment); char *p = start + 0x80; char *end = p + length; char *result = NULL; if( memcmp( start, FLASH_PARTITION_MAGIC, 16 ) != 0 ) return NULL; /* Missing magic */ while( p < end ) { if( p[0] == 0x05 && p[1] == 0 ) { result = p; } p += 0x40; } return result; }
static gboolean file_load_binary( const gchar *filename, int fd, ERROR *err ) { struct stat st; if( fstat( fd, &st ) == -1 ) { SET_ERROR( err, LX_ERR_FILE_IOERROR, "Error reading binary file '%s' (%s)", filename, strerror(errno) ); return FALSE; } if( st.st_size > BINARY_MAX_SIZE ) { SET_ERROR( err, LX_ERR_FILE_INVALID, "Binary file '%s' is too large to fit in memory", filename ); return FALSE; } sh4ptr_t target = mem_get_region( BINARY_LOAD_ADDR ); if( read( fd, target, st.st_size ) != st.st_size ) { SET_ERROR( err, LX_ERR_FILE_IOERROR, "Error reading binary file '%s' (%s)", filename, strerror(errno) ); return FALSE; } file_load_postload( filename, BINARY_LOAD_ADDR ); return TRUE; }
static gboolean file_load_elf( const gchar *filename, int fd, ERROR *err ) { Elf32_Ehdr head; Elf32_Phdr phdr; Elf32_Shdr shdr; Elf32_Sym sym; int i; if( read( fd, &head, sizeof(head) ) != sizeof(head) ) return FALSE; if( !is_sh4_elf(&head) ) { SET_ERROR( err, LX_ERR_FILE_INVALID, "File is not an SH4 ELF executable file" ); return FALSE; } /* Program headers */ for( i=0; i<head.e_phnum; i++ ) { lseek( fd, head.e_phoff + i*head.e_phentsize, SEEK_SET ); read( fd, &phdr, sizeof(phdr) ); if( phdr.p_type == PT_LOAD ) { lseek( fd, phdr.p_offset, SEEK_SET ); sh4ptr_t target = mem_get_region( phdr.p_vaddr ); read( fd, target, phdr.p_filesz ); if( phdr.p_memsz > phdr.p_filesz ) { memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz ); } } } /* Find symbol table */ uint32_t symtabOffset = 0, symtabSize = 0, symtabEntSize = 0; uint32_t strtabOffset = 0, strtabSize = 0; for( int i = 0; i < head.e_shnum; i++ ) { lseek( fd, head.e_shoff + i * head.e_shentsize, SEEK_SET ); read( fd, &shdr, sizeof( shdr ) ); if( shdr.sh_type == SHT_SYMTAB ) { symtabOffset = shdr.sh_offset; symtabSize = shdr.sh_size; symtabEntSize = shdr.sh_entsize; } else if( shdr.sh_type == SHT_STRTAB ) { strtabOffset = shdr.sh_offset; strtabSize = shdr.sh_size; } } /* Extract symbols */ if( symtabOffset != 0 && strtabOffset != 0 ) { unsigned numSymtabEntries = symtabSize / symtabEntSize; char *data = g_malloc( numSymtabEntries * sizeof( struct sh4_symbol ) + strtabSize ); struct sh4_symbol *symtab = ( struct sh4_symbol * )data; char *strings = data + ( numSymtabEntries * sizeof( struct sh4_symbol ) ); lseek( fd, strtabOffset, SEEK_SET ); read( fd, strings, strtabSize ); strings[strtabSize-1] = '\0'; /* Should already be 0, but just in case */ for( int i = 0; i < numSymtabEntries; i++ ) { lseek( fd, symtabOffset + ( i * symtabEntSize ), SEEK_SET ); read( fd, &sym, sizeof( sym ) ); if( sym.st_name < strtabSize ) symtab[i].name = &strings[sym.st_name]; else symtab[i].name = NULL; symtab[i].address = sym.st_value; symtab[i].size = sym.st_size; } sh4_set_symbol_table( symtab, numSymtabEntries, ( sh4_symtab_destroy_cb )free ); } file_load_postload( filename, head.e_entry ); return TRUE; }