/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (hide annotations)
Mon Oct 8 16:21:34 2007 UTC (13 years, 3 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 dpavlin 36 /*
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