filename | src/loader.c |
changeset | 110:83a33da5ed06 |
prev | 105:1faa0745f200 |
next | 171:3542185a8cf9 |
author | nkeynes |
date | Thu Jun 15 10:25:45 2006 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add P4 I/O tracing Add ability to set I/O trace by region address |
view | annotate | diff | log | raw |
1 /**
2 * $Id: loader.c,v 1.12 2006-03-15 13:17:40 nkeynes Exp $
3 *
4 * File loading routines, mostly for loading demos without going through the
5 * whole procedure of making a CD image for them.
6 *
7 * Copyright (c) 2005 Nathan Keynes.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <errno.h>
24 #include <stdint.h>
25 #include <elf.h>
26 #include "gui/gui.h"
27 #include "mem.h"
28 #include "sh4core.h"
29 #include "bootstrap.h"
31 char *bootstrap_file = DEFAULT_BOOTSTRAP_FILE;
32 char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES";
33 char iso_magic[6] = "\001CD001";
34 char *file_loader_extensions[][2] = {
35 { "sbi", "Self Boot Inducer" },
36 { "bin", "SH4 Bin file" },
37 { NULL, NULL } };
39 #define BOOTSTRAP_LOAD_ADDR 0x8C008000
40 #define BOOTSTRAP_SIZE 32768
42 #define BINARY_LOAD_ADDR 0x8C010000
44 #define CDI_V2 0x80000004
45 #define CDI_V3 0x80000005
47 gboolean file_load_magic( const gchar *filename )
48 {
49 char buf[32];
50 uint32_t tmpa[2];
51 struct stat st;
53 int fd = open( filename, O_RDONLY );
54 if( fd == -1 ) {
55 ERROR( "Unable to open file: '%s' (%s)", filename,
56 strerror(errno) );
57 return FALSE;
58 }
60 fstat( fd, &st );
61 /*
62 if( st.st_size < 32768 ) {
63 ERROR( "File '%s' too small to be a dreamcast image", filename );
64 close(fd);
65 return FALSE;
66 }
67 */
69 /* begin magic */
70 if( read( fd, buf, 32 ) != 32 ) {
71 ERROR( "Unable to read from file '%s'", filename );
72 close(fd);
73 return FALSE;
74 }
75 if( memcmp( buf, bootstrap_magic, 32 ) == 0 ) {
76 /* we have a DC bootstrap */
77 if( st.st_size == BOOTSTRAP_SIZE ) {
78 char *load = mem_get_region( BOOTSTRAP_LOAD_ADDR );
79 lseek( fd, 0, SEEK_SET );
80 read( fd, load, BOOTSTRAP_SIZE );
81 bootstrap_dump( load );
82 sh4_set_pc( BOOTSTRAP_LOAD_ADDR + 0x300 );
83 gtk_gui_update();
84 } else {
85 /* look for a valid ISO9660 header */
86 lseek( fd, 32768, SEEK_SET );
87 read( fd, buf, 8 );
88 if( memcmp( buf, iso_magic, 6 ) == 0 ) {
89 /* Alright, got it */
90 INFO( "Loading ISO9660 filesystem from '%s'",
91 filename );
92 }
93 }
94 } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) {
95 /* ZIP file, aka SBI file */
96 WARN( "SBI files not supported yet" );
97 } else if( buf[0] == 0x7F && buf[1] == 'E' &&
98 buf[2] == 'L' && buf[3] == 'F' ) {
99 /* ELF binary */
100 lseek( fd, 0, SEEK_SET );
101 file_load_elf_fd( fd );
102 } else {
103 /* Assume raw binary */
104 file_load_binary( filename );
105 }
106 close(fd);
107 return TRUE;
108 }
110 int file_load_postload( int pc )
111 {
112 if( bootstrap_file != NULL ) {
113 /* Load in a bootstrap before the binary, to initialize everything
114 * correctly
115 */
116 mem_load_block( bootstrap_file, BOOTSTRAP_LOAD_ADDR, BOOTSTRAP_SIZE );
117 sh4_set_pc( BOOTSTRAP_LOAD_ADDR + 0x300 );
118 } else {
119 sh4_set_pc( pc );
120 }
121 bios_install();
122 dcload_install();
123 gtk_gui_update();
124 }
127 int file_load_binary( const gchar *filename )
128 {
129 /* Load the binary itself */
130 mem_load_block( filename, BINARY_LOAD_ADDR, -1 );
131 file_load_postload( BINARY_LOAD_ADDR );
132 }
134 int file_load_elf_fd( int fd )
135 {
136 Elf32_Ehdr head;
137 Elf32_Phdr phdr;
138 int i;
140 if( read( fd, &head, sizeof(head) ) != sizeof(head) )
141 return -1;
142 if( head.e_ident[EI_CLASS] != ELFCLASS32 ||
143 head.e_ident[EI_DATA] != ELFDATA2LSB ||
144 head.e_ident[EI_VERSION] != 1 ||
145 head.e_type != ET_EXEC ||
146 head.e_machine != EM_SH ||
147 head.e_version != 1 ) {
148 ERROR( "File is not an SH4 ELF executable file" );
149 return -1;
150 }
152 /* Program headers */
153 for( i=0; i<head.e_phnum; i++ ) {
154 lseek( fd, head.e_phoff + i*head.e_phentsize, SEEK_SET );
155 read( fd, &phdr, sizeof(phdr) );
156 if( phdr.p_type == PT_LOAD ) {
157 lseek( fd, phdr.p_offset, SEEK_SET );
158 char *target = mem_get_region( phdr.p_vaddr );
159 read( fd, target, phdr.p_filesz );
160 if( phdr.p_memsz > phdr.p_filesz ) {
161 memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz );
162 }
163 INFO( "Loaded %d bytes to %08X", phdr.p_filesz, phdr.p_vaddr );
164 }
165 }
167 file_load_postload( head.e_entry );
168 }
.