/[gxemul]/trunk/src/disk/bootblock.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/disk/bootblock.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 9557 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


1 /*
2 * Copyright (C) 2003-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: bootblock.c,v 1.1 2007/03/16 14:45:30 debug Exp $
29 *
30 * Bootblock handling:
31 *
32 * o) For some machines (e.g. DECstation or the Dreamcast), it is
33 * possible to load a bootblock from a fixed location on disk, and
34 * simply execute it in memory.
35 *
36 * o) For booting from generic CDROM ISO9660 images, a filename of
37 * a file to load must be supplied (the kernel filename). It is
38 * loaded, possibly gunzipped, and then executed as if it was a
39 * separate file.
40 *
41 * TODO: This module needs some cleanup.
42 */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include "cpu.h"
49 #include "diskimage.h"
50 #include "emul.h"
51 #include "machine.h"
52 #include "misc.h"
53
54 static char *diskimage_types[] = DISKIMAGE_TYPES;
55
56
57 /*
58 * load_bootblock():
59 *
60 * For some emulation modes, it is possible to boot from a harddisk image by
61 * loading a bootblock from a specific disk offset into memory, and executing
62 * that, instead of requiring a separate kernel file. It is then up to the
63 * bootblock to load a kernel.
64 *
65 * Returns 1 on success, 0 on failure.
66 */
67 int load_bootblock(struct machine *m, struct cpu *cpu,
68 int *n_loadp, char ***load_namesp)
69 {
70 int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs,
71 iso_type, retval = 0;
72 unsigned char minibuf[0x20];
73 unsigned char *bootblock_buf;
74 uint64_t bootblock_offset, base_offset;
75 uint64_t bootblock_loadaddr, bootblock_pc;
76
77 boot_disk_id = diskimage_bootdev(m, &boot_disk_type);
78 if (boot_disk_id < 0)
79 return 0;
80
81 base_offset = diskimage_get_baseoffset(m, boot_disk_id, boot_disk_type);
82
83 switch (m->machine_type) {
84
85 case MACHINE_DREAMCAST:
86 if (!diskimage_is_a_cdrom(cpu->machine, boot_disk_id,
87 boot_disk_type)) {
88 fatal("The Dreamcast emulation mode can only boot"
89 " from CD images, not from other disk types.\n");
90 exit(1);
91 }
92
93 bootblock_buf = malloc(32768);
94 if (bootblock_buf == NULL) {
95 fprintf(stderr, "Out of memory.\n");
96 exit(1);
97 }
98
99 debug("loading Dreamcast IP.BIN from %s id %i\n",
100 diskimage_types[boot_disk_type], boot_disk_id);
101
102 res = diskimage_access(m, boot_disk_id, boot_disk_type,
103 0, base_offset, bootblock_buf, 0x8000);
104 if (!res) {
105 fatal("Couldn't read the disk image. Aborting.\n");
106 return 0;
107 }
108
109 if (strncmp((char *)bootblock_buf, "SEGA ", 5) != 0) {
110 fatal("This is not a Dreamcast IP.BIN header.\n");
111 free(bootblock_buf);
112 return 0;
113 }
114
115 /* Store IP.BIN at 0x8c008000, and set entry point. */
116 store_buf(cpu, 0x8c008000, (char *)bootblock_buf, 32768);
117 cpu->pc = 0x8c008300;
118
119 /* Remember the name of the file to boot (1ST_READ.BIN): */
120 if (cpu->machine->boot_kernel_filename == NULL ||
121 cpu->machine->boot_kernel_filename[0] == '\0') {
122 int i = 0x60;
123 while (i < 0x70) {
124 if (bootblock_buf[i] == ' ')
125 bootblock_buf[i] = 0;
126 i ++;
127 }
128 cpu->machine->boot_kernel_filename = strdup(
129 (char *)bootblock_buf + 0x60);
130 }
131
132 debug("boot filename: %s\n",
133 cpu->machine->boot_kernel_filename);
134
135 free(bootblock_buf);
136
137 break;
138
139 case MACHINE_PMAX:
140 /*
141 * The first few bytes of a disk contains information about
142 * where the bootblock(s) are located. (These are all 32-bit
143 * little-endian words.)
144 *
145 * Offset 0x10 = load address
146 * 0x14 = initial PC value
147 * 0x18 = nr of 512-byte blocks to read
148 * 0x1c = offset on disk to where the bootblocks
149 * are (in 512-byte units)
150 * 0x20 = nr of blocks to read...
151 * 0x24 = offset...
152 *
153 * nr of blocks to read and offset are repeated until nr of
154 * blocks to read is zero.
155 */
156 res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0,
157 minibuf, sizeof(minibuf));
158
159 bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)
160 + (minibuf[0x12] << 16) + ((uint64_t)minibuf[0x13] << 24);
161
162 /* Convert loadaddr to uncached: */
163 if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&
164 (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000) {
165 fatal("\nWARNING! Weird load address 0x%08"PRIx32
166 " for SCSI id %i.\n\n",
167 (uint32_t)bootblock_loadaddr, boot_disk_id);
168 if (bootblock_loadaddr == 0) {
169 fatal("I'm assuming that this is _not_ a "
170 "DEC bootblock.\nAre you sure you are"
171 " booting from the correct disk?\n");
172 exit(1);
173 }
174 }
175
176 bootblock_loadaddr &= 0x0fffffffULL;
177 bootblock_loadaddr |= 0xffffffffa0000000ULL;
178
179 bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)
180 + (minibuf[0x16] << 16) + ((uint64_t)minibuf[0x17] << 24);
181
182 bootblock_pc &= 0x0fffffffULL;
183 bootblock_pc |= 0xffffffffa0000000ULL;
184 cpu->pc = bootblock_pc;
185
186 debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",
187 (int)bootblock_loadaddr, (int)bootblock_pc);
188
189 readofs = 0x18;
190
191 for (;;) {
192 res = diskimage_access(m, boot_disk_id, boot_disk_type,
193 0, readofs, minibuf, sizeof(minibuf));
194 if (!res) {
195 fatal("Couldn't read the disk image. "
196 "Aborting.\n");
197 return 0;
198 }
199
200 n_blocks = minibuf[0] + (minibuf[1] << 8)
201 + (minibuf[2] << 16) + ((uint64_t)minibuf[3] << 24);
202
203 bootblock_offset = (minibuf[4] + (minibuf[5] << 8) +
204 (minibuf[6]<<16) + ((uint64_t)minibuf[7]<<24)) * 512;
205
206 if (n_blocks < 1)
207 break;
208
209 debug(readofs == 0x18? ": %i" : " + %i", n_blocks);
210
211 if (n_blocks * 512 > 65536)
212 fatal("\nWARNING! Unusually large bootblock "
213 "(%i bytes)\n\n", n_blocks * 512);
214
215 bootblock_buf = malloc(n_blocks * 512);
216 if (bootblock_buf == NULL) {
217 fprintf(stderr, "out of memory in "
218 "load_bootblock()\n");
219 exit(1);
220 }
221
222 res = diskimage_access(m, boot_disk_id, boot_disk_type,
223 0, bootblock_offset, bootblock_buf, n_blocks * 512);
224 if (!res) {
225 fatal("WARNING: could not load bootblocks from"
226 " disk offset 0x%llx\n",
227 (long long)bootblock_offset);
228 }
229
230 store_buf(cpu, bootblock_loadaddr,
231 (char *)bootblock_buf, n_blocks * 512);
232
233 bootblock_loadaddr += 512*n_blocks;
234 free(bootblock_buf);
235 readofs += 8;
236 }
237
238 debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");
239 return 1;
240 }
241
242
243 /*
244 * Try reading a kernel manually from the disk. The code here
245 * does not rely on machine-dependent boot blocks etc.
246 */
247 /* ISO9660: (0x800 bytes at 0x8000 + base_offset) */
248 bootblock_buf = malloc(0x800);
249 if (bootblock_buf == NULL) {
250 fprintf(stderr, "Out of memory.\n");
251 exit(1);
252 }
253
254 res = diskimage_access(m, boot_disk_id, boot_disk_type,
255 0, base_offset + 0x8000, bootblock_buf, 0x800);
256 if (!res) {
257 fatal("Couldn't read the disk image. Aborting.\n");
258 return 0;
259 }
260
261 iso_type = 0;
262 if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0)
263 iso_type = 1;
264 if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0)
265 iso_type = 2;
266 if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0)
267 iso_type = 3;
268
269 if (iso_type != 0) {
270 /*
271 * If the user specified a kernel name, then load it from
272 * disk.
273 */
274 if (cpu->machine->boot_kernel_filename == NULL ||
275 cpu->machine->boot_kernel_filename[0] == '\0')
276 fatal("\nISO9660 filesystem, but no kernel "
277 "specified? (Use the -j option.)\n");
278 else
279 retval = iso_load_bootblock(m, cpu, boot_disk_id,
280 boot_disk_type, iso_type, bootblock_buf,
281 n_loadp, load_namesp);
282 }
283
284 if (retval != 0)
285 goto ret_ok;
286
287 /* Apple parition table: */
288 res = diskimage_access(m, boot_disk_id, boot_disk_type,
289 0, 0x0, bootblock_buf, 0x800);
290 if (!res) {
291 fatal("Couldn't read the disk image. Aborting.\n");
292 return 0;
293 }
294 if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' &&
295 bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') {
296 if (cpu->machine->boot_kernel_filename == NULL ||
297 cpu->machine->boot_kernel_filename[0] == '\0')
298 fatal("\nApple partition table, but no kernel "
299 "specified? (Use the -j option.)\n");
300 else
301 retval = apple_load_bootblock(m, cpu, boot_disk_id,
302 boot_disk_type, n_loadp, load_namesp);
303 }
304
305 ret_ok:
306 free(bootblock_buf);
307 return retval;
308 }
309
310

  ViewVC Help
Powered by ViewVC 1.1.26