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