filename | src/loader.c |
changeset | 537:d924be49e192 |
prev | 502:c4ecae2b1b5e |
next | 543:361ec0a70cf2 |
author | nkeynes |
date | Tue Nov 20 10:27:58 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Move gtk UI into gtkui subdir (prep for non-gtk builds), and protect with an automake conditional |
view | annotate | diff | log | raw |
1 /**
2 * $Id: loader.c,v 1.22 2007-11-08 11:54:16 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 <unistd.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <errno.h>
25 #include <stdint.h>
26 #include <elf.h>
27 #include "mem.h"
28 #include "sh4core.h"
29 #include "bootstrap.h"
30 #include "dreamcast.h"
31 #include "config.h"
32 #include "loader.h"
33 #include "syscall.h"
34 #include "gui.h"
36 char bootstrap_magic[32] = "SEGA SEGAKATANA SEGA ENTERPRISES";
37 char iso_magic[6] = "\001CD001";
38 char *file_loader_extensions[][2] = {
39 { "sbi", "Self Boot Inducer" },
40 { "bin", "SH4 Bin file" },
41 { NULL, NULL } };
43 #define BOOTSTRAP_LOAD_ADDR 0x8C008000
44 #define BOOTSTRAP_SIZE 32768
46 #define BINARY_LOAD_ADDR 0x8C010000
48 #define CDI_V2 0x80000004
49 #define CDI_V3 0x80000005
51 gboolean file_load_elf_fd( int fd );
54 gboolean file_load_magic( const gchar *filename )
55 {
56 char buf[32];
57 struct stat st;
58 gboolean result = TRUE;
60 int fd = open( filename, O_RDONLY );
61 if( fd == -1 ) {
62 return FALSE;
63 }
65 fstat( fd, &st );
67 /* begin magic */
68 if( read( fd, buf, 32 ) != 32 ) {
69 ERROR( "Unable to read from file '%s'", filename );
70 close(fd);
71 return FALSE;
72 }
73 if( memcmp( buf, bootstrap_magic, 32 ) == 0 ) {
74 /* we have a DC bootstrap */
75 if( st.st_size == BOOTSTRAP_SIZE ) {
76 sh4ptr_t load = mem_get_region( BOOTSTRAP_LOAD_ADDR );
77 lseek( fd, 0, SEEK_SET );
78 read( fd, load, BOOTSTRAP_SIZE );
79 bootstrap_dump( load, TRUE );
80 sh4_set_pc( BOOTSTRAP_LOAD_ADDR + 0x300 );
81 gui_update_state();
82 } else {
83 /* look for a valid ISO9660 header */
84 lseek( fd, 32768, SEEK_SET );
85 read( fd, buf, 8 );
86 if( memcmp( buf, iso_magic, 6 ) == 0 ) {
87 /* Alright, got it */
88 INFO( "Loading ISO9660 filesystem from '%s'",
89 filename );
90 }
91 }
92 } else if( memcmp( buf, "PK\x03\x04", 4 ) == 0 ) {
93 /* ZIP file, aka SBI file */
94 WARN( "SBI files not supported yet" );
95 result = FALSE;
96 } else if( memcmp( buf, DREAMCAST_SAVE_MAGIC, 16 ) == 0 ) {
97 /* Save state */
98 result = (dreamcast_load_state( filename )==0);
99 } else if( buf[0] == 0x7F && buf[1] == 'E' &&
100 buf[2] == 'L' && buf[3] == 'F' ) {
101 /* ELF binary */
102 lseek( fd, 0, SEEK_SET );
103 result = file_load_elf_fd( fd );
104 } else {
105 result = FALSE;
106 }
107 close(fd);
108 return result;
109 }
111 void file_load_postload( int pc )
112 {
113 const gchar *bootstrap_file = lxdream_get_config_value(CONFIG_BOOTSTRAP);
114 if( bootstrap_file != NULL ) {
115 /* Load in a bootstrap before the binary, to initialize everything
116 * correctly
117 */
118 if( mem_load_block( bootstrap_file, BOOTSTRAP_LOAD_ADDR, BOOTSTRAP_SIZE ) != 0 ) {
119 /* Try it without the bootstrap */
120 sh4_set_pc( pc );
121 } else {
122 sh4_set_pc( BOOTSTRAP_LOAD_ADDR + 0x300 );
123 }
124 } else {
125 sh4_set_pc( pc );
126 }
127 bios_install();
128 dcload_install();
129 gui_update_state();
130 }
133 gboolean file_load_binary( const gchar *filename )
134 {
135 /* Load the binary itself */
136 if( mem_load_block( filename, BINARY_LOAD_ADDR, -1 ) == 0 ) {
137 file_load_postload( BINARY_LOAD_ADDR );
138 return TRUE;
139 } else {
140 return FALSE;
141 }
142 }
144 gboolean file_load_elf_fd( int fd )
145 {
146 Elf32_Ehdr head;
147 Elf32_Phdr phdr;
148 int i;
150 if( read( fd, &head, sizeof(head) ) != sizeof(head) )
151 return FALSE;
152 if( head.e_ident[EI_CLASS] != ELFCLASS32 ||
153 head.e_ident[EI_DATA] != ELFDATA2LSB ||
154 head.e_ident[EI_VERSION] != 1 ||
155 head.e_type != ET_EXEC ||
156 head.e_machine != EM_SH ||
157 head.e_version != 1 ) {
158 ERROR( "File is not an SH4 ELF executable file" );
159 return FALSE;
160 }
162 /* Program headers */
163 for( i=0; i<head.e_phnum; i++ ) {
164 lseek( fd, head.e_phoff + i*head.e_phentsize, SEEK_SET );
165 read( fd, &phdr, sizeof(phdr) );
166 if( phdr.p_type == PT_LOAD ) {
167 lseek( fd, phdr.p_offset, SEEK_SET );
168 sh4ptr_t target = mem_get_region( phdr.p_vaddr );
169 read( fd, target, phdr.p_filesz );
170 if( phdr.p_memsz > phdr.p_filesz ) {
171 memset( target + phdr.p_filesz, 0, phdr.p_memsz - phdr.p_filesz );
172 }
173 INFO( "Loaded %d bytes to %08X", phdr.p_filesz, phdr.p_vaddr );
174 }
175 }
177 file_load_postload( head.e_entry );
178 return TRUE;
179 }
.