1 |
/* |
2 |
* Copyright (C) 2005-2006 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.18 2006/02/16 05:57:10 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->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->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->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->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->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->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->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->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->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->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->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->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 |
of_add_device(ofd, "ata", "/bandit/gc"); |
906 |
of_add_prop_str(machine, ofd, "/bandit/gc/ata", "name", "ata"); |
907 |
of_add_prop_str(machine, ofd, "/bandit/gc/ata", "compatible", |
908 |
"heathrow-ata"); |
909 |
of_store_32bit_in_host(ata_interrupts + 0, 13); |
910 |
of_store_32bit_in_host(ata_interrupts + 4, 0); |
911 |
of_store_32bit_in_host(ata_interrupts + 8, 0); |
912 |
of_store_32bit_in_host(ata_interrupts + 12, 0); |
913 |
of_store_32bit_in_host(ata_interrupts + 16, 0); |
914 |
of_store_32bit_in_host(ata_interrupts + 20, 0); |
915 |
of_add_prop(ofd, "/bandit/gc/ata", "interrupts", ata_interrupts, |
916 |
6*sizeof(uint32_t), 0); |
917 |
of_store_32bit_in_host(ata_reg + 0, 0x20000); |
918 |
of_store_32bit_in_host(ata_reg + 4, 0); |
919 |
of_store_32bit_in_host(ata_reg + 8, 0x21000); |
920 |
of_store_32bit_in_host(ata_reg + 12, 0x22000); |
921 |
of_store_32bit_in_host(ata_reg + 16, 0); |
922 |
of_store_32bit_in_host(ata_reg + 20, 0); |
923 |
of_store_32bit_in_host(ata_reg + 24, 0); |
924 |
of_store_32bit_in_host(ata_reg + 28, 0); |
925 |
of_add_prop(ofd, "/bandit/gc/ata", "reg", ata_reg, |
926 |
8*sizeof(uint32_t), 0); |
927 |
device_add(machine, "wdc addr=0xf3020000 irq=21 " |
928 |
"addr_mult=0x10"); |
929 |
} |
930 |
|
931 |
return; |
932 |
|
933 |
bad: |
934 |
fatal("of_emul_init_uninorth(): out of memory\n"); |
935 |
exit(1); |
936 |
} |
937 |
|
938 |
|
939 |
/* |
940 |
* of_emul_init(): |
941 |
* |
942 |
* This function creates an OpenFirmware emulation instance. |
943 |
*/ |
944 |
struct of_data *of_emul_init(struct machine *machine, struct vfb_data *vfb_data, |
945 |
uint64_t fb_addr, int fb_xsize, int fb_ysize) |
946 |
{ |
947 |
unsigned char *memory_reg, *memory_av; |
948 |
unsigned char *zs_assigned_addresses; |
949 |
struct of_device *mmu, *devstdout, *devstdin; |
950 |
struct of_data *ofd = malloc(sizeof(struct of_data)); |
951 |
int i; |
952 |
|
953 |
if (ofd == NULL) |
954 |
goto bad; |
955 |
memset(ofd, 0, sizeof(struct of_data)); |
956 |
|
957 |
ofd->vfb_data = vfb_data; |
958 |
|
959 |
/* Devices: */ |
960 |
|
961 |
/* Root = device 1 */ |
962 |
of_add_device(ofd, "", ""); |
963 |
|
964 |
of_add_device(ofd, "io", "/"); |
965 |
devstdin = of_add_device(ofd, "stdin", "/io"); |
966 |
devstdout = of_add_device(ofd, "stdout", "/io"); |
967 |
|
968 |
if (machine->use_x11) { |
969 |
fatal("!\n! TODO: keyboard + framebuffer for MacPPC\n!\n"); |
970 |
|
971 |
of_add_prop_str(machine, ofd, "/io/stdin", "name", |
972 |
"keyboard"); |
973 |
of_add_prop_str(machine, ofd, "/io", "name", "adb"); |
974 |
|
975 |
of_add_prop_str(machine, ofd, "/io/stdout", "device_type", |
976 |
"display"); |
977 |
of_add_prop_int32(ofd, "/io/stdout", "width", fb_xsize); |
978 |
of_add_prop_int32(ofd, "/io/stdout", "height", fb_ysize); |
979 |
of_add_prop_int32(ofd, "/io/stdout", "linebytes", fb_xsize * 1); |
980 |
of_add_prop_int32(ofd, "/io/stdout", "depth", 8); |
981 |
of_add_prop_int32(ofd, "/io/stdout", "address", fb_addr); |
982 |
} else { |
983 |
zs_assigned_addresses = malloc(12); |
984 |
if (zs_assigned_addresses == NULL) |
985 |
goto bad; |
986 |
memset(zs_assigned_addresses, 0, 12); |
987 |
of_add_prop_str(machine, ofd, "/io/stdin", "name", "ch-b"); |
988 |
of_add_prop_str(machine, ofd, "/io/stdin", "device_type", |
989 |
"serial"); |
990 |
of_add_prop_int32(ofd, "/io/stdin", "reg", 0xf3013000); |
991 |
of_add_prop(ofd, "/io/stdin", "assigned-addresses", |
992 |
zs_assigned_addresses, 12, 0); |
993 |
|
994 |
of_add_prop_str(machine, ofd, "/io/stdout", "device_type", |
995 |
"serial"); |
996 |
} |
997 |
|
998 |
of_add_device(ofd, "cpus", "/"); |
999 |
for (i=0; i<machine->ncpus; i++) { |
1000 |
char tmp[50]; |
1001 |
snprintf(tmp, sizeof(tmp), "@%x", i); |
1002 |
of_add_device(ofd, tmp, "/cpus"); |
1003 |
snprintf(tmp, sizeof(tmp), "/cpus/@%x", i); |
1004 |
of_add_prop_str(machine, ofd, tmp, "device_type", "cpu"); |
1005 |
of_add_prop_int32(ofd, tmp, "timebase-frequency", |
1006 |
machine->emulated_hz / 4); |
1007 |
of_add_prop_int32(ofd, tmp, "clock-frequency", |
1008 |
machine->emulated_hz); |
1009 |
of_add_prop_int32(ofd, tmp, "reg", i); |
1010 |
} |
1011 |
|
1012 |
mmu = of_add_device(ofd, "mmu", "/"); |
1013 |
|
1014 |
/* TODO: */ |
1015 |
of_add_prop(ofd, "/mmu", "translations", NULL, 0, 0); |
1016 |
|
1017 |
of_add_device(ofd, "chosen", "/"); |
1018 |
of_add_prop_int32(ofd, "/chosen", "mmu", mmu->handle); |
1019 |
of_add_prop_int32(ofd, "/chosen", "stdin", devstdin->handle); |
1020 |
of_add_prop_int32(ofd, "/chosen", "stdout", devstdout->handle); |
1021 |
|
1022 |
of_add_device(ofd, "memory", "/"); |
1023 |
memory_reg = malloc(2 * sizeof(uint32_t)); |
1024 |
memory_av = malloc(2 * sizeof(uint32_t)); |
1025 |
if (memory_reg == NULL || memory_av == NULL) |
1026 |
goto bad; |
1027 |
of_store_32bit_in_host(memory_reg + 0, 0); |
1028 |
of_store_32bit_in_host(memory_reg + 4, machine->physical_ram_in_mb<<20); |
1029 |
of_store_32bit_in_host(memory_av + 0, 10 << 20); |
1030 |
of_store_32bit_in_host(memory_av + 4, |
1031 |
(machine->physical_ram_in_mb - 10) << 20); |
1032 |
of_add_prop(ofd, "/memory", "reg", memory_reg, 2 * sizeof(uint32_t), 0); |
1033 |
of_add_prop(ofd, "/memory", "available",memory_av,2*sizeof(uint32_t),0); |
1034 |
of_add_prop_str(machine, ofd, "/memory","device_type","memory"/*?*/); |
1035 |
|
1036 |
/* Services: */ |
1037 |
of_add_service(ofd, "call-method", of__call_method_2_2, 2, 2); |
1038 |
of_add_service(ofd, "call-method", of__call_method_3_4, 3, 4); |
1039 |
of_add_service(ofd, "call-method", of__call_method_5_2, 5, 2); |
1040 |
of_add_service(ofd, "call-method", of__call_method_6_1, 6, 1); |
1041 |
of_add_service(ofd, "call-method", of__call_method_6_2, 6, 2); |
1042 |
of_add_service(ofd, "child", of__child, 1, 1); |
1043 |
of_add_service(ofd, "exit", of__exit, 0, 0); |
1044 |
of_add_service(ofd, "finddevice", of__finddevice, 1, 1); |
1045 |
of_add_service(ofd, "getprop", of__getprop, 4, 1); |
1046 |
of_add_service(ofd, "getproplen", of__getproplen, 2, 1); |
1047 |
of_add_service(ofd, "instance-to-package", |
1048 |
of__instance_to_package, 1, 1); |
1049 |
of_add_service(ofd, "interpret", of__interpret_1, 1, 1); |
1050 |
of_add_service(ofd, "interpret", of__interpret_2, 1, 2); |
1051 |
of_add_service(ofd, "package-to-path", of__package_to_path, 3, 1); |
1052 |
of_add_service(ofd, "parent", of__parent, 1, 1); |
1053 |
of_add_service(ofd, "peer", of__peer, 1, 1); |
1054 |
of_add_service(ofd, "read", of__read, 3, 1); |
1055 |
of_add_service(ofd, "write", of__write, 3, 1); |
1056 |
|
1057 |
if (verbose >= 2) |
1058 |
of_dump_all(ofd); |
1059 |
|
1060 |
machine->of_data = ofd; |
1061 |
return ofd; |
1062 |
|
1063 |
bad: |
1064 |
fatal("of_emul_init(): out of memory\n"); |
1065 |
exit(1); |
1066 |
} |
1067 |
|
1068 |
|
1069 |
/* |
1070 |
* of_emul(): |
1071 |
* |
1072 |
* OpenFirmware call emulation. |
1073 |
*/ |
1074 |
int of_emul(struct cpu *cpu) |
1075 |
{ |
1076 |
int i, nargs, nret, ofs, retval = 0; |
1077 |
char service[50]; |
1078 |
char *arg[OF_N_MAX_ARGS]; |
1079 |
uint64_t base, ptr; |
1080 |
struct of_service *os; |
1081 |
struct of_data *of_data = cpu->machine->of_data; |
1082 |
|
1083 |
if (of_data == NULL) { |
1084 |
fatal("of_emul(): no of_data struct?\n"); |
1085 |
exit(1); |
1086 |
} |
1087 |
|
1088 |
/* |
1089 |
* The first argument register points to "prom_args": |
1090 |
* |
1091 |
* char *service; (probably 32 bit) |
1092 |
* int nargs; |
1093 |
* int nret; |
1094 |
* char *args[10]; |
1095 |
*/ |
1096 |
|
1097 |
switch (cpu->machine->arch) { |
1098 |
case ARCH_ARM: |
1099 |
base = cpu->cd.arm.r[0]; |
1100 |
break; |
1101 |
case ARCH_PPC: |
1102 |
base = cpu->cd.ppc.gpr[3]; |
1103 |
break; |
1104 |
default:fatal("of_emul(): unimplemented arch (TODO)\n"); |
1105 |
exit(1); |
1106 |
} |
1107 |
|
1108 |
/* TODO: how about 64-bit OpenFirmware? */ |
1109 |
ptr = load_32bit_word(cpu, base); |
1110 |
nargs = load_32bit_word(cpu, base + 4); |
1111 |
nret = load_32bit_word(cpu, base + 8); |
1112 |
|
1113 |
readstr(cpu, ptr, service, sizeof(service)); |
1114 |
|
1115 |
debug("[ of: %s(", service); |
1116 |
ofs = 12; |
1117 |
for (i=0; i<nargs; i++) { |
1118 |
int x; |
1119 |
if (i > 0) |
1120 |
debug(", "); |
1121 |
if (i >= OF_N_MAX_ARGS) { |
1122 |
fatal("TOO MANY ARGS!"); |
1123 |
continue; |
1124 |
} |
1125 |
ptr = load_32bit_word(cpu, base + ofs); |
1126 |
arg[i] = malloc(OF_ARG_MAX_LEN + 1); |
1127 |
if (arg[i] == NULL) { |
1128 |
fatal("out of memory\n"); |
1129 |
exit(1); |
1130 |
} |
1131 |
memset(arg[i], 0, OF_ARG_MAX_LEN + 1); |
1132 |
x = ptr; |
1133 |
if (x > -256 && x < 256) { |
1134 |
debug("%i", x); |
1135 |
} else { |
1136 |
readstr(cpu, ptr, arg[i], OF_ARG_MAX_LEN); |
1137 |
if (arg[i][0]) |
1138 |
debug("\"%s\"", arg[i]); |
1139 |
else |
1140 |
debug("0x%x", x); |
1141 |
} |
1142 |
ofs += sizeof(uint32_t); |
1143 |
} |
1144 |
debug(") ]\n"); |
1145 |
|
1146 |
/* Note: base + ofs points to the first return slot. */ |
1147 |
|
1148 |
os = of_data->of_services; |
1149 |
while (os != NULL) { |
1150 |
if (strcmp(service, os->name) == 0 && |
1151 |
nargs == os->n_args && nret == os->n_ret_args) { |
1152 |
retval = os->f(cpu, arg, base, ofs); |
1153 |
break; |
1154 |
} |
1155 |
os = os->next; |
1156 |
} |
1157 |
|
1158 |
if (os == NULL) { |
1159 |
quiet_mode = 0; |
1160 |
cpu_register_dump(cpu->machine, cpu, 1, 0); |
1161 |
printf("\n"); |
1162 |
fatal("[ of: unimplemented service \"%s\" with %i input " |
1163 |
"args and %i output values ]\n", service, nargs, nret); |
1164 |
cpu->running = 0; |
1165 |
cpu->dead = 1; |
1166 |
} |
1167 |
|
1168 |
for (i=0; i<nargs; i++) |
1169 |
free(arg[i]); |
1170 |
|
1171 |
/* Return: */ |
1172 |
switch (cpu->machine->arch) { |
1173 |
case ARCH_ARM: |
1174 |
cpu->cd.arm.r[0] = retval; |
1175 |
break; |
1176 |
case ARCH_PPC: |
1177 |
cpu->cd.ppc.gpr[3] = retval; |
1178 |
break; |
1179 |
default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n"); |
1180 |
exit(1); |
1181 |
} |
1182 |
|
1183 |
return 1; |
1184 |
} |
1185 |
|