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.23 2007/03/24 06:40:16 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 |
return NULL; /* Silences a compiler warning */ |
502 |
} |
503 |
|
504 |
|
505 |
/* |
506 |
* of_add_prop(): |
507 |
* |
508 |
* Adds a property to a device. |
509 |
*/ |
510 |
static void of_add_prop(struct of_data *of_data, char *devname, |
511 |
char *propname, unsigned char *data, uint32_t len, int flags) |
512 |
{ |
513 |
struct of_device_property *pr = |
514 |
malloc(sizeof(struct of_device_property)); |
515 |
struct of_device *od = of_data->of_devices; |
516 |
int h = find_device_handle(of_data, devname); |
517 |
|
518 |
OF_FIND(od, od->handle == h); |
519 |
if (od == NULL) { |
520 |
fatal("of_add_prop(): device '%s' not registered\n", devname); |
521 |
exit(1); |
522 |
} |
523 |
|
524 |
if (pr == NULL) |
525 |
goto bad; |
526 |
memset(pr, 0, sizeof(struct of_device_property)); |
527 |
|
528 |
pr->name = strdup(propname); |
529 |
if (pr->name == NULL) |
530 |
goto bad; |
531 |
pr->data = data; |
532 |
pr->len = len; |
533 |
pr->flags = flags; |
534 |
|
535 |
pr->next = od->properties; |
536 |
od->properties = pr; |
537 |
return; |
538 |
|
539 |
bad: |
540 |
fatal("of_add_device(): out of memory\n"); |
541 |
exit(1); |
542 |
} |
543 |
|
544 |
|
545 |
/* |
546 |
* of_add_service(): |
547 |
* |
548 |
* Adds a service. |
549 |
*/ |
550 |
static void of_add_service(struct of_data *of_data, char *name, |
551 |
int (*f)(OF_SERVICE_ARGS), int n_args, int n_ret_args) |
552 |
{ |
553 |
struct of_service *os = malloc(sizeof(struct of_service)); |
554 |
if (os == NULL) |
555 |
goto bad; |
556 |
memset(os, 0, sizeof(struct of_service)); |
557 |
|
558 |
os->name = strdup(name); |
559 |
if (os->name == NULL) |
560 |
goto bad; |
561 |
|
562 |
os->f = f; |
563 |
os->n_args = n_args; |
564 |
os->n_ret_args = n_ret_args; |
565 |
|
566 |
os->next = of_data->of_services; |
567 |
of_data->of_services = os; |
568 |
return; |
569 |
|
570 |
bad: |
571 |
fatal("of_add_service(): out of memory\n"); |
572 |
exit(1); |
573 |
} |
574 |
|
575 |
|
576 |
/* |
577 |
* of_dump_devices(): |
578 |
* |
579 |
* Debug dump helper. |
580 |
*/ |
581 |
static void of_dump_devices(struct of_data *ofd, int parent) |
582 |
{ |
583 |
int iadd = DEBUG_INDENTATION; |
584 |
struct of_device *od = ofd->of_devices; |
585 |
|
586 |
while (od != NULL) { |
587 |
struct of_device_property *pr = od->properties; |
588 |
if (od->parent != parent) { |
589 |
od = od->next; |
590 |
continue; |
591 |
} |
592 |
debug("\"%s\"\n", od->name, od->handle); |
593 |
debug_indentation(iadd); |
594 |
while (pr != NULL) { |
595 |
debug("(%s: ", pr->name); |
596 |
if (pr->flags == OF_PROP_STRING) |
597 |
debug("\"%s\"", pr->data); |
598 |
else |
599 |
debug("%i bytes", pr->len); |
600 |
debug(")\n"); |
601 |
pr = pr->next; |
602 |
} |
603 |
of_dump_devices(ofd, od->handle); |
604 |
debug_indentation(-iadd); |
605 |
od = od->next; |
606 |
} |
607 |
} |
608 |
|
609 |
|
610 |
/* |
611 |
* of_dump_all(): |
612 |
* |
613 |
* Debug dump. |
614 |
*/ |
615 |
static void of_dump_all(struct of_data *ofd) |
616 |
{ |
617 |
int iadd = DEBUG_INDENTATION; |
618 |
struct of_service *os; |
619 |
|
620 |
debug("openfirmware debug dump:\n"); |
621 |
debug_indentation(iadd); |
622 |
|
623 |
/* Devices: */ |
624 |
of_dump_devices(ofd, 0); |
625 |
|
626 |
/* Services: */ |
627 |
os = ofd->of_services; |
628 |
while (os != NULL) { |
629 |
debug("service '%s'", os->name); |
630 |
if (os->n_ret_args > 0 || os->n_args > 0) { |
631 |
debug(" ("); |
632 |
if (os->n_args > 0) { |
633 |
debug("%i arg%s", os->n_args, |
634 |
os->n_args > 1? "s" : ""); |
635 |
if (os->n_ret_args > 0) |
636 |
debug(", "); |
637 |
} |
638 |
if (os->n_ret_args > 0) |
639 |
debug("%i return value%s", os->n_ret_args, |
640 |
os->n_ret_args > 1? "s" : ""); |
641 |
debug(")"); |
642 |
} |
643 |
debug("\n"); |
644 |
os = os->next; |
645 |
} |
646 |
|
647 |
debug_indentation(-iadd); |
648 |
} |
649 |
|
650 |
|
651 |
/* |
652 |
* of_add_prop_int32(): |
653 |
* |
654 |
* Helper function. |
655 |
*/ |
656 |
static void of_add_prop_int32(struct of_data *ofd, |
657 |
char *devname, char *propname, uint32_t x) |
658 |
{ |
659 |
unsigned char *p = malloc(sizeof(int32_t)); |
660 |
if (p == NULL) { |
661 |
fatal("of_add_prop_int32(): out of memory\n"); |
662 |
exit(1); |
663 |
} |
664 |
of_store_32bit_in_host(p, x); |
665 |
of_add_prop(ofd, devname, propname, p, sizeof(int32_t), |
666 |
OF_PROP_INT); |
667 |
} |
668 |
|
669 |
|
670 |
/* |
671 |
* of_add_prop_str(): |
672 |
* |
673 |
* Helper function. |
674 |
*/ |
675 |
static void of_add_prop_str(struct machine *machine, struct of_data *ofd, |
676 |
char *devname, char *propname, char *data) |
677 |
{ |
678 |
char *p = strdup(data); |
679 |
if (p == NULL) { |
680 |
fatal("of_add_prop_str(): out of memory\n"); |
681 |
exit(1); |
682 |
} |
683 |
|
684 |
of_add_prop(ofd, devname, propname, (unsigned char *)p, strlen(p) + 1, |
685 |
OF_PROP_STRING); |
686 |
} |
687 |
|
688 |
|
689 |
/* |
690 |
* of_emul_init_isa(): |
691 |
*/ |
692 |
void of_emul_init_isa(struct machine *machine) |
693 |
{ |
694 |
struct of_data *ofd = machine->md.of_data; |
695 |
unsigned char *isa_ranges; |
696 |
|
697 |
of_add_device(ofd, "isa", "/"); |
698 |
isa_ranges = malloc(32); |
699 |
if (isa_ranges == NULL) |
700 |
goto bad; |
701 |
memset(isa_ranges, 0, 32); |
702 |
/* 2 *: isa_phys_hi, isa_phys_lo, parent_phys_start, size */ |
703 |
/* MEM space: */ |
704 |
of_store_32bit_in_host(isa_ranges + 0, 0); |
705 |
of_store_32bit_in_host(isa_ranges + 4, 0xc0000000); |
706 |
/* I/O space: low bit if isa_phys_hi set */ |
707 |
of_store_32bit_in_host(isa_ranges + 16, 1); |
708 |
of_store_32bit_in_host(isa_ranges + 20, 0xd0000000); |
709 |
|
710 |
of_add_prop(ofd, "/isa", "ranges", isa_ranges, 32, 0); |
711 |
|
712 |
return; |
713 |
|
714 |
bad: |
715 |
fatal("of_emul_init_isa(): out of memory\n"); |
716 |
exit(1); |
717 |
} |
718 |
|
719 |
|
720 |
/* |
721 |
* of_emul_init_adb(): |
722 |
*/ |
723 |
void of_emul_init_adb(struct machine *machine) |
724 |
{ |
725 |
struct of_data *ofd = machine->md.of_data; |
726 |
unsigned char *adb_interrupts, *adb_reg; |
727 |
|
728 |
adb_interrupts = malloc(4 * sizeof(uint32_t)); |
729 |
adb_reg = malloc(8 * sizeof(uint32_t)); |
730 |
if (adb_interrupts == NULL || adb_reg == NULL) |
731 |
goto bad; |
732 |
|
733 |
of_add_device(ofd, "adb", "/bandit/gc"); |
734 |
of_add_prop_str(machine, ofd, "/bandit/gc/adb", "name", "via-cuda"); |
735 |
of_store_32bit_in_host(adb_interrupts + 0, 25); |
736 |
of_store_32bit_in_host(adb_interrupts + 4, 0); |
737 |
of_store_32bit_in_host(adb_interrupts + 8, 0); |
738 |
of_store_32bit_in_host(adb_interrupts + 12, 0); |
739 |
of_add_prop(ofd, "/bandit/gc/adb", "interrupts", adb_interrupts, |
740 |
4*sizeof(uint32_t), 0); |
741 |
of_store_32bit_in_host(adb_reg + 0, 0x16000); |
742 |
of_store_32bit_in_host(adb_reg + 4, 0x2000); |
743 |
of_store_32bit_in_host(adb_reg + 8, 0); |
744 |
of_store_32bit_in_host(adb_reg + 12, 0); |
745 |
of_store_32bit_in_host(adb_reg + 16, 0); |
746 |
of_store_32bit_in_host(adb_reg + 20, 0); |
747 |
of_store_32bit_in_host(adb_reg + 24, 0); |
748 |
of_store_32bit_in_host(adb_reg + 28, 0); |
749 |
of_add_prop(ofd, "/bandit/gc/adb", "reg", adb_reg, |
750 |
8*sizeof(uint32_t), 0); |
751 |
|
752 |
return; |
753 |
|
754 |
bad: |
755 |
fatal("of_emul_init_adb(): out of memory\n"); |
756 |
exit(1); |
757 |
} |
758 |
|
759 |
|
760 |
/* |
761 |
* of_emul_init_zs(): |
762 |
*/ |
763 |
void of_emul_init_zs(struct machine *machine) |
764 |
{ |
765 |
struct of_data *ofd = machine->md.of_data; |
766 |
unsigned char *zs_interrupts, *zs_reg; |
767 |
|
768 |
zs_reg = malloc(6 * sizeof(uint32_t)); |
769 |
if (zs_reg == NULL) |
770 |
goto bad; |
771 |
|
772 |
/* The controller: */ |
773 |
of_add_device(ofd, "zs", "/bandit/gc"); |
774 |
of_add_prop_str(machine, ofd, "/bandit/gc/zs", "device_type", "serial"); |
775 |
of_add_prop_str(machine, ofd, "/bandit/gc/zs", "name", "escc"); |
776 |
of_store_32bit_in_host(zs_reg + 0, 0x13000); |
777 |
of_store_32bit_in_host(zs_reg + 4, 0x40); |
778 |
of_store_32bit_in_host(zs_reg + 8, 0x100); |
779 |
of_store_32bit_in_host(zs_reg + 12, 0x100); |
780 |
of_store_32bit_in_host(zs_reg + 16, 0x200); |
781 |
of_store_32bit_in_host(zs_reg + 20, 0x100); |
782 |
of_add_prop(ofd, "/bandit/gc/zs", "reg", zs_reg, 6*sizeof(uint32_t), 0); |
783 |
|
784 |
/* Port 1: */ |
785 |
zs_interrupts = malloc(3 * sizeof(uint32_t)); |
786 |
zs_reg = malloc(6 * sizeof(uint32_t)); |
787 |
if (zs_interrupts == NULL || zs_reg == NULL) |
788 |
goto bad; |
789 |
|
790 |
of_add_device(ofd, "zstty1", "/bandit/gc/zs"); |
791 |
of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty1", "name", "ch-a"); |
792 |
of_store_32bit_in_host(zs_interrupts + 0, 16); |
793 |
of_store_32bit_in_host(zs_interrupts + 4, 0); |
794 |
of_store_32bit_in_host(zs_interrupts + 8, 0); |
795 |
of_add_prop(ofd, "/bandit/gc/zs/zstty1", "interrupts", zs_interrupts, |
796 |
3*sizeof(uint32_t), 0); |
797 |
of_store_32bit_in_host(zs_reg + 0, 0x13800); |
798 |
of_store_32bit_in_host(zs_reg + 4, 0x100); |
799 |
of_store_32bit_in_host(zs_reg + 8, 0x100); |
800 |
of_store_32bit_in_host(zs_reg + 12, 0x100); |
801 |
of_store_32bit_in_host(zs_reg + 16, 0x200); |
802 |
of_store_32bit_in_host(zs_reg + 20, 0x100); |
803 |
of_add_prop(ofd, "/bandit/gc/zs/zstty1", |
804 |
"reg", zs_reg, 6*sizeof(uint32_t), 0); |
805 |
|
806 |
/* Port 0: */ |
807 |
zs_interrupts = malloc(3 * sizeof(uint32_t)); |
808 |
zs_reg = malloc(6 * sizeof(uint32_t)); |
809 |
if (zs_interrupts == NULL || zs_reg == NULL) |
810 |
goto bad; |
811 |
|
812 |
of_add_device(ofd, "zstty0", "/bandit/gc/zs"); |
813 |
of_add_prop_str(machine, ofd, "/bandit/gc/zs/zstty0", "name", "ch-b"); |
814 |
of_store_32bit_in_host(zs_interrupts + 0, 15); |
815 |
of_store_32bit_in_host(zs_interrupts + 4, 0); |
816 |
of_store_32bit_in_host(zs_interrupts + 8, 0); |
817 |
of_add_prop(ofd, "/bandit/gc/zs/zstty0", "interrupts", zs_interrupts, |
818 |
3*sizeof(uint32_t), 0); |
819 |
of_store_32bit_in_host(zs_reg + 0, 0x13400); |
820 |
of_store_32bit_in_host(zs_reg + 4, 0x100); |
821 |
of_store_32bit_in_host(zs_reg + 8, 0x100); |
822 |
of_store_32bit_in_host(zs_reg + 12, 0x100); |
823 |
of_store_32bit_in_host(zs_reg + 16, 0x200); |
824 |
of_store_32bit_in_host(zs_reg + 20, 0x100); |
825 |
of_add_prop(ofd, "/bandit/gc/zs/zstty0", |
826 |
"reg", zs_reg, 6*sizeof(uint32_t), 0); |
827 |
|
828 |
return; |
829 |
|
830 |
bad: |
831 |
fatal("of_emul_init_zs(): out of memory\n"); |
832 |
exit(1); |
833 |
} |
834 |
|
835 |
|
836 |
/* |
837 |
* of_emul_init_uninorth(): |
838 |
*/ |
839 |
void of_emul_init_uninorth(struct machine *machine) |
840 |
{ |
841 |
struct of_data *ofd = machine->md.of_data; |
842 |
unsigned char *uninorth_reg, *uninorth_bus_range, *uninorth_ranges; |
843 |
unsigned char *macio_aa, *ata_interrupts, *ata_reg; |
844 |
struct of_device *ic; |
845 |
char *n = "pci@e2000000"; |
846 |
char *macio = "mac-io"; |
847 |
|
848 |
of_add_device(ofd, n, "/"); |
849 |
of_add_prop_str(machine, ofd, n, "name", "pci"); |
850 |
of_add_prop_str(machine, ofd, n, "device_type", "pci"); |
851 |
of_add_prop_str(machine, ofd, n, "compatible", "uni-north"); |
852 |
|
853 |
uninorth_reg = malloc(2 * sizeof(uint32_t)); |
854 |
uninorth_bus_range = malloc(2 * sizeof(uint32_t)); |
855 |
uninorth_ranges = malloc(12 * sizeof(uint32_t)); |
856 |
macio_aa = malloc(5 * sizeof(uint32_t)); |
857 |
ata_interrupts = malloc(6 * sizeof(uint32_t)); |
858 |
ata_reg = malloc(8 * sizeof(uint32_t)); |
859 |
if (uninorth_ranges == NULL || uninorth_bus_range == NULL || |
860 |
uninorth_reg == NULL || macio_aa == NULL || |
861 |
ata_interrupts == NULL || ata_reg == NULL) |
862 |
goto bad; |
863 |
|
864 |
of_store_32bit_in_host(uninorth_reg + 0, 0xe2000000); |
865 |
of_store_32bit_in_host(uninorth_reg + 4, 0); /* not used? */ |
866 |
of_add_prop(ofd, n, "reg", uninorth_reg, 2*sizeof(uint32_t), 0); |
867 |
|
868 |
of_store_32bit_in_host(uninorth_bus_range + 0, 0); |
869 |
of_store_32bit_in_host(uninorth_bus_range + 4, 0); |
870 |
of_add_prop(ofd, n, "bus-range", uninorth_bus_range, |
871 |
2*sizeof(uint32_t), 0); |
872 |
|
873 |
/* MEM: */ |
874 |
of_store_32bit_in_host(uninorth_ranges + 0, 0x02000000); |
875 |
of_store_32bit_in_host(uninorth_ranges + 4, 0); |
876 |
of_store_32bit_in_host(uninorth_ranges + 8, 0); |
877 |
of_store_32bit_in_host(uninorth_ranges + 12, 0xd0000000); |
878 |
of_store_32bit_in_host(uninorth_ranges + 16, 0); |
879 |
of_store_32bit_in_host(uninorth_ranges + 20, 0x04000000); |
880 |
/* IO: */ |
881 |
of_store_32bit_in_host(uninorth_ranges + 24, 0x01000000); |
882 |
of_store_32bit_in_host(uninorth_ranges + 28, 0); |
883 |
of_store_32bit_in_host(uninorth_ranges + 32, 0); |
884 |
of_store_32bit_in_host(uninorth_ranges + 36, 0xe2000000); |
885 |
of_store_32bit_in_host(uninorth_ranges + 40, 0); |
886 |
of_store_32bit_in_host(uninorth_ranges + 44, 0x01000000); |
887 |
of_add_prop(ofd, n, "ranges", uninorth_ranges, |
888 |
12*sizeof(uint32_t), 0); |
889 |
|
890 |
ic = of_add_device(ofd, macio, "/"); |
891 |
memset(macio_aa, 0, 20); |
892 |
of_store_32bit_in_host(macio_aa + 0, 15 << 11); /* pci tag */ |
893 |
of_store_32bit_in_host(macio_aa + 8, 0xf3000000); |
894 |
of_add_prop(ofd, macio, "assigned-addresses", macio_aa, |
895 |
5*sizeof(uint32_t), 0); |
896 |
/* of_add_prop(ofd, n, "assigned-addresses", macio_aa, |
897 |
5*sizeof(uint32_t), 0); */ |
898 |
of_add_prop_int32(ofd, "/chosen", "interrupt-controller", ic->handle); |
899 |
|
900 |
of_add_device(ofd, "bandit", "/"); |
901 |
of_add_device(ofd, "gc", "/bandit"); |
902 |
of_add_prop(ofd, "/bandit/gc", "assigned-addresses", macio_aa, |
903 |
5*sizeof(uint32_t), 0); |
904 |
|
905 |
if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || |
906 |
diskimage_exist(machine, 1, DISKIMAGE_IDE)) { |
907 |
char tmpstr[400]; |
908 |
of_add_device(ofd, "ata", "/bandit/gc"); |
909 |
of_add_prop_str(machine, ofd, "/bandit/gc/ata", "name", "ata"); |
910 |
of_add_prop_str(machine, ofd, "/bandit/gc/ata", "compatible", |
911 |
"heathrow-ata"); |
912 |
of_store_32bit_in_host(ata_interrupts + 0, 13); |
913 |
of_store_32bit_in_host(ata_interrupts + 4, 0); |
914 |
of_store_32bit_in_host(ata_interrupts + 8, 0); |
915 |
of_store_32bit_in_host(ata_interrupts + 12, 0); |
916 |
of_store_32bit_in_host(ata_interrupts + 16, 0); |
917 |
of_store_32bit_in_host(ata_interrupts + 20, 0); |
918 |
of_add_prop(ofd, "/bandit/gc/ata", "interrupts", ata_interrupts, |
919 |
6*sizeof(uint32_t), 0); |
920 |
of_store_32bit_in_host(ata_reg + 0, 0x20000); |
921 |
of_store_32bit_in_host(ata_reg + 4, 0); |
922 |
of_store_32bit_in_host(ata_reg + 8, 0x21000); |
923 |
of_store_32bit_in_host(ata_reg + 12, 0x22000); |
924 |
of_store_32bit_in_host(ata_reg + 16, 0); |
925 |
of_store_32bit_in_host(ata_reg + 20, 0); |
926 |
of_store_32bit_in_host(ata_reg + 24, 0); |
927 |
of_store_32bit_in_host(ata_reg + 28, 0); |
928 |
of_add_prop(ofd, "/bandit/gc/ata", "reg", ata_reg, |
929 |
8*sizeof(uint32_t), 0); |
930 |
|
931 |
snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0xf3020000 " |
932 |
"irq=%s.cpu[%i].gc.lo.21 addr_mult=0x10", machine->path, |
933 |
machine->bootstrap_cpu); |
934 |
device_add(machine, tmpstr); |
935 |
} |
936 |
|
937 |
return; |
938 |
|
939 |
bad: |
940 |
fatal("of_emul_init_uninorth(): out of memory\n"); |
941 |
exit(1); |
942 |
} |
943 |
|
944 |
|
945 |
/* |
946 |
* of_emul_init(): |
947 |
* |
948 |
* This function creates an OpenFirmware emulation instance. |
949 |
*/ |
950 |
struct of_data *of_emul_init(struct machine *machine, struct vfb_data *vfb_data, |
951 |
uint64_t fb_addr, int fb_xsize, int fb_ysize) |
952 |
{ |
953 |
unsigned char *memory_reg, *memory_av; |
954 |
unsigned char *zs_assigned_addresses; |
955 |
struct of_device *mmu, *devstdout, *devstdin; |
956 |
struct of_data *ofd = malloc(sizeof(struct of_data)); |
957 |
int i; |
958 |
|
959 |
if (ofd == NULL) |
960 |
goto bad; |
961 |
memset(ofd, 0, sizeof(struct of_data)); |
962 |
|
963 |
ofd->vfb_data = vfb_data; |
964 |
|
965 |
/* Devices: */ |
966 |
|
967 |
/* Root = device 1 */ |
968 |
of_add_device(ofd, "", ""); |
969 |
|
970 |
of_add_device(ofd, "io", "/"); |
971 |
devstdin = of_add_device(ofd, "stdin", "/io"); |
972 |
devstdout = of_add_device(ofd, "stdout", "/io"); |
973 |
|
974 |
if (machine->use_x11) { |
975 |
fatal("!\n! TODO: keyboard + framebuffer for MacPPC\n!\n"); |
976 |
|
977 |
of_add_prop_str(machine, ofd, "/io/stdin", "name", |
978 |
"keyboard"); |
979 |
of_add_prop_str(machine, ofd, "/io", "name", "adb"); |
980 |
|
981 |
of_add_prop_str(machine, ofd, "/io/stdout", "device_type", |
982 |
"display"); |
983 |
of_add_prop_int32(ofd, "/io/stdout", "width", fb_xsize); |
984 |
of_add_prop_int32(ofd, "/io/stdout", "height", fb_ysize); |
985 |
of_add_prop_int32(ofd, "/io/stdout", "linebytes", fb_xsize * 1); |
986 |
of_add_prop_int32(ofd, "/io/stdout", "depth", 8); |
987 |
of_add_prop_int32(ofd, "/io/stdout", "address", fb_addr); |
988 |
} else { |
989 |
zs_assigned_addresses = malloc(12); |
990 |
if (zs_assigned_addresses == NULL) |
991 |
goto bad; |
992 |
memset(zs_assigned_addresses, 0, 12); |
993 |
of_add_prop_str(machine, ofd, "/io/stdin", "name", "ch-b"); |
994 |
of_add_prop_str(machine, ofd, "/io/stdin", "device_type", |
995 |
"serial"); |
996 |
of_add_prop_int32(ofd, "/io/stdin", "reg", 0xf3013000); |
997 |
of_add_prop(ofd, "/io/stdin", "assigned-addresses", |
998 |
zs_assigned_addresses, 12, 0); |
999 |
|
1000 |
of_add_prop_str(machine, ofd, "/io/stdout", "device_type", |
1001 |
"serial"); |
1002 |
} |
1003 |
|
1004 |
of_add_device(ofd, "cpus", "/"); |
1005 |
for (i=0; i<machine->ncpus; i++) { |
1006 |
char tmp[50]; |
1007 |
snprintf(tmp, sizeof(tmp), "@%x", i); |
1008 |
of_add_device(ofd, tmp, "/cpus"); |
1009 |
snprintf(tmp, sizeof(tmp), "/cpus/@%x", i); |
1010 |
of_add_prop_str(machine, ofd, tmp, "device_type", "cpu"); |
1011 |
of_add_prop_int32(ofd, tmp, "timebase-frequency", |
1012 |
machine->emulated_hz / 4); |
1013 |
of_add_prop_int32(ofd, tmp, "clock-frequency", |
1014 |
machine->emulated_hz); |
1015 |
of_add_prop_int32(ofd, tmp, "reg", i); |
1016 |
} |
1017 |
|
1018 |
mmu = of_add_device(ofd, "mmu", "/"); |
1019 |
|
1020 |
/* TODO: */ |
1021 |
of_add_prop(ofd, "/mmu", "translations", NULL, 0, 0); |
1022 |
|
1023 |
of_add_device(ofd, "chosen", "/"); |
1024 |
of_add_prop_int32(ofd, "/chosen", "mmu", mmu->handle); |
1025 |
of_add_prop_int32(ofd, "/chosen", "stdin", devstdin->handle); |
1026 |
of_add_prop_int32(ofd, "/chosen", "stdout", devstdout->handle); |
1027 |
|
1028 |
of_add_device(ofd, "memory", "/"); |
1029 |
memory_reg = malloc(2 * sizeof(uint32_t)); |
1030 |
memory_av = malloc(2 * sizeof(uint32_t)); |
1031 |
if (memory_reg == NULL || memory_av == NULL) |
1032 |
goto bad; |
1033 |
of_store_32bit_in_host(memory_reg + 0, 0); |
1034 |
of_store_32bit_in_host(memory_reg + 4, machine->physical_ram_in_mb<<20); |
1035 |
of_store_32bit_in_host(memory_av + 0, 10 << 20); |
1036 |
of_store_32bit_in_host(memory_av + 4, |
1037 |
(machine->physical_ram_in_mb - 10) << 20); |
1038 |
of_add_prop(ofd, "/memory", "reg", memory_reg, 2 * sizeof(uint32_t), 0); |
1039 |
of_add_prop(ofd, "/memory", "available",memory_av,2*sizeof(uint32_t),0); |
1040 |
of_add_prop_str(machine, ofd, "/memory","device_type","memory"/*?*/); |
1041 |
|
1042 |
/* Services: */ |
1043 |
of_add_service(ofd, "call-method", of__call_method_2_2, 2, 2); |
1044 |
of_add_service(ofd, "call-method", of__call_method_3_4, 3, 4); |
1045 |
of_add_service(ofd, "call-method", of__call_method_5_2, 5, 2); |
1046 |
of_add_service(ofd, "call-method", of__call_method_6_1, 6, 1); |
1047 |
of_add_service(ofd, "call-method", of__call_method_6_2, 6, 2); |
1048 |
of_add_service(ofd, "child", of__child, 1, 1); |
1049 |
of_add_service(ofd, "exit", of__exit, 0, 0); |
1050 |
of_add_service(ofd, "finddevice", of__finddevice, 1, 1); |
1051 |
of_add_service(ofd, "getprop", of__getprop, 4, 1); |
1052 |
of_add_service(ofd, "getproplen", of__getproplen, 2, 1); |
1053 |
of_add_service(ofd, "instance-to-package", |
1054 |
of__instance_to_package, 1, 1); |
1055 |
of_add_service(ofd, "interpret", of__interpret_1, 1, 1); |
1056 |
of_add_service(ofd, "interpret", of__interpret_2, 1, 2); |
1057 |
of_add_service(ofd, "package-to-path", of__package_to_path, 3, 1); |
1058 |
of_add_service(ofd, "parent", of__parent, 1, 1); |
1059 |
of_add_service(ofd, "peer", of__peer, 1, 1); |
1060 |
of_add_service(ofd, "read", of__read, 3, 1); |
1061 |
of_add_service(ofd, "write", of__write, 3, 1); |
1062 |
|
1063 |
if (verbose >= 2) |
1064 |
of_dump_all(ofd); |
1065 |
|
1066 |
machine->md.of_data = ofd; |
1067 |
return ofd; |
1068 |
|
1069 |
bad: |
1070 |
fatal("of_emul_init(): out of memory\n"); |
1071 |
exit(1); |
1072 |
|
1073 |
return NULL; /* Silences a compiler warning */ |
1074 |
} |
1075 |
|
1076 |
|
1077 |
/* |
1078 |
* of_emul(): |
1079 |
* |
1080 |
* OpenFirmware call emulation. |
1081 |
*/ |
1082 |
int of_emul(struct cpu *cpu) |
1083 |
{ |
1084 |
int i, nargs, nret, ofs, retval = 0; |
1085 |
char service[50]; |
1086 |
char *arg[OF_N_MAX_ARGS]; |
1087 |
uint64_t base, ptr; |
1088 |
struct of_service *os; |
1089 |
struct of_data *of_data = cpu->machine->md.of_data; |
1090 |
|
1091 |
if (of_data == NULL) { |
1092 |
fatal("of_emul(): no of_data struct?\n"); |
1093 |
exit(1); |
1094 |
} |
1095 |
|
1096 |
/* |
1097 |
* The first argument register points to "prom_args": |
1098 |
* |
1099 |
* char *service; (probably 32 bit) |
1100 |
* int nargs; |
1101 |
* int nret; |
1102 |
* char *args[10]; |
1103 |
*/ |
1104 |
|
1105 |
switch (cpu->machine->arch) { |
1106 |
case ARCH_ARM: |
1107 |
base = cpu->cd.arm.r[0]; |
1108 |
break; |
1109 |
case ARCH_PPC: |
1110 |
base = cpu->cd.ppc.gpr[3]; |
1111 |
break; |
1112 |
default:fatal("of_emul(): unimplemented arch (TODO)\n"); |
1113 |
exit(1); |
1114 |
} |
1115 |
|
1116 |
/* TODO: how about 64-bit OpenFirmware? */ |
1117 |
ptr = load_32bit_word(cpu, base); |
1118 |
nargs = load_32bit_word(cpu, base + 4); |
1119 |
nret = load_32bit_word(cpu, base + 8); |
1120 |
|
1121 |
readstr(cpu, ptr, service, sizeof(service)); |
1122 |
|
1123 |
debug("[ of: %s(", service); |
1124 |
ofs = 12; |
1125 |
for (i=0; i<nargs; i++) { |
1126 |
int x; |
1127 |
if (i > 0) |
1128 |
debug(", "); |
1129 |
if (i >= OF_N_MAX_ARGS) { |
1130 |
fatal("TOO MANY ARGS!"); |
1131 |
continue; |
1132 |
} |
1133 |
ptr = load_32bit_word(cpu, base + ofs); |
1134 |
arg[i] = malloc(OF_ARG_MAX_LEN + 1); |
1135 |
if (arg[i] == NULL) { |
1136 |
fatal("out of memory\n"); |
1137 |
exit(1); |
1138 |
} |
1139 |
memset(arg[i], 0, OF_ARG_MAX_LEN + 1); |
1140 |
x = ptr; |
1141 |
if (x > -256 && x < 256) { |
1142 |
debug("%i", x); |
1143 |
} else { |
1144 |
readstr(cpu, ptr, arg[i], OF_ARG_MAX_LEN); |
1145 |
if (arg[i][0]) |
1146 |
debug("\"%s\"", arg[i]); |
1147 |
else |
1148 |
debug("0x%x", x); |
1149 |
} |
1150 |
ofs += sizeof(uint32_t); |
1151 |
} |
1152 |
debug(") ]\n"); |
1153 |
|
1154 |
/* Note: base + ofs points to the first return slot. */ |
1155 |
|
1156 |
os = of_data->of_services; |
1157 |
while (os != NULL) { |
1158 |
if (strcmp(service, os->name) == 0 && |
1159 |
nargs == os->n_args && nret == os->n_ret_args) { |
1160 |
retval = os->f(cpu, arg, base, ofs); |
1161 |
break; |
1162 |
} |
1163 |
os = os->next; |
1164 |
} |
1165 |
|
1166 |
if (os == NULL) { |
1167 |
quiet_mode = 0; |
1168 |
cpu_register_dump(cpu->machine, cpu, 1, 0); |
1169 |
printf("\n"); |
1170 |
fatal("[ of: unimplemented service \"%s\" with %i input " |
1171 |
"args and %i output values ]\n", service, nargs, nret); |
1172 |
cpu->running = 0; |
1173 |
} |
1174 |
|
1175 |
for (i=0; i<nargs; i++) |
1176 |
free(arg[i]); |
1177 |
|
1178 |
/* Return: */ |
1179 |
switch (cpu->machine->arch) { |
1180 |
case ARCH_ARM: |
1181 |
cpu->cd.arm.r[0] = retval; |
1182 |
break; |
1183 |
case ARCH_PPC: |
1184 |
cpu->cd.ppc.gpr[3] = retval; |
1185 |
break; |
1186 |
default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n"); |
1187 |
exit(1); |
1188 |
} |
1189 |
|
1190 |
return 1; |
1191 |
} |
1192 |
|