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

Contents of /trunk/src/promemul/of.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 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 /*
2 * Copyright (C) 2005-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: of.c,v 1.22 2007/02/16 17:17:51 debug Exp $
29 *
30 * OpenFirmware emulation.
31 *
32 * 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 */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/types.h>
47
48 #define OF_C
49
50 #include "console.h"
51 #include "cpu.h"
52 #include "device.h"
53 #include "devices.h"
54 #include "diskimage.h"
55 #include "machine.h"
56 #include "memory.h"
57 #include "misc.h"
58 #include "of.h"
59
60
61 /* #define debug fatal */
62
63 extern int quiet_mode;
64 extern int verbose;
65
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 * 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 struct vfb_data *v = cpu->machine->md.of_data->vfb_data;
167 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 struct of_device *od = cpu->machine->md.of_data->of_devices;
203 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 int h = find_device_handle(cpu->machine->md.of_data, arg[0]);
220 store_32bit_word(cpu, base + retofs, h);
221 return h>0? 0 : -1;
222 }
223
224
225 OF_SERVICE(getprop)
226 {
227 struct of_device *od = cpu->machine->md.of_data->of_devices;
228 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 struct of_device *od = cpu->machine->md.of_data->of_devices;
275 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 struct of_device *od = cpu->machine->md.of_data->of_devices;
352 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 struct of_device *od = cpu->machine->md.of_data->of_devices;
362 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 od = cpu->machine->md.of_data->of_devices;
379
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 struct of_data *ofd = machine->md.of_data;
693 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 struct of_data *ofd = machine->md.of_data;
724 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 struct of_data *ofd = machine->md.of_data;
764 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 struct of_data *ofd = machine->md.of_data;
840 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 char tmpstr[400];
906 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
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 }
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 machine->md.of_data = ofd;
1065 return ofd;
1066
1067 bad:
1068 fatal("of_emul_init(): out of memory\n");
1069 exit(1);
1070 }
1071
1072
1073 /*
1074 * of_emul():
1075 *
1076 * OpenFirmware call emulation.
1077 */
1078 int of_emul(struct cpu *cpu)
1079 {
1080 int i, nargs, nret, ofs, retval = 0;
1081 char service[50];
1082 char *arg[OF_N_MAX_ARGS];
1083 uint64_t base, ptr;
1084 struct of_service *os;
1085 struct of_data *of_data = cpu->machine->md.of_data;
1086
1087 if (of_data == NULL) {
1088 fatal("of_emul(): no of_data struct?\n");
1089 exit(1);
1090 }
1091
1092 /*
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 default:fatal("of_emul(): unimplemented arch (TODO)\n");
1109 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 int x;
1123 if (i > 0)
1124 debug(", ");
1125 if (i >= OF_N_MAX_ARGS) {
1126 fatal("TOO MANY ARGS!");
1127 continue;
1128 }
1129 ptr = load_32bit_word(cpu, base + ofs);
1130 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 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 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 }
1159 os = os->next;
1160 }
1161
1162 if (os == NULL) {
1163 quiet_mode = 0;
1164 cpu_register_dump(cpu->machine, cpu, 1, 0);
1165 printf("\n");
1166 fatal("[ of: unimplemented service \"%s\" with %i input "
1167 "args and %i output values ]\n", service, nargs, nret);
1168 cpu->running = 0;
1169 }
1170
1171 for (i=0; i<nargs; i++)
1172 free(arg[i]);
1173
1174 /* Return: */
1175 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 default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n");
1183 exit(1);
1184 }
1185
1186 return 1;
1187 }
1188

  ViewVC Help
Powered by ViewVC 1.1.26