/[gxemul]/trunk/src/promemul/of.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/promemul/of.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 30778 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 34 * $Id: of.c,v 1.22 2007/02/16 17:17:51 debug Exp $
29 dpavlin 14 *
30     * OpenFirmware emulation.
31     *
32 dpavlin 22 * NOTE: OpenFirmware is used on quite a variety of different hardware archs,
33     * at least POWER/PowerPC, ARM, and SPARC, so the code in this module
34     * must always remain architecture agnostic.
35     *
36     * NOTE: Some things, e.g. 32-bit integers as returned by the "getprop"
37     * service, are always fixed to big-endian. (According to the standard.)
38     *
39     * TODO: o) 64-bit OpenFirmware?
40     * o) More devices...
41 dpavlin 14 */
42    
43     #include <stdio.h>
44     #include <stdlib.h>
45     #include <string.h>
46     #include <sys/types.h>
47    
48 dpavlin 22 #define OF_C
49    
50 dpavlin 14 #include "console.h"
51     #include "cpu.h"
52 dpavlin 22 #include "device.h"
53     #include "devices.h"
54     #include "diskimage.h"
55 dpavlin 14 #include "machine.h"
56     #include "memory.h"
57     #include "misc.h"
58 dpavlin 22 #include "of.h"
59 dpavlin 14
60    
61 dpavlin 22 /* #define debug fatal */
62 dpavlin 14
63     extern int quiet_mode;
64 dpavlin 22 extern int verbose;
65 dpavlin 14
66    
67     /*
68     * readstr():
69     *
70     * Helper function to read a string from emulated memory.
71     */
72     static void readstr(struct cpu *cpu, uint64_t addr, char *strbuf,
73     int bufsize)
74     {
75     int i;
76     for (i=0; i<bufsize; i++) {
77     unsigned char ch;
78     cpu->memory_rw(cpu, cpu->mem, addr + i,
79     &ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
80     strbuf[i] = '\0';
81     if (ch >= 1 && ch < 32)
82     ch = 0;
83     strbuf[i] = ch;
84     if (strbuf[i] == '\0')
85     break;
86     }
87    
88     strbuf[bufsize - 1] = '\0';
89     }
90    
91    
92     /*
93 dpavlin 22 * of_store_32bit_in_host():
94     *
95     * Store big-endian. OpenFirmware properties returned by getprop etc are
96     * always big-endian, even on little-endian machines.
97     */
98     static void of_store_32bit_in_host(unsigned char *d, uint32_t x)
99     {
100     d[0] = x >> 24; d[1] = x >> 16;
101     d[2] = x >> 8; d[3] = x;
102     }
103    
104    
105     /*
106     * find_device_handle():
107     *
108     * name may consist of multiple names, separaed with slashes.
109     */
110     static int find_device_handle(struct of_data *ofd, char *name)
111     {
112     int handle = 1, cur_parent = 1;
113    
114     if (name[0] == 0)
115     return 0;
116    
117     for (;;) {
118     struct of_device *od = ofd->of_devices;
119     char tmp[200];
120     int i;
121    
122     while (name[0] == '/')
123     name++;
124     if (name[0] == '\0')
125     break;
126     snprintf(tmp, sizeof(tmp), "%s", name);
127     i = 0;
128     while (tmp[i] != '\0' && tmp[i] != '/')
129     i++;
130     tmp[i] = '\0';
131    
132     OF_FIND(od, strcmp(od->name, tmp) == 0 &&
133     od->parent == cur_parent);
134     if (od == NULL)
135     return -1;
136    
137     handle = cur_parent = od->handle;
138     name += strlen(tmp);
139     }
140    
141     return handle;
142     }
143    
144    
145     /*****************************************************************************/
146    
147    
148     OF_SERVICE(call_method_2_2)
149     {
150     fatal("[ of: call_method_2_2('%s'): TODO ]\n", arg[0]);
151     return -1;
152     }
153    
154    
155     OF_SERVICE(call_method_3_4)
156     {
157     fatal("[ of: call_method_3_4('%s'): TODO ]\n", arg[0]);
158     return -1;
159     }
160    
161    
162     OF_SERVICE(call_method_5_2)
163     {
164     if (strcmp(arg[0], "set-colors") == 0) {
165     /* Used by OpenBSD/macppc: */
166 dpavlin 34 struct vfb_data *v = cpu->machine->md.of_data->vfb_data;
167 dpavlin 22 int color = OF_GET_ARG(3);
168     uint64_t ptr = OF_GET_ARG(4);
169     unsigned char rgb[3];
170     cpu->memory_rw(cpu, cpu->mem, ptr, rgb, 3, MEM_READ,
171     CACHE_DATA | NO_EXCEPTIONS);
172     if (v != NULL) {
173     memcpy(v->rgb_palette + 3 * color, rgb, 3);
174     v->update_x1 = v->update_y1 = 0;
175     v->update_x2 = v->xsize - 1;
176     v->update_y2 = v->ysize - 1;
177     }
178     } else {
179     fatal("[ of: call_method_5_2('%s'): TODO ]\n", arg[0]);
180     return -1;
181     }
182     return 0;
183     }
184    
185    
186     OF_SERVICE(call_method_6_1)
187     {
188     fatal("[ of: call_method_6_1('%s'): TODO ]\n", arg[0]);
189     return -1;
190     }
191    
192    
193     OF_SERVICE(call_method_6_2)
194     {
195     fatal("[ of: call_method_6_2('%s'): TODO ]\n", arg[0]);
196     return -1;
197     }
198    
199    
200     OF_SERVICE(child)
201     {
202 dpavlin 34 struct of_device *od = cpu->machine->md.of_data->of_devices;
203 dpavlin 22 int handle = OF_GET_ARG(0);
204     OF_FIND(od, od->parent == handle);
205     store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->handle);
206     return 0;
207     }
208    
209    
210     OF_SERVICE(exit)
211     {
212     cpu->running = 0;
213     return 0;
214     }
215    
216    
217     OF_SERVICE(finddevice)
218     {
219 dpavlin 34 int h = find_device_handle(cpu->machine->md.of_data, arg[0]);
220 dpavlin 22 store_32bit_word(cpu, base + retofs, h);
221     return h>0? 0 : -1;
222     }
223    
224    
225     OF_SERVICE(getprop)
226     {
227 dpavlin 34 struct of_device *od = cpu->machine->md.of_data->of_devices;
228 dpavlin 22 struct of_device_property *pr;
229     int handle = OF_GET_ARG(0), i, len_returned = 0;
230     uint64_t buf = OF_GET_ARG(2);
231     uint64_t max = OF_GET_ARG(3);
232    
233     OF_FIND(od, od->handle == handle);
234     if (od == NULL) {
235     fatal("[ of: WARNING: getprop handle=%i; no such handle ]\n",
236     handle);
237     return -1;
238     }
239    
240     pr = od->properties;
241     OF_FIND(pr, strcmp(pr->name, arg[1]) == 0);
242     if (pr == NULL) {
243     fatal("[ of: WARNING: getprop: no property '%s' at handle"
244     " %i (device '%s') ]\n", arg[1], handle, od->name);
245     /* exit(1); */
246     return -1;
247     }
248    
249     if (pr->data == NULL) {
250     fatal("[ of: WARNING: property '%s' of '%s' has no data! ]\n",
251     arg[1], od->name);
252     goto ret;
253     }
254    
255     /* Return the property into emulated RAM: */
256     len_returned = pr->len <= max? pr->len : max;
257    
258     for (i=0; i<len_returned; i++) {
259     if (!cpu->memory_rw(cpu, cpu->mem, buf + i, pr->data + i,
260     1, MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS)) {
261     fatal("[ of: getprop memory_rw() error ]\n");
262     exit(1);
263     }
264     }
265    
266     ret:
267     store_32bit_word(cpu, base + retofs, len_returned);
268     return 0;
269     }
270    
271    
272     OF_SERVICE(getproplen)
273     {
274 dpavlin 34 struct of_device *od = cpu->machine->md.of_data->of_devices;
275 dpavlin 22 struct of_device_property *pr;
276     int handle = OF_GET_ARG(0);
277    
278     OF_FIND(od, od->handle == handle);
279     if (od == NULL) {
280     fatal("[ of: WARNING: getproplen handle=%i; no such handle ]\n",
281     handle);
282     exit(1);
283     /* return -1; */
284     }
285    
286     pr = od->properties;
287     OF_FIND(pr, strcmp(pr->name, arg[1]) == 0);
288     if (pr == NULL) {
289     fatal("[ of: WARNING: getproplen: no property '%s' at handle"
290     " %i (device '%s') ]\n", arg[1], handle, od->name);
291     exit(1);
292     }
293    
294     store_32bit_word(cpu, base + retofs, pr->len);
295     return 0;
296     }
297    
298    
299     OF_SERVICE(instance_to_package)
300     {
301     int handle = OF_GET_ARG(0);
302     /* TODO: actually do something here? :-) */
303     store_32bit_word(cpu, base + retofs, handle);
304     return 0;
305     }
306    
307    
308     OF_SERVICE(interpret_1)
309     {
310     if (strcmp(arg[0], "#lines 2 - to line#") == 0) {
311     } else {
312     fatal("[ of: interpret_1('%s'): TODO ]\n", arg[0]);
313     return -1;
314     }
315     return 0;
316     }
317    
318    
319     OF_SERVICE(interpret_2)
320     {
321     store_32bit_word(cpu, base + retofs, 0); /* ? TODO */
322     if (strcmp(arg[0], "#columns") == 0) {
323     store_32bit_word(cpu, base + retofs + 4, 80);
324     } else if (strcmp(arg[0], "#lines") == 0) {
325     store_32bit_word(cpu, base + retofs + 4, 40);
326     } else if (strcmp(arg[0], "char-height") == 0) {
327     store_32bit_word(cpu, base + retofs + 4, 15);
328     } else if (strcmp(arg[0], "char-width") == 0) {
329     store_32bit_word(cpu, base + retofs + 4, 10);
330     } else if (strcmp(arg[0], "line#") == 0) {
331     store_32bit_word(cpu, base + retofs + 4, 0);
332     } else if (strcmp(arg[0], "font-adr") == 0) {
333     store_32bit_word(cpu, base + retofs + 4, 0);
334     } else {
335     fatal("[ of: interpret_2('%s'): TODO ]\n", arg[0]);
336     return -1;
337     }
338     return 0;
339     }
340    
341    
342     OF_SERVICE(package_to_path)
343     {
344     fatal("[ of: package-to-path: TODO ]\n");
345     return -1;
346     }
347    
348    
349     OF_SERVICE(parent)
350     {
351 dpavlin 34 struct of_device *od = cpu->machine->md.of_data->of_devices;
352 dpavlin 22 int handle = OF_GET_ARG(0);
353     OF_FIND(od, od->handle == handle);
354     store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->parent);
355     return 0;
356     }
357    
358    
359     OF_SERVICE(peer)
360     {
361 dpavlin 34 struct of_device *od = cpu->machine->md.of_data->of_devices;
362 dpavlin 22 int handle = OF_GET_ARG(0), parent = 0, peer = 0, seen_self = 1;
363    
364     if (handle == 0) {
365     /* Return the handle of the root node (1): */
366     store_32bit_word(cpu, base + retofs, 1);
367     return 0;
368     }
369    
370     OF_FIND(od, od->handle == handle);
371     if (od == NULL) {
372     fatal("[ of: peer(): can't find handle %i ]\n", handle);
373     exit(1);
374     }
375     parent = od->parent;
376     seen_self = 0;
377    
378 dpavlin 34 od = cpu->machine->md.of_data->of_devices;
379 dpavlin 22
380     while (od != NULL) {
381     if (od->parent == parent) {
382     if (seen_self) {
383     peer = od->handle;
384     break;
385     }
386     if (od->handle == handle)
387     seen_self = 1;
388     }
389     od = od->next;
390     }
391     store_32bit_word(cpu, base + retofs, peer);
392     return 0;
393     }
394    
395    
396     OF_SERVICE(read)
397     {
398     /* int handle = OF_GET_ARG(0); */
399     uint64_t ptr = OF_GET_ARG(1);
400     /* int len = OF_GET_ARG(2); */
401     int c;
402     unsigned char ch;
403    
404     /* TODO: check handle! This just reads chars from the console! */
405     /* TODO: This is blocking! */
406    
407     c = console_readchar(cpu->machine->main_console_handle);
408     ch = c;
409     if (!cpu->memory_rw(cpu, cpu->mem, ptr, &ch, 1, MEM_WRITE,
410     CACHE_DATA | NO_EXCEPTIONS)) {
411     fatal("[ of: read: memory_rw() error ]\n");
412     exit(1);
413     }
414    
415     store_32bit_word(cpu, base + retofs, c == -1? 0 : 1);
416     return c == -1? -1 : 0;
417     }
418    
419    
420     OF_SERVICE(write)
421     {
422     /* int handle = OF_GET_ARG(0); */
423     uint64_t ptr = OF_GET_ARG(1);
424     int n_written = 0, i, len = OF_GET_ARG(2);
425    
426     /* TODO: check handle! This just dumps the data to the console! */
427    
428     for (i=0; i<len; i++) {
429     unsigned char ch;
430     if (!cpu->memory_rw(cpu, cpu->mem, ptr + i, &ch,
431     1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) {
432     fatal("[ of: write: memory_rw() error ]\n");
433     exit(1);
434     }
435     if (ch != 7)
436     console_putchar(cpu->machine->main_console_handle, ch);
437     n_written ++;
438     }
439    
440     store_32bit_word(cpu, base + retofs, n_written);
441     return 0;
442     }
443    
444    
445     /*****************************************************************************/
446    
447    
448     /*
449     * of_get_unused_device_handle():
450     *
451     * Returns an unused device handle number (1 or higher).
452     */
453     static int of_get_unused_device_handle(struct of_data *of_data)
454     {
455     int max_handle = 0;
456     struct of_device *od = of_data->of_devices;
457    
458     while (od != NULL) {
459     if (od->handle > max_handle)
460     max_handle = od->handle;
461     od = od->next;
462     }
463    
464     return max_handle + 1;
465     }
466    
467    
468     /*
469     * of_add_device():
470     *
471     * Adds a device.
472     */
473     static struct of_device *of_add_device(struct of_data *of_data, char *name,
474     char *parentname)
475     {
476     struct of_device *od = malloc(sizeof(struct of_device));
477     if (od == NULL)
478     goto bad;
479     memset(od, 0, sizeof(struct of_device));
480    
481     od->name = strdup(name);
482     if (od->name == NULL)
483     goto bad;
484    
485     od->handle = of_get_unused_device_handle(of_data);
486     od->parent = find_device_handle(of_data, parentname);
487     if (od->parent < 0) {
488     fatal("of_add_device(): adding '%s' to parent '%s' failed: "
489     "parent not found!\n", name, parentname);
490     exit(1);
491     }
492    
493     od->next = of_data->of_devices;
494     of_data->of_devices = od;
495     return od;
496    
497     bad:
498     fatal("of_add_device(): out of memory\n");
499     exit(1);
500     }
501    
502    
503     /*
504     * of_add_prop():
505     *
506     * Adds a property to a device.
507     */
508     static void of_add_prop(struct of_data *of_data, char *devname,
509     char *propname, unsigned char *data, uint32_t len, int flags)
510     {
511     struct of_device_property *pr =
512     malloc(sizeof(struct of_device_property));
513     struct of_device *od = of_data->of_devices;
514     int h = find_device_handle(of_data, devname);
515    
516     OF_FIND(od, od->handle == h);
517     if (od == NULL) {
518     fatal("of_add_prop(): device '%s' not registered\n", devname);
519     exit(1);
520     }
521    
522     if (pr == NULL)
523     goto bad;
524     memset(pr, 0, sizeof(struct of_device_property));
525    
526     pr->name = strdup(propname);
527     if (pr->name == NULL)
528     goto bad;
529     pr->data = data;
530     pr->len = len;
531     pr->flags = flags;
532    
533     pr->next = od->properties;
534     od->properties = pr;
535     return;
536    
537     bad:
538     fatal("of_add_device(): out of memory\n");
539     exit(1);
540     }
541    
542    
543     /*
544     * of_add_service():
545     *
546     * Adds a service.
547     */
548     static void of_add_service(struct of_data *of_data, char *name,
549     int (*f)(OF_SERVICE_ARGS), int n_args, int n_ret_args)
550     {
551     struct of_service *os = malloc(sizeof(struct of_service));
552     if (os == NULL)
553     goto bad;
554     memset(os, 0, sizeof(struct of_service));
555    
556     os->name = strdup(name);
557     if (os->name == NULL)
558     goto bad;
559    
560     os->f = f;
561     os->n_args = n_args;
562     os->n_ret_args = n_ret_args;
563    
564     os->next = of_data->of_services;
565     of_data->of_services = os;
566     return;
567    
568     bad:
569     fatal("of_add_service(): out of memory\n");
570     exit(1);
571     }
572    
573    
574     /*
575     * of_dump_devices():
576     *
577     * Debug dump helper.
578     */
579     static void of_dump_devices(struct of_data *ofd, int parent)
580     {
581     int iadd = DEBUG_INDENTATION;
582     struct of_device *od = ofd->of_devices;
583    
584     while (od != NULL) {
585     struct of_device_property *pr = od->properties;
586     if (od->parent != parent) {
587     od = od->next;
588     continue;
589     }
590     debug("\"%s\"\n", od->name, od->handle);
591     debug_indentation(iadd);
592     while (pr != NULL) {
593     debug("(%s: ", pr->name);
594     if (pr->flags == OF_PROP_STRING)
595     debug("\"%s\"", pr->data);
596     else
597     debug("%i bytes", pr->len);
598     debug(")\n");
599     pr = pr->next;
600     }
601     of_dump_devices(ofd, od->handle);
602     debug_indentation(-iadd);
603     od = od->next;
604     }
605     }
606    
607    
608     /*
609     * of_dump_all():
610     *
611     * Debug dump.
612     */
613     static void of_dump_all(struct of_data *ofd)
614     {
615     int iadd = DEBUG_INDENTATION;
616     struct of_service *os;
617    
618     debug("openfirmware debug dump:\n");
619     debug_indentation(iadd);
620    
621     /* Devices: */
622     of_dump_devices(ofd, 0);
623    
624     /* Services: */
625     os = ofd->of_services;
626     while (os != NULL) {
627     debug("service '%s'", os->name);
628     if (os->n_ret_args > 0 || os->n_args > 0) {
629     debug(" (");
630     if (os->n_args > 0) {
631     debug("%i arg%s", os->n_args,
632     os->n_args > 1? "s" : "");
633     if (os->n_ret_args > 0)
634     debug(", ");
635     }
636     if (os->n_ret_args > 0)
637     debug("%i return value%s", os->n_ret_args,
638     os->n_ret_args > 1? "s" : "");
639     debug(")");
640     }
641     debug("\n");
642     os = os->next;
643     }
644    
645     debug_indentation(-iadd);
646     }
647    
648    
649     /*
650     * of_add_prop_int32():
651     *
652     * Helper function.
653     */
654     static void of_add_prop_int32(struct of_data *ofd,
655     char *devname, char *propname, uint32_t x)
656     {
657     unsigned char *p = malloc(sizeof(int32_t));
658     if (p == NULL) {
659     fatal("of_add_prop_int32(): out of memory\n");
660     exit(1);
661     }
662     of_store_32bit_in_host(p, x);
663     of_add_prop(ofd, devname, propname, p, sizeof(int32_t),
664     OF_PROP_INT);
665     }
666    
667    
668     /*
669     * of_add_prop_str():
670     *
671     * Helper function.
672     */
673     static void of_add_prop_str(struct machine *machine, struct of_data *ofd,
674     char *devname, char *propname, char *data)
675     {
676     char *p = strdup(data);
677     if (p == NULL) {
678     fatal("of_add_prop_str(): out of memory\n");
679     exit(1);
680     }
681    
682     of_add_prop(ofd, devname, propname, (unsigned char *)p, strlen(p) + 1,
683     OF_PROP_STRING);
684     }
685    
686    
687     /*
688     * of_emul_init_isa():
689     */
690     void of_emul_init_isa(struct machine *machine)
691     {
692 dpavlin 34 struct of_data *ofd = machine->md.of_data;
693 dpavlin 22 unsigned char *isa_ranges;
694    
695     of_add_device(ofd, "isa", "/");
696     isa_ranges = malloc(32);
697     if (isa_ranges == NULL)
698     goto bad;
699     memset(isa_ranges, 0, 32);
700     /* 2 *: isa_phys_hi, isa_phys_lo, parent_phys_start, size */
701     /* MEM space: */
702     of_store_32bit_in_host(isa_ranges + 0, 0);
703     of_store_32bit_in_host(isa_ranges + 4, 0xc0000000);
704     /* I/O space: low bit if isa_phys_hi set */
705     of_store_32bit_in_host(isa_ranges + 16, 1);
706     of_store_32bit_in_host(isa_ranges + 20, 0xd0000000);
707    
708     of_add_prop(ofd, "/isa", "ranges", isa_ranges, 32, 0);
709    
710     return;
711    
712     bad:
713     fatal("of_emul_init_isa(): out of memory\n");
714     exit(1);
715     }
716    
717    
718     /*
719     * of_emul_init_adb():
720     */
721     void of_emul_init_adb(struct machine *machine)
722     {
723 dpavlin 34 struct of_data *ofd = machine->md.of_data;
724 dpavlin 22 unsigned char *adb_interrupts, *adb_reg;
725    
726     adb_interrupts = malloc(4 * sizeof(uint32_t));
727     adb_reg = malloc(8 * sizeof(uint32_t));
728     if (adb_interrupts == NULL || adb_reg == NULL)
729     goto bad;
730    
731     of_add_device(ofd, "adb", "/bandit/gc");
732     of_add_prop_str(machine, ofd, "/bandit/gc/adb", "name", "via-cuda");
733     of_store_32bit_in_host(adb_interrupts + 0, 25);
734     of_store_32bit_in_host(adb_interrupts + 4, 0);
735     of_store_32bit_in_host(adb_interrupts + 8, 0);
736     of_store_32bit_in_host(adb_interrupts + 12, 0);
737     of_add_prop(ofd, "/bandit/gc/adb", "interrupts", adb_interrupts,
738     4*sizeof(uint32_t), 0);
739     of_store_32bit_in_host(adb_reg + 0, 0x16000);
740     of_store_32bit_in_host(adb_reg + 4, 0x2000);
741     of_store_32bit_in_host(adb_reg + 8, 0);
742     of_store_32bit_in_host(adb_reg + 12, 0);
743     of_store_32bit_in_host(adb_reg + 16, 0);
744     of_store_32bit_in_host(adb_reg + 20, 0);
745     of_store_32bit_in_host(adb_reg + 24, 0);
746     of_store_32bit_in_host(adb_reg + 28, 0);
747     of_add_prop(ofd, "/bandit/gc/adb", "reg", adb_reg,
748     8*sizeof(uint32_t), 0);
749    
750     return;
751    
752     bad:
753     fatal("of_emul_init_adb(): out of memory\n");
754     exit(1);
755     }
756    
757    
758     /*
759     * of_emul_init_zs():
760     */
761     void of_emul_init_zs(struct machine *machine)
762     {
763 dpavlin 34 struct of_data *ofd = machine->md.of_data;
764 dpavlin 22 unsigned char *zs_interrupts, *zs_reg;
765    
766     zs_reg = malloc(6 * sizeof(uint32_t));
767     if (zs_reg == NULL)
768     goto bad;
769    
770     /* The controller: */
771     of_add_device(ofd, "zs", "/bandit/gc");
772     of_add_prop_str(machine, ofd, "/bandit/gc/zs", "device_type", "serial");
773     of_add_prop_str(machine, ofd, "/bandit/gc/zs", "name", "escc");
774     of_store_32bit_in_host(zs_reg + 0, 0x13000);
775     of_store_32bit_in_host(zs_reg + 4, 0x40);
776     of_store_32bit_in_host(zs_reg + 8, 0x100);
777     of_store_32bit_in_host(zs_reg + 12, 0x100);
778     of_store_32bit_in_host(zs_reg + 16, 0x200);
779     of_store_32bit_in_host(zs_reg + 20, 0x100);
780     of_add_prop(ofd, "/bandit/gc/zs", "reg", zs_reg, 6*sizeof(uint32_t), 0);
781    
782     /* Port 1: */
783     zs_interrupts = malloc(3 * sizeof(uint32_t));
784     zs_reg = malloc(6 * sizeof(uint32_t));
785     if (zs_interrupts == NULL || zs_reg == NULL)
786     goto bad;
787    
788     of_add_device(ofd, "zstty1", "/bandit/gc/zs");
789     of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty1", "name", "ch-a");
790     of_store_32bit_in_host(zs_interrupts + 0, 16);
791     of_store_32bit_in_host(zs_interrupts + 4, 0);
792     of_store_32bit_in_host(zs_interrupts + 8, 0);
793     of_add_prop(ofd, "/bandit/gc/zs/zstty1", "interrupts", zs_interrupts,
794     3*sizeof(uint32_t), 0);
795     of_store_32bit_in_host(zs_reg + 0, 0x13800);
796     of_store_32bit_in_host(zs_reg + 4, 0x100);
797     of_store_32bit_in_host(zs_reg + 8, 0x100);
798     of_store_32bit_in_host(zs_reg + 12, 0x100);
799     of_store_32bit_in_host(zs_reg + 16, 0x200);
800     of_store_32bit_in_host(zs_reg + 20, 0x100);
801     of_add_prop(ofd, "/bandit/gc/zs/zstty1",
802     "reg", zs_reg, 6*sizeof(uint32_t), 0);
803    
804     /* Port 0: */
805     zs_interrupts = malloc(3 * sizeof(uint32_t));
806     zs_reg = malloc(6 * sizeof(uint32_t));
807     if (zs_interrupts == NULL || zs_reg == NULL)
808     goto bad;
809    
810     of_add_device(ofd, "zstty0", "/bandit/gc/zs");
811     of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty0", "name", "ch-b");
812     of_store_32bit_in_host(zs_interrupts + 0, 15);
813     of_store_32bit_in_host(zs_interrupts + 4, 0);
814     of_store_32bit_in_host(zs_interrupts + 8, 0);
815     of_add_prop(ofd, "/bandit/gc/zs/zstty0", "interrupts", zs_interrupts,
816     3*sizeof(uint32_t), 0);
817     of_store_32bit_in_host(zs_reg + 0, 0x13400);
818     of_store_32bit_in_host(zs_reg + 4, 0x100);
819     of_store_32bit_in_host(zs_reg + 8, 0x100);
820     of_store_32bit_in_host(zs_reg + 12, 0x100);
821     of_store_32bit_in_host(zs_reg + 16, 0x200);
822     of_store_32bit_in_host(zs_reg + 20, 0x100);
823     of_add_prop(ofd, "/bandit/gc/zs/zstty0",
824     "reg", zs_reg, 6*sizeof(uint32_t), 0);
825    
826     return;
827    
828     bad:
829     fatal("of_emul_init_zs(): out of memory\n");
830     exit(1);
831     }
832    
833    
834     /*
835     * of_emul_init_uninorth():
836     */
837     void of_emul_init_uninorth(struct machine *machine)
838     {
839 dpavlin 34 struct of_data *ofd = machine->md.of_data;
840 dpavlin 22 unsigned char *uninorth_reg, *uninorth_bus_range, *uninorth_ranges;
841     unsigned char *macio_aa, *ata_interrupts, *ata_reg;
842     struct of_device *ic;
843     char *n = "pci@e2000000";
844     char *macio = "mac-io";
845    
846     of_add_device(ofd, n, "/");
847     of_add_prop_str(machine, ofd, n, "name", "pci");
848     of_add_prop_str(machine, ofd, n, "device_type", "pci");
849     of_add_prop_str(machine, ofd, n, "compatible", "uni-north");
850    
851     uninorth_reg = malloc(2 * sizeof(uint32_t));
852     uninorth_bus_range = malloc(2 * sizeof(uint32_t));
853     uninorth_ranges = malloc(12 * sizeof(uint32_t));
854     macio_aa = malloc(5 * sizeof(uint32_t));
855     ata_interrupts = malloc(6 * sizeof(uint32_t));
856     ata_reg = malloc(8 * sizeof(uint32_t));
857     if (uninorth_ranges == NULL || uninorth_bus_range == NULL ||
858     uninorth_reg == NULL || macio_aa == NULL ||
859     ata_interrupts == NULL || ata_reg == NULL)
860     goto bad;
861    
862     of_store_32bit_in_host(uninorth_reg + 0, 0xe2000000);
863     of_store_32bit_in_host(uninorth_reg + 4, 0); /* not used? */
864     of_add_prop(ofd, n, "reg", uninorth_reg, 2*sizeof(uint32_t), 0);
865    
866     of_store_32bit_in_host(uninorth_bus_range + 0, 0);
867     of_store_32bit_in_host(uninorth_bus_range + 4, 0);
868     of_add_prop(ofd, n, "bus-range", uninorth_bus_range,
869     2*sizeof(uint32_t), 0);
870    
871     /* MEM: */
872     of_store_32bit_in_host(uninorth_ranges + 0, 0x02000000);
873     of_store_32bit_in_host(uninorth_ranges + 4, 0);
874     of_store_32bit_in_host(uninorth_ranges + 8, 0);
875     of_store_32bit_in_host(uninorth_ranges + 12, 0xd0000000);
876     of_store_32bit_in_host(uninorth_ranges + 16, 0);
877     of_store_32bit_in_host(uninorth_ranges + 20, 0x04000000);
878     /* IO: */
879     of_store_32bit_in_host(uninorth_ranges + 24, 0x01000000);
880     of_store_32bit_in_host(uninorth_ranges + 28, 0);
881     of_store_32bit_in_host(uninorth_ranges + 32, 0);
882     of_store_32bit_in_host(uninorth_ranges + 36, 0xe2000000);
883     of_store_32bit_in_host(uninorth_ranges + 40, 0);
884     of_store_32bit_in_host(uninorth_ranges + 44, 0x01000000);
885     of_add_prop(ofd, n, "ranges", uninorth_ranges,
886     12*sizeof(uint32_t), 0);
887    
888     ic = of_add_device(ofd, macio, "/");
889     memset(macio_aa, 0, 20);
890     of_store_32bit_in_host(macio_aa + 0, 15 << 11); /* pci tag */
891     of_store_32bit_in_host(macio_aa + 8, 0xf3000000);
892     of_add_prop(ofd, macio, "assigned-addresses", macio_aa,
893     5*sizeof(uint32_t), 0);
894     /* of_add_prop(ofd, n, "assigned-addresses", macio_aa,
895     5*sizeof(uint32_t), 0); */
896     of_add_prop_int32(ofd, "/chosen", "interrupt-controller", ic->handle);
897    
898     of_add_device(ofd, "bandit", "/");
899     of_add_device(ofd, "gc", "/bandit");
900     of_add_prop(ofd, "/bandit/gc", "assigned-addresses", macio_aa,
901     5*sizeof(uint32_t), 0);
902    
903     if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
904     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
905 dpavlin 34 char tmpstr[400];
906 dpavlin 22 of_add_device(ofd, "ata", "/bandit/gc");
907     of_add_prop_str(machine, ofd, "/bandit/gc/ata", "name", "ata");
908     of_add_prop_str(machine, ofd, "/bandit/gc/ata", "compatible",
909     "heathrow-ata");
910     of_store_32bit_in_host(ata_interrupts + 0, 13);
911     of_store_32bit_in_host(ata_interrupts + 4, 0);
912     of_store_32bit_in_host(ata_interrupts + 8, 0);
913     of_store_32bit_in_host(ata_interrupts + 12, 0);
914     of_store_32bit_in_host(ata_interrupts + 16, 0);
915     of_store_32bit_in_host(ata_interrupts + 20, 0);
916     of_add_prop(ofd, "/bandit/gc/ata", "interrupts", ata_interrupts,
917     6*sizeof(uint32_t), 0);
918     of_store_32bit_in_host(ata_reg + 0, 0x20000);
919     of_store_32bit_in_host(ata_reg + 4, 0);
920     of_store_32bit_in_host(ata_reg + 8, 0x21000);
921     of_store_32bit_in_host(ata_reg + 12, 0x22000);
922     of_store_32bit_in_host(ata_reg + 16, 0);
923     of_store_32bit_in_host(ata_reg + 20, 0);
924     of_store_32bit_in_host(ata_reg + 24, 0);
925     of_store_32bit_in_host(ata_reg + 28, 0);
926     of_add_prop(ofd, "/bandit/gc/ata", "reg", ata_reg,
927     8*sizeof(uint32_t), 0);
928 dpavlin 34
929     snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0xf3020000 "
930     "irq=%s.cpu[%i].gc.lo.21 addr_mult=0x10", machine->path,
931     machine->bootstrap_cpu);
932     device_add(machine, tmpstr);
933 dpavlin 22 }
934    
935     return;
936    
937     bad:
938     fatal("of_emul_init_uninorth(): out of memory\n");
939     exit(1);
940     }
941    
942    
943     /*
944     * of_emul_init():
945     *
946     * This function creates an OpenFirmware emulation instance.
947     */
948     struct of_data *of_emul_init(struct machine *machine, struct vfb_data *vfb_data,
949     uint64_t fb_addr, int fb_xsize, int fb_ysize)
950     {
951     unsigned char *memory_reg, *memory_av;
952     unsigned char *zs_assigned_addresses;
953     struct of_device *mmu, *devstdout, *devstdin;
954     struct of_data *ofd = malloc(sizeof(struct of_data));
955     int i;
956    
957     if (ofd == NULL)
958     goto bad;
959     memset(ofd, 0, sizeof(struct of_data));
960    
961     ofd->vfb_data = vfb_data;
962    
963     /* Devices: */
964    
965     /* Root = device 1 */
966     of_add_device(ofd, "", "");
967    
968     of_add_device(ofd, "io", "/");
969     devstdin = of_add_device(ofd, "stdin", "/io");
970     devstdout = of_add_device(ofd, "stdout", "/io");
971    
972     if (machine->use_x11) {
973     fatal("!\n! TODO: keyboard + framebuffer for MacPPC\n!\n");
974    
975     of_add_prop_str(machine, ofd, "/io/stdin", "name",
976     "keyboard");
977     of_add_prop_str(machine, ofd, "/io", "name", "adb");
978    
979     of_add_prop_str(machine, ofd, "/io/stdout", "device_type",
980     "display");
981     of_add_prop_int32(ofd, "/io/stdout", "width", fb_xsize);
982     of_add_prop_int32(ofd, "/io/stdout", "height", fb_ysize);
983     of_add_prop_int32(ofd, "/io/stdout", "linebytes", fb_xsize * 1);
984     of_add_prop_int32(ofd, "/io/stdout", "depth", 8);
985     of_add_prop_int32(ofd, "/io/stdout", "address", fb_addr);
986     } else {
987     zs_assigned_addresses = malloc(12);
988     if (zs_assigned_addresses == NULL)
989     goto bad;
990     memset(zs_assigned_addresses, 0, 12);
991     of_add_prop_str(machine, ofd, "/io/stdin", "name", "ch-b");
992     of_add_prop_str(machine, ofd, "/io/stdin", "device_type",
993     "serial");
994     of_add_prop_int32(ofd, "/io/stdin", "reg", 0xf3013000);
995     of_add_prop(ofd, "/io/stdin", "assigned-addresses",
996     zs_assigned_addresses, 12, 0);
997    
998     of_add_prop_str(machine, ofd, "/io/stdout", "device_type",
999     "serial");
1000     }
1001    
1002     of_add_device(ofd, "cpus", "/");
1003     for (i=0; i<machine->ncpus; i++) {
1004     char tmp[50];
1005     snprintf(tmp, sizeof(tmp), "@%x", i);
1006     of_add_device(ofd, tmp, "/cpus");
1007     snprintf(tmp, sizeof(tmp), "/cpus/@%x", i);
1008     of_add_prop_str(machine, ofd, tmp, "device_type", "cpu");
1009     of_add_prop_int32(ofd, tmp, "timebase-frequency",
1010     machine->emulated_hz / 4);
1011     of_add_prop_int32(ofd, tmp, "clock-frequency",
1012     machine->emulated_hz);
1013     of_add_prop_int32(ofd, tmp, "reg", i);
1014     }
1015    
1016     mmu = of_add_device(ofd, "mmu", "/");
1017    
1018     /* TODO: */
1019     of_add_prop(ofd, "/mmu", "translations", NULL, 0, 0);
1020    
1021     of_add_device(ofd, "chosen", "/");
1022     of_add_prop_int32(ofd, "/chosen", "mmu", mmu->handle);
1023     of_add_prop_int32(ofd, "/chosen", "stdin", devstdin->handle);
1024     of_add_prop_int32(ofd, "/chosen", "stdout", devstdout->handle);
1025    
1026     of_add_device(ofd, "memory", "/");
1027     memory_reg = malloc(2 * sizeof(uint32_t));
1028     memory_av = malloc(2 * sizeof(uint32_t));
1029     if (memory_reg == NULL || memory_av == NULL)
1030     goto bad;
1031     of_store_32bit_in_host(memory_reg + 0, 0);
1032     of_store_32bit_in_host(memory_reg + 4, machine->physical_ram_in_mb<<20);
1033     of_store_32bit_in_host(memory_av + 0, 10 << 20);
1034     of_store_32bit_in_host(memory_av + 4,
1035     (machine->physical_ram_in_mb - 10) << 20);
1036     of_add_prop(ofd, "/memory", "reg", memory_reg, 2 * sizeof(uint32_t), 0);
1037     of_add_prop(ofd, "/memory", "available",memory_av,2*sizeof(uint32_t),0);
1038     of_add_prop_str(machine, ofd, "/memory","device_type","memory"/*?*/);
1039    
1040     /* Services: */
1041     of_add_service(ofd, "call-method", of__call_method_2_2, 2, 2);
1042     of_add_service(ofd, "call-method", of__call_method_3_4, 3, 4);
1043     of_add_service(ofd, "call-method", of__call_method_5_2, 5, 2);
1044     of_add_service(ofd, "call-method", of__call_method_6_1, 6, 1);
1045     of_add_service(ofd, "call-method", of__call_method_6_2, 6, 2);
1046     of_add_service(ofd, "child", of__child, 1, 1);
1047     of_add_service(ofd, "exit", of__exit, 0, 0);
1048     of_add_service(ofd, "finddevice", of__finddevice, 1, 1);
1049     of_add_service(ofd, "getprop", of__getprop, 4, 1);
1050     of_add_service(ofd, "getproplen", of__getproplen, 2, 1);
1051     of_add_service(ofd, "instance-to-package",
1052     of__instance_to_package, 1, 1);
1053     of_add_service(ofd, "interpret", of__interpret_1, 1, 1);
1054     of_add_service(ofd, "interpret", of__interpret_2, 1, 2);
1055     of_add_service(ofd, "package-to-path", of__package_to_path, 3, 1);
1056     of_add_service(ofd, "parent", of__parent, 1, 1);
1057     of_add_service(ofd, "peer", of__peer, 1, 1);
1058     of_add_service(ofd, "read", of__read, 3, 1);
1059     of_add_service(ofd, "write", of__write, 3, 1);
1060    
1061     if (verbose >= 2)
1062     of_dump_all(ofd);
1063    
1064 dpavlin 34 machine->md.of_data = ofd;
1065 dpavlin 22 return ofd;
1066    
1067     bad:
1068     fatal("of_emul_init(): out of memory\n");
1069     exit(1);
1070     }
1071    
1072    
1073     /*
1074 dpavlin 14 * of_emul():
1075     *
1076     * OpenFirmware call emulation.
1077     */
1078     int of_emul(struct cpu *cpu)
1079     {
1080 dpavlin 22 int i, nargs, nret, ofs, retval = 0;
1081 dpavlin 14 char service[50];
1082 dpavlin 22 char *arg[OF_N_MAX_ARGS];
1083 dpavlin 14 uint64_t base, ptr;
1084 dpavlin 22 struct of_service *os;
1085 dpavlin 34 struct of_data *of_data = cpu->machine->md.of_data;
1086 dpavlin 14
1087 dpavlin 22 if (of_data == NULL) {
1088     fatal("of_emul(): no of_data struct?\n");
1089     exit(1);
1090     }
1091    
1092 dpavlin 14 /*
1093     * The first argument register points to "prom_args":
1094     *
1095     * char *service; (probably 32 bit)
1096     * int nargs;
1097     * int nret;
1098     * char *args[10];
1099     */
1100    
1101     switch (cpu->machine->arch) {
1102     case ARCH_ARM:
1103     base = cpu->cd.arm.r[0];
1104     break;
1105     case ARCH_PPC:
1106     base = cpu->cd.ppc.gpr[3];
1107     break;
1108 dpavlin 22 default:fatal("of_emul(): unimplemented arch (TODO)\n");
1109 dpavlin 14 exit(1);
1110     }
1111    
1112     /* TODO: how about 64-bit OpenFirmware? */
1113     ptr = load_32bit_word(cpu, base);
1114     nargs = load_32bit_word(cpu, base + 4);
1115     nret = load_32bit_word(cpu, base + 8);
1116    
1117     readstr(cpu, ptr, service, sizeof(service));
1118    
1119     debug("[ of: %s(", service);
1120     ofs = 12;
1121     for (i=0; i<nargs; i++) {
1122 dpavlin 22 int x;
1123 dpavlin 14 if (i > 0)
1124     debug(", ");
1125 dpavlin 22 if (i >= OF_N_MAX_ARGS) {
1126 dpavlin 14 fatal("TOO MANY ARGS!");
1127     continue;
1128     }
1129     ptr = load_32bit_word(cpu, base + ofs);
1130 dpavlin 22 arg[i] = malloc(OF_ARG_MAX_LEN + 1);
1131     if (arg[i] == NULL) {
1132     fatal("out of memory\n");
1133     exit(1);
1134     }
1135     memset(arg[i], 0, OF_ARG_MAX_LEN + 1);
1136     x = ptr;
1137     if (x > -256 && x < 256) {
1138     debug("%i", x);
1139     } else {
1140     readstr(cpu, ptr, arg[i], OF_ARG_MAX_LEN);
1141     if (arg[i][0])
1142     debug("\"%s\"", arg[i]);
1143 dpavlin 14 else
1144     debug("0x%x", x);
1145     }
1146     ofs += sizeof(uint32_t);
1147     }
1148     debug(") ]\n");
1149    
1150     /* Note: base + ofs points to the first return slot. */
1151    
1152 dpavlin 22 os = of_data->of_services;
1153     while (os != NULL) {
1154     if (strcmp(service, os->name) == 0 &&
1155     nargs == os->n_args && nret == os->n_ret_args) {
1156     retval = os->f(cpu, arg, base, ofs);
1157     break;
1158 dpavlin 14 }
1159 dpavlin 22 os = os->next;
1160     }
1161 dpavlin 14
1162 dpavlin 22 if (os == NULL) {
1163 dpavlin 14 quiet_mode = 0;
1164     cpu_register_dump(cpu->machine, cpu, 1, 0);
1165     printf("\n");
1166 dpavlin 22 fatal("[ of: unimplemented service \"%s\" with %i input "
1167     "args and %i output values ]\n", service, nargs, nret);
1168 dpavlin 14 cpu->running = 0;
1169     }
1170    
1171 dpavlin 22 for (i=0; i<nargs; i++)
1172     free(arg[i]);
1173    
1174     /* Return: */
1175 dpavlin 14 switch (cpu->machine->arch) {
1176     case ARCH_ARM:
1177     cpu->cd.arm.r[0] = retval;
1178     break;
1179     case ARCH_PPC:
1180     cpu->cd.ppc.gpr[3] = retval;
1181     break;
1182 dpavlin 22 default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n");
1183 dpavlin 14 exit(1);
1184     }
1185    
1186     return 1;
1187     }
1188    

  ViewVC Help
Powered by ViewVC 1.1.26