nkeynes@26: /** nkeynes@502: * $Id: loader.c,v 1.22 2007-11-08 11:54:16 nkeynes Exp $ nkeynes@1: * nkeynes@26: * File loading routines, mostly for loading demos without going through the nkeynes@26: * whole procedure of making a CD image for them. nkeynes@26: * nkeynes@26: * Copyright (c) 2005 Nathan Keynes. nkeynes@26: * nkeynes@26: * This program is free software; you can redistribute it and/or modify nkeynes@26: * it under the terms of the GNU General Public License as published by nkeynes@26: * the Free Software Foundation; either version 2 of the License, or nkeynes@26: * (at your option) any later version. nkeynes@26: * nkeynes@26: * This program is distributed in the hope that it will be useful, nkeynes@26: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@26: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@26: * GNU General Public License for more details. nkeynes@1: */ nkeynes@1: nkeynes@481: #include nkeynes@1: #include nkeynes@1: #include nkeynes@1: #include nkeynes@1: #include nkeynes@1: #include nkeynes@105: #include nkeynes@26: #include "mem.h" nkeynes@26: #include "bootstrap.h" nkeynes@171: #include "dreamcast.h" nkeynes@450: #include "config.h" nkeynes@427: #include "loader.h" nkeynes@481: nkeynes@26: char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES"; nkeynes@1: char iso_magic[6] = "\001CD001"; nkeynes@26: char *file_loader_extensions[][2] = { nkeynes@26: { "sbi", "Self Boot Inducer" }, nkeynes@26: { "bin", "SH4 Bin file" }, nkeynes@26: { NULL, NULL } }; nkeynes@26: nkeynes@26: #define BOOTSTRAP_LOAD_ADDR 0x8C008000 nkeynes@26: #define BOOTSTRAP_SIZE 32768 nkeynes@26: nkeynes@26: #define BINARY_LOAD_ADDR 0x8C010000 nkeynes@1: nkeynes@1: #define CDI_V2 0x80000004 nkeynes@1: #define CDI_V3 0x80000005 nkeynes@1: nkeynes@543: gboolean file_load_elf_fd( const gchar *filename, int fd ); nkeynes@427: nkeynes@427: nkeynes@26: gboolean file_load_magic( const gchar *filename ) nkeynes@1: { nkeynes@1: char buf[32]; nkeynes@1: struct stat st; nkeynes@446: gboolean result = TRUE; nkeynes@1: nkeynes@1: int fd = open( filename, O_RDONLY ); nkeynes@1: if( fd == -1 ) { nkeynes@26: return FALSE; nkeynes@1: } nkeynes@88: nkeynes@1: fstat( fd, &st ); nkeynes@1: nkeynes@1: /* begin magic */ nkeynes@1: if( read( fd, buf, 32 ) != 32 ) { nkeynes@1: ERROR( "Unable to read from file '%s'", filename ); nkeynes@1: close(fd); nkeynes@26: return FALSE; nkeynes@1: } nkeynes@26: if( memcmp( buf, bootstrap_magic, 32 ) == 0 ) { nkeynes@1: /* we have a DC bootstrap */ nkeynes@1: if( st.st_size == BOOTSTRAP_SIZE ) { nkeynes@502: sh4ptr_t load = mem_get_region( BOOTSTRAP_LOAD_ADDR ); nkeynes@1: lseek( fd, 0, SEEK_SET ); nkeynes@1: read( fd, load, BOOTSTRAP_SIZE ); nkeynes@171: bootstrap_dump( load, TRUE ); nkeynes@543: dreamcast_program_loaded( filename, BOOTSTRAP_LOAD_ADDR + 0x300 ); nkeynes@1: } else { nkeynes@1: /* look for a valid ISO9660 header */ nkeynes@1: lseek( fd, 32768, SEEK_SET ); nkeynes@1: read( fd, buf, 8 ); nkeynes@1: if( memcmp( buf, iso_magic, 6 ) == 0 ) { nkeynes@1: /* Alright, got it */ nkeynes@1: INFO( "Loading ISO9660 filesystem from '%s'", nkeynes@1: filename ); nkeynes@1: } nkeynes@1: } nkeynes@26: } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) { nkeynes@26: /* ZIP file, aka SBI file */ nkeynes@26: WARN( "SBI files not supported yet" ); nkeynes@446: result = FALSE; nkeynes@294: } else if( memcmp( buf, DREAMCAST_SAVE_MAGIC, 16 ) == 0 ) { nkeynes@294: /* Save state */ nkeynes@446: result = (dreamcast_load_state( filename )==0); nkeynes@105: } else if( buf[0] == 0x7F && buf[1] == 'E' && nkeynes@105: buf[2] == 'L' && buf[3] == 'F' ) { nkeynes@88: /* ELF binary */ nkeynes@105: lseek( fd, 0, SEEK_SET ); nkeynes@543: result = file_load_elf_fd( filename, fd ); nkeynes@1: } else { nkeynes@446: result = FALSE; nkeynes@446: } nkeynes@1: close(fd); nkeynes@446: return result; nkeynes@1: } nkeynes@19: nkeynes@543: void file_load_postload( const gchar *filename, int pc ) nkeynes@110: { nkeynes@450: const gchar *bootstrap_file = lxdream_get_config_value(CONFIG_BOOTSTRAP); nkeynes@88: if( bootstrap_file != NULL ) { nkeynes@88: /* Load in a bootstrap before the binary, to initialize everything nkeynes@88: * correctly nkeynes@88: */ nkeynes@543: if( mem_load_block( bootstrap_file, BOOTSTRAP_LOAD_ADDR, BOOTSTRAP_SIZE ) == 0 ) { nkeynes@543: dreamcast_program_loaded( filename, BOOTSTRAP_LOAD_ADDR+0x300 ); nkeynes@543: return; nkeynes@180: } nkeynes@88: } nkeynes@543: dreamcast_program_loaded( filename, pc ); nkeynes@110: } nkeynes@110: nkeynes@110: nkeynes@427: gboolean file_load_binary( const gchar *filename ) nkeynes@110: { nkeynes@110: /* Load the binary itself */ nkeynes@427: if( mem_load_block( filename, BINARY_LOAD_ADDR, -1 ) == 0 ) { nkeynes@543: file_load_postload( filename, BINARY_LOAD_ADDR ); nkeynes@427: return TRUE; nkeynes@427: } else { nkeynes@427: return FALSE; nkeynes@427: } nkeynes@19: } nkeynes@105: nkeynes@543: gboolean file_load_elf_fd( const gchar *filename, int fd ) nkeynes@105: { nkeynes@105: Elf32_Ehdr head; nkeynes@105: Elf32_Phdr phdr; nkeynes@105: int i; nkeynes@105: nkeynes@105: if( read( fd, &head, sizeof(head) ) != sizeof(head) ) nkeynes@446: return FALSE; nkeynes@105: if( head.e_ident[EI_CLASS] != ELFCLASS32 || nkeynes@105: head.e_ident[EI_DATA] != ELFDATA2LSB || nkeynes@105: head.e_ident[EI_VERSION] != 1 || nkeynes@105: head.e_type != ET_EXEC || nkeynes@105: head.e_machine != EM_SH || nkeynes@105: head.e_version != 1 ) { nkeynes@105: ERROR( "File is not an SH4 ELF executable file" ); nkeynes@446: return FALSE; nkeynes@105: } nkeynes@105: nkeynes@105: /* Program headers */ nkeynes@105: for( i=0; i phdr.p_filesz ) { nkeynes@105: memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz ); nkeynes@105: } nkeynes@105: INFO( "Loaded %d bytes to %08X", phdr.p_filesz, phdr.p_vaddr ); nkeynes@105: } nkeynes@105: } nkeynes@110: nkeynes@543: file_load_postload( filename, head.e_entry ); nkeynes@446: return TRUE; nkeynes@105: }