1 |
dpavlin |
14 |
/* |
2 |
dpavlin |
34 |
* Copyright (C) 2005-2007 Anders Gavare. All rights reserved. |
3 |
dpavlin |
14 |
* |
4 |
|
|
* Redistribution and use in source and binary forms, with or without |
5 |
|
|
* modification, are permitted provided that the following conditions are met: |
6 |
|
|
* |
7 |
|
|
* 1. Redistributions of source code must retain the above copyright |
8 |
|
|
* notice, this list of conditions and the following disclaimer. |
9 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
10 |
|
|
* notice, this list of conditions and the following disclaimer in the |
11 |
|
|
* documentation and/or other materials provided with the distribution. |
12 |
|
|
* 3. The name of the author may not be used to endorse or promote products |
13 |
|
|
* derived from this software without specific prior written permission. |
14 |
|
|
* |
15 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 |
|
|
* SUCH DAMAGE. |
26 |
|
|
* |
27 |
|
|
* |
28 |
dpavlin |
44 |
* $Id: of.c,v 1.25 2007/06/17 23:32:20 debug Exp $ |
29 |
dpavlin |
14 |
* |
30 |
dpavlin |
44 |
* COMMENT: OpenFirmware emulation |
31 |
dpavlin |
14 |
* |
32 |
dpavlin |
22 |
* NOTE: OpenFirmware is used on quite a variety of different hardware archs, |
33 |
|
|
* at least POWER/PowerPC, ARM, and SPARC, so the code in this module |
34 |
|
|
* must always remain architecture agnostic. |
35 |
|
|
* |
36 |
|
|
* NOTE: Some things, e.g. 32-bit integers as returned by the "getprop" |
37 |
|
|
* service, are always fixed to big-endian. (According to the standard.) |
38 |
|
|
* |
39 |
|
|
* TODO: o) 64-bit OpenFirmware? |
40 |
|
|
* o) More devices... |
41 |
dpavlin |
14 |
*/ |
42 |
|
|
|
43 |
|
|
#include <stdio.h> |
44 |
|
|
#include <stdlib.h> |
45 |
|
|
#include <string.h> |
46 |
|
|
#include <sys/types.h> |
47 |
|
|
|
48 |
dpavlin |
22 |
#define OF_C |
49 |
|
|
|
50 |
dpavlin |
14 |
#include "console.h" |
51 |
|
|
#include "cpu.h" |
52 |
dpavlin |
22 |
#include "device.h" |
53 |
|
|
#include "devices.h" |
54 |
|
|
#include "diskimage.h" |
55 |
dpavlin |
14 |
#include "machine.h" |
56 |
|
|
#include "memory.h" |
57 |
|
|
#include "misc.h" |
58 |
dpavlin |
22 |
#include "of.h" |
59 |
dpavlin |
14 |
|
60 |
|
|
|
61 |
dpavlin |
22 |
/* #define debug fatal */ |
62 |
dpavlin |
14 |
|
63 |
|
|
extern int quiet_mode; |
64 |
dpavlin |
22 |
extern int verbose; |
65 |
dpavlin |
14 |
|
66 |
|
|
|
67 |
|
|
/* |
68 |
|
|
* readstr(): |
69 |
|
|
* |
70 |
|
|
* Helper function to read a string from emulated memory. |
71 |
|
|
*/ |
72 |
|
|
static void readstr(struct cpu *cpu, uint64_t addr, char *strbuf, |
73 |
|
|
int bufsize) |
74 |
|
|
{ |
75 |
|
|
int i; |
76 |
|
|
for (i=0; i<bufsize; i++) { |
77 |
|
|
unsigned char ch; |
78 |
|
|
cpu->memory_rw(cpu, cpu->mem, addr + i, |
79 |
|
|
&ch, sizeof(ch), MEM_READ, CACHE_DATA | NO_EXCEPTIONS); |
80 |
|
|
strbuf[i] = '\0'; |
81 |
|
|
if (ch >= 1 && ch < 32) |
82 |
|
|
ch = 0; |
83 |
|
|
strbuf[i] = ch; |
84 |
|
|
if (strbuf[i] == '\0') |
85 |
|
|
break; |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
strbuf[bufsize - 1] = '\0'; |
89 |
|
|
} |
90 |
|
|
|
91 |
|
|
|
92 |
|
|
/* |
93 |
dpavlin |
22 |
* of_store_32bit_in_host(): |
94 |
|
|
* |
95 |
|
|
* Store big-endian. OpenFirmware properties returned by getprop etc are |
96 |
|
|
* always big-endian, even on little-endian machines. |
97 |
|
|
*/ |
98 |
|
|
static void of_store_32bit_in_host(unsigned char *d, uint32_t x) |
99 |
|
|
{ |
100 |
|
|
d[0] = x >> 24; d[1] = x >> 16; |
101 |
|
|
d[2] = x >> 8; d[3] = x; |
102 |
|
|
} |
103 |
|
|
|
104 |
|
|
|
105 |
|
|
/* |
106 |
|
|
* find_device_handle(): |
107 |
|
|
* |
108 |
|
|
* name may consist of multiple names, separaed with slashes. |
109 |
|
|
*/ |
110 |
|
|
static int find_device_handle(struct of_data *ofd, char *name) |
111 |
|
|
{ |
112 |
|
|
int handle = 1, cur_parent = 1; |
113 |
|
|
|
114 |
|
|
if (name[0] == 0) |
115 |
|
|
return 0; |
116 |
|
|
|
117 |
|
|
for (;;) { |
118 |
|
|
struct of_device *od = ofd->of_devices; |
119 |
|
|
char tmp[200]; |
120 |
|
|
int i; |
121 |
|
|
|
122 |
|
|
while (name[0] == '/') |
123 |
|
|
name++; |
124 |
|
|
if (name[0] == '\0') |
125 |
|
|
break; |
126 |
|
|
snprintf(tmp, sizeof(tmp), "%s", name); |
127 |
|
|
i = 0; |
128 |
|
|
while (tmp[i] != '\0' && tmp[i] != '/') |
129 |
|
|
i++; |
130 |
|
|
tmp[i] = '\0'; |
131 |
|
|
|
132 |
|
|
OF_FIND(od, strcmp(od->name, tmp) == 0 && |
133 |
|
|
od->parent == cur_parent); |
134 |
|
|
if (od == NULL) |
135 |
|
|
return -1; |
136 |
|
|
|
137 |
|
|
handle = cur_parent = od->handle; |
138 |
|
|
name += strlen(tmp); |
139 |
|
|
} |
140 |
|
|
|
141 |
|
|
return handle; |
142 |
|
|
} |
143 |
|
|
|
144 |
|
|
|
145 |
|
|
/*****************************************************************************/ |
146 |
|
|
|
147 |
|
|
|
148 |
|
|
OF_SERVICE(call_method_2_2) |
149 |
|
|
{ |
150 |
|
|
fatal("[ of: call_method_2_2('%s'): TODO ]\n", arg[0]); |
151 |
|
|
return -1; |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
|
155 |
|
|
OF_SERVICE(call_method_3_4) |
156 |
|
|
{ |
157 |
|
|
fatal("[ of: call_method_3_4('%s'): TODO ]\n", arg[0]); |
158 |
|
|
return -1; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
|
162 |
|
|
OF_SERVICE(call_method_5_2) |
163 |
|
|
{ |
164 |
|
|
if (strcmp(arg[0], "set-colors") == 0) { |
165 |
|
|
/* Used by OpenBSD/macppc: */ |
166 |
dpavlin |
34 |
struct vfb_data *v = cpu->machine->md.of_data->vfb_data; |
167 |
dpavlin |
22 |
int color = OF_GET_ARG(3); |
168 |
|
|
uint64_t ptr = OF_GET_ARG(4); |
169 |
|
|
unsigned char rgb[3]; |
170 |
|
|
cpu->memory_rw(cpu, cpu->mem, ptr, rgb, 3, MEM_READ, |
171 |
|
|
CACHE_DATA | NO_EXCEPTIONS); |
172 |
|
|
if (v != NULL) { |
173 |
|
|
memcpy(v->rgb_palette + 3 * color, rgb, 3); |
174 |
|
|
v->update_x1 = v->update_y1 = 0; |
175 |
|
|
v->update_x2 = v->xsize - 1; |
176 |
|
|
v->update_y2 = v->ysize - 1; |
177 |
|
|
} |
178 |
|
|
} else { |
179 |
|
|
fatal("[ of: call_method_5_2('%s'): TODO ]\n", arg[0]); |
180 |
|
|
return -1; |
181 |
|
|
} |
182 |
|
|
return 0; |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
|
186 |
|
|
OF_SERVICE(call_method_6_1) |
187 |
|
|
{ |
188 |
|
|
fatal("[ of: call_method_6_1('%s'): TODO ]\n", arg[0]); |
189 |
|
|
return -1; |
190 |
|
|
} |
191 |
|
|
|
192 |
|
|
|
193 |
|
|
OF_SERVICE(call_method_6_2) |
194 |
|
|
{ |
195 |
|
|
fatal("[ of: call_method_6_2('%s'): TODO ]\n", arg[0]); |
196 |
|
|
return -1; |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
|
200 |
|
|
OF_SERVICE(child) |
201 |
|
|
{ |
202 |
dpavlin |
34 |
struct of_device *od = cpu->machine->md.of_data->of_devices; |
203 |
dpavlin |
22 |
int handle = OF_GET_ARG(0); |
204 |
|
|
OF_FIND(od, od->parent == handle); |
205 |
|
|
store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->handle); |
206 |
|
|
return 0; |
207 |
|
|
} |
208 |
|
|
|
209 |
|
|
|
210 |
|
|
OF_SERVICE(exit) |
211 |
|
|
{ |
212 |
|
|
cpu->running = 0; |
213 |
|
|
return 0; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
|
217 |
|
|
OF_SERVICE(finddevice) |
218 |
|
|
{ |
219 |
dpavlin |
34 |
int h = find_device_handle(cpu->machine->md.of_data, arg[0]); |
220 |
dpavlin |
22 |
store_32bit_word(cpu, base + retofs, h); |
221 |
|
|
return h>0? 0 : -1; |
222 |
|
|
} |
223 |
|
|
|
224 |
|
|
|
225 |
|
|
OF_SERVICE(getprop) |
226 |
|
|
{ |
227 |
dpavlin |
34 |
struct of_device *od = cpu->machine->md.of_data->of_devices; |
228 |
dpavlin |
22 |
struct of_device_property *pr; |
229 |
|
|
int handle = OF_GET_ARG(0), i, len_returned = 0; |
230 |
|
|
uint64_t buf = OF_GET_ARG(2); |
231 |
|
|
uint64_t max = OF_GET_ARG(3); |
232 |
|
|
|
233 |
|
|
OF_FIND(od, od->handle == handle); |
234 |
|
|
if (od == NULL) { |
235 |
|
|
fatal("[ of: WARNING: getprop handle=%i; no such handle ]\n", |
236 |
|
|
handle); |
237 |
|
|
return -1; |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
pr = od->properties; |
241 |
|
|
OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); |
242 |
|
|
if (pr == NULL) { |
243 |
|
|
fatal("[ of: WARNING: getprop: no property '%s' at handle" |
244 |
|
|
" %i (device '%s') ]\n", arg[1], handle, od->name); |
245 |
|
|
/* exit(1); */ |
246 |
|
|
return -1; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
|
if (pr->data == NULL) { |
250 |
|
|
fatal("[ of: WARNING: property '%s' of '%s' has no data! ]\n", |
251 |
|
|
arg[1], od->name); |
252 |
|
|
goto ret; |
253 |
|
|
} |
254 |
|
|
|
255 |
|
|
/* Return the property into emulated RAM: */ |
256 |
|
|
len_returned = pr->len <= max? pr->len : max; |
257 |
|
|
|
258 |
|
|
for (i=0; i<len_returned; i++) { |
259 |
|
|
if (!cpu->memory_rw(cpu, cpu->mem, buf + i, pr->data + i, |
260 |
|
|
1, MEM_WRITE, CACHE_DATA | NO_EXCEPTIONS)) { |
261 |
|
|
fatal("[ of: getprop memory_rw() error ]\n"); |
262 |
|
|
exit(1); |
263 |
|
|
} |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
ret: |
267 |
|
|
store_32bit_word(cpu, base + retofs, len_returned); |
268 |
|
|
return 0; |
269 |
|
|
} |
270 |
|
|
|
271 |
|
|
|
272 |
|
|
OF_SERVICE(getproplen) |
273 |
|
|
{ |
274 |
dpavlin |
34 |
struct of_device *od = cpu->machine->md.of_data->of_devices; |
275 |
dpavlin |
22 |
struct of_device_property *pr; |
276 |
|
|
int handle = OF_GET_ARG(0); |
277 |
|
|
|
278 |
|
|
OF_FIND(od, od->handle == handle); |
279 |
|
|
if (od == NULL) { |
280 |
|
|
fatal("[ of: WARNING: getproplen handle=%i; no such handle ]\n", |
281 |
|
|
handle); |
282 |
|
|
exit(1); |
283 |
|
|
/* return -1; */ |
284 |
|
|
} |
285 |
|
|
|
286 |
|
|
pr = od->properties; |
287 |
|
|
OF_FIND(pr, strcmp(pr->name, arg[1]) == 0); |
288 |
|
|
if (pr == NULL) { |
289 |
|
|
fatal("[ of: WARNING: getproplen: no property '%s' at handle" |
290 |
|
|
" %i (device '%s') ]\n", arg[1], handle, od->name); |
291 |
|
|
exit(1); |
292 |
|
|
} |
293 |
|
|
|
294 |
|
|
store_32bit_word(cpu, base + retofs, pr->len); |
295 |
|
|
return 0; |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
|
299 |
|
|
OF_SERVICE(instance_to_package) |
300 |
|
|
{ |
301 |
|
|
int handle = OF_GET_ARG(0); |
302 |
|
|
/* TODO: actually do something here? :-) */ |
303 |
|
|
store_32bit_word(cpu, base + retofs, handle); |
304 |
|
|
return 0; |
305 |
|
|
} |
306 |
|
|
|
307 |
|
|
|
308 |
|
|
OF_SERVICE(interpret_1) |
309 |
|
|
{ |
310 |
|
|
if (strcmp(arg[0], "#lines 2 - to line#") == 0) { |
311 |
|
|
} else { |
312 |
|
|
fatal("[ of: interpret_1('%s'): TODO ]\n", arg[0]); |
313 |
|
|
return -1; |
314 |
|
|
} |
315 |
|
|
return 0; |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
|
319 |
|
|
OF_SERVICE(interpret_2) |
320 |
|
|
{ |
321 |
|
|
store_32bit_word(cpu, base + retofs, 0); /* ? TODO */ |
322 |
|
|
if (strcmp(arg[0], "#columns") == 0) { |
323 |
|
|
store_32bit_word(cpu, base + retofs + 4, 80); |
324 |
|
|
} else if (strcmp(arg[0], "#lines") == 0) { |
325 |
|
|
store_32bit_word(cpu, base + retofs + 4, 40); |
326 |
|
|
} else if (strcmp(arg[0], "char-height") == 0) { |
327 |
|
|
store_32bit_word(cpu, base + retofs + 4, 15); |
328 |
|
|
} else if (strcmp(arg[0], "char-width") == 0) { |
329 |
|
|
store_32bit_word(cpu, base + retofs + 4, 10); |
330 |
|
|
} else if (strcmp(arg[0], "line#") == 0) { |
331 |
|
|
store_32bit_word(cpu, base + retofs + 4, 0); |
332 |
|
|
} else if (strcmp(arg[0], "font-adr") == 0) { |
333 |
|
|
store_32bit_word(cpu, base + retofs + 4, 0); |
334 |
|
|
} else { |
335 |
|
|
fatal("[ of: interpret_2('%s'): TODO ]\n", arg[0]); |
336 |
|
|
return -1; |
337 |
|
|
} |
338 |
|
|
return 0; |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
|
342 |
|
|
OF_SERVICE(package_to_path) |
343 |
|
|
{ |
344 |
|
|
fatal("[ of: package-to-path: TODO ]\n"); |
345 |
|
|
return -1; |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
|
349 |
|
|
OF_SERVICE(parent) |
350 |
|
|
{ |
351 |
dpavlin |
34 |
struct of_device *od = cpu->machine->md.of_data->of_devices; |
352 |
dpavlin |
22 |
int handle = OF_GET_ARG(0); |
353 |
|
|
OF_FIND(od, od->handle == handle); |
354 |
|
|
store_32bit_word(cpu, base + retofs, od == NULL? 0 : od->parent); |
355 |
|
|
return 0; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
|
359 |
|
|
OF_SERVICE(peer) |
360 |
|
|
{ |
361 |
dpavlin |
34 |
struct of_device *od = cpu->machine->md.of_data->of_devices; |
362 |
dpavlin |
22 |
int handle = OF_GET_ARG(0), parent = 0, peer = 0, seen_self = 1; |
363 |
|
|
|
364 |
|
|
if (handle == 0) { |
365 |
|
|
/* Return the handle of the root node (1): */ |
366 |
|
|
store_32bit_word(cpu, base + retofs, 1); |
367 |
|
|
return 0; |
368 |
|
|
} |
369 |
|
|
|
370 |
|
|
OF_FIND(od, od->handle == handle); |
371 |
|
|
if (od == NULL) { |
372 |
|
|
fatal("[ of: peer(): can't find handle %i ]\n", handle); |
373 |
|
|
exit(1); |
374 |
|
|
} |
375 |
|
|
parent = od->parent; |
376 |
|
|
seen_self = 0; |
377 |
|
|
|
378 |
dpavlin |
34 |
od = cpu->machine->md.of_data->of_devices; |
379 |
dpavlin |
22 |
|
380 |
|
|
while (od != NULL) { |
381 |
|
|
if (od->parent == parent) { |
382 |
|
|
if (seen_self) { |
383 |
|
|
peer = od->handle; |
384 |
|
|
break; |
385 |
|
|
} |
386 |
|
|
if (od->handle == handle) |
387 |
|
|
seen_self = 1; |
388 |
|
|
} |
389 |
|
|
od = od->next; |
390 |
|
|
} |
391 |
|
|
store_32bit_word(cpu, base + retofs, peer); |
392 |
|
|
return 0; |
393 |
|
|
} |
394 |
|
|
|
395 |
|
|
|
396 |
|
|
OF_SERVICE(read) |
397 |
|
|
{ |
398 |
|
|
/* int handle = OF_GET_ARG(0); */ |
399 |
|
|
uint64_t ptr = OF_GET_ARG(1); |
400 |
|
|
/* int len = OF_GET_ARG(2); */ |
401 |
|
|
int c; |
402 |
|
|
unsigned char ch; |
403 |
|
|
|
404 |
|
|
/* TODO: check handle! This just reads chars from the console! */ |
405 |
|
|
/* TODO: This is blocking! */ |
406 |
|
|
|
407 |
|
|
c = console_readchar(cpu->machine->main_console_handle); |
408 |
|
|
ch = c; |
409 |
|
|
if (!cpu->memory_rw(cpu, cpu->mem, ptr, &ch, 1, MEM_WRITE, |
410 |
|
|
CACHE_DATA | NO_EXCEPTIONS)) { |
411 |
|
|
fatal("[ of: read: memory_rw() error ]\n"); |
412 |
|
|
exit(1); |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
store_32bit_word(cpu, base + retofs, c == -1? 0 : 1); |
416 |
|
|
return c == -1? -1 : 0; |
417 |
|
|
} |
418 |
|
|
|
419 |
|
|
|
420 |
|
|
OF_SERVICE(write) |
421 |
|
|
{ |
422 |
|
|
/* int handle = OF_GET_ARG(0); */ |
423 |
|
|
uint64_t ptr = OF_GET_ARG(1); |
424 |
|
|
int n_written = 0, i, len = OF_GET_ARG(2); |
425 |
|
|
|
426 |
|
|
/* TODO: check handle! This just dumps the data to the console! */ |
427 |
|
|
|
428 |
|
|
for (i=0; i<len; i++) { |
429 |
|
|
unsigned char ch; |
430 |
|
|
if (!cpu->memory_rw(cpu, cpu->mem, ptr + i, &ch, |
431 |
|
|
1, MEM_READ, CACHE_DATA | NO_EXCEPTIONS)) { |
432 |
|
|
fatal("[ of: write: memory_rw() error ]\n"); |
433 |
|
|
exit(1); |
434 |
|
|
} |
435 |
|
|
if (ch != 7) |
436 |
|
|
console_putchar(cpu->machine->main_console_handle, ch); |
437 |
|
|
n_written ++; |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
store_32bit_word(cpu, base + retofs, n_written); |
441 |
|
|
return 0; |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
|
445 |
|
|
/*****************************************************************************/ |
446 |
|
|
|
447 |
|
|
|
448 |
|
|
/* |
449 |
|
|
* of_get_unused_device_handle(): |
450 |
|
|
* |
451 |
|
|
* Returns an unused device handle number (1 or higher). |
452 |
|
|
*/ |
453 |
|
|
static int of_get_unused_device_handle(struct of_data *of_data) |
454 |
|
|
{ |
455 |
|
|
int max_handle = 0; |
456 |
|
|
struct of_device *od = of_data->of_devices; |
457 |
|
|
|
458 |
|
|
while (od != NULL) { |
459 |
|
|
if (od->handle > max_handle) |
460 |
|
|
max_handle = od->handle; |
461 |
|
|
od = od->next; |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
return max_handle + 1; |
465 |
|
|
} |
466 |
|
|
|
467 |
|
|
|
468 |
|
|
/* |
469 |
|
|
* of_add_device(): |
470 |
|
|
* |
471 |
|
|
* Adds a device. |
472 |
|
|
*/ |
473 |
|
|
static struct of_device *of_add_device(struct of_data *of_data, char *name, |
474 |
|
|
char *parentname) |
475 |
|
|
{ |
476 |
dpavlin |
42 |
struct of_device *od; |
477 |
|
|
|
478 |
|
|
CHECK_ALLOCATION(od = malloc(sizeof(struct of_device))); |
479 |
dpavlin |
22 |
memset(od, 0, sizeof(struct of_device)); |
480 |
|
|
|
481 |
dpavlin |
42 |
CHECK_ALLOCATION(od->name = strdup(name)); |
482 |
dpavlin |
22 |
|
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 |
dpavlin |
42 |
|
494 |
dpavlin |
22 |
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 |
dpavlin |
42 |
struct of_device_property *pr; |
507 |
dpavlin |
22 |
struct of_device *od = of_data->of_devices; |
508 |
|
|
int h = find_device_handle(of_data, devname); |
509 |
|
|
|
510 |
dpavlin |
42 |
CHECK_ALLOCATION(pr = malloc(sizeof(struct of_device_property))); |
511 |
|
|
memset(pr, 0, sizeof(struct of_device_property)); |
512 |
|
|
|
513 |
dpavlin |
22 |
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 |
dpavlin |
42 |
CHECK_ALLOCATION(pr->name = strdup(propname)); |
520 |
dpavlin |
22 |
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 |
dpavlin |
42 |
struct of_service *os; |
538 |
|
|
|
539 |
|
|
CHECK_ALLOCATION(os = malloc(sizeof(struct of_service))); |
540 |
dpavlin |
22 |
memset(os, 0, sizeof(struct of_service)); |
541 |
|
|
|
542 |
dpavlin |
42 |
CHECK_ALLOCATION(os->name = strdup(name)); |
543 |
dpavlin |
22 |
|
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 |
dpavlin |
42 |
unsigned char *p; |
637 |
|
|
|
638 |
|
|
CHECK_ALLOCATION(p = malloc(sizeof(int32_t))); |
639 |
|
|
|
640 |
dpavlin |
22 |
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 |
dpavlin |
42 |
char *p; |
655 |
dpavlin |
22 |
|
656 |
dpavlin |
42 |
CHECK_ALLOCATION(p = strdup(data)); |
657 |
|
|
|
658 |
dpavlin |
22 |
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 |
dpavlin |
34 |
struct of_data *ofd = machine->md.of_data; |
669 |
dpavlin |
22 |
unsigned char *isa_ranges; |
670 |
|
|
|
671 |
|
|
of_add_device(ofd, "isa", "/"); |
672 |
dpavlin |
42 |
|
673 |
|
|
CHECK_ALLOCATION(isa_ranges = malloc(32)); |
674 |
dpavlin |
22 |
memset(isa_ranges, 0, 32); |
675 |
dpavlin |
42 |
|
676 |
dpavlin |
22 |
/* 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 |
dpavlin |
34 |
struct of_data *ofd = machine->md.of_data; |
694 |
dpavlin |
22 |
unsigned char *adb_interrupts, *adb_reg; |
695 |
|
|
|
696 |
dpavlin |
42 |
CHECK_ALLOCATION(adb_interrupts = malloc(4 * sizeof(uint32_t))); |
697 |
|
|
CHECK_ALLOCATION(adb_reg = malloc(8 * sizeof(uint32_t))); |
698 |
dpavlin |
22 |
|
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 |
dpavlin |
34 |
struct of_data *ofd = machine->md.of_data; |
726 |
dpavlin |
22 |
unsigned char *zs_interrupts, *zs_reg; |
727 |
|
|
|
728 |
dpavlin |
42 |
CHECK_ALLOCATION(zs_reg = malloc(6 * sizeof(uint32_t))); |
729 |
dpavlin |
22 |
|
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 |
dpavlin |
42 |
CHECK_ALLOCATION(zs_interrupts = malloc(3 * sizeof(uint32_t))); |
744 |
|
|
CHECK_ALLOCATION(zs_reg = malloc(6 * sizeof(uint32_t))); |
745 |
dpavlin |
22 |
|
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 |
dpavlin |
42 |
CHECK_ALLOCATION(zs_interrupts = malloc(3 * sizeof(uint32_t))); |
764 |
|
|
CHECK_ALLOCATION(zs_reg = malloc(6 * sizeof(uint32_t))); |
765 |
dpavlin |
22 |
|
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 |
dpavlin |
34 |
struct of_data *ofd = machine->md.of_data; |
790 |
dpavlin |
22 |
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 |
dpavlin |
42 |
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 |
dpavlin |
22 |
|
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 |
dpavlin |
34 |
char tmpstr[400]; |
852 |
dpavlin |
22 |
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 |
dpavlin |
34 |
|
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 |
dpavlin |
22 |
} |
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 |
dpavlin |
42 |
struct of_data *ofd; |
895 |
dpavlin |
22 |
int i; |
896 |
|
|
|
897 |
dpavlin |
42 |
CHECK_ALLOCATION(ofd = malloc(sizeof(struct of_data))); |
898 |
dpavlin |
22 |
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 |
dpavlin |
42 |
if (machine->x11_md.in_use) { |
912 |
dpavlin |
22 |
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 |
dpavlin |
42 |
CHECK_ALLOCATION(zs_assigned_addresses = malloc(12)); |
927 |
dpavlin |
22 |
memset(zs_assigned_addresses, 0, 12); |
928 |
dpavlin |
42 |
|
929 |
dpavlin |
22 |
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 |
dpavlin |
42 |
CHECK_ALLOCATION(memory_reg = malloc(2 * sizeof(uint32_t))); |
966 |
|
|
CHECK_ALLOCATION(memory_av = malloc(2 * sizeof(uint32_t))); |
967 |
|
|
|
968 |
dpavlin |
22 |
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 |
dpavlin |
34 |
machine->md.of_data = ofd; |
1002 |
dpavlin |
42 |
|
1003 |
dpavlin |
22 |
return ofd; |
1004 |
|
|
} |
1005 |
|
|
|
1006 |
|
|
|
1007 |
|
|
/* |
1008 |
dpavlin |
14 |
* of_emul(): |
1009 |
|
|
* |
1010 |
|
|
* OpenFirmware call emulation. |
1011 |
|
|
*/ |
1012 |
|
|
int of_emul(struct cpu *cpu) |
1013 |
|
|
{ |
1014 |
dpavlin |
22 |
int i, nargs, nret, ofs, retval = 0; |
1015 |
dpavlin |
14 |
char service[50]; |
1016 |
dpavlin |
22 |
char *arg[OF_N_MAX_ARGS]; |
1017 |
dpavlin |
14 |
uint64_t base, ptr; |
1018 |
dpavlin |
22 |
struct of_service *os; |
1019 |
dpavlin |
34 |
struct of_data *of_data = cpu->machine->md.of_data; |
1020 |
dpavlin |
14 |
|
1021 |
dpavlin |
22 |
if (of_data == NULL) { |
1022 |
|
|
fatal("of_emul(): no of_data struct?\n"); |
1023 |
|
|
exit(1); |
1024 |
|
|
} |
1025 |
|
|
|
1026 |
dpavlin |
14 |
/* |
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 |
dpavlin |
22 |
default:fatal("of_emul(): unimplemented arch (TODO)\n"); |
1043 |
dpavlin |
14 |
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 |
dpavlin |
22 |
int x; |
1057 |
dpavlin |
14 |
if (i > 0) |
1058 |
|
|
debug(", "); |
1059 |
dpavlin |
22 |
if (i >= OF_N_MAX_ARGS) { |
1060 |
dpavlin |
14 |
fatal("TOO MANY ARGS!"); |
1061 |
|
|
continue; |
1062 |
|
|
} |
1063 |
dpavlin |
42 |
|
1064 |
dpavlin |
14 |
ptr = load_32bit_word(cpu, base + ofs); |
1065 |
dpavlin |
42 |
|
1066 |
|
|
CHECK_ALLOCATION(arg[i] = malloc(OF_ARG_MAX_LEN + 1)); |
1067 |
dpavlin |
22 |
memset(arg[i], 0, OF_ARG_MAX_LEN + 1); |
1068 |
dpavlin |
42 |
|
1069 |
dpavlin |
22 |
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 |
dpavlin |
14 |
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 |
dpavlin |
22 |
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 |
dpavlin |
14 |
} |
1092 |
dpavlin |
22 |
os = os->next; |
1093 |
|
|
} |
1094 |
dpavlin |
14 |
|
1095 |
dpavlin |
22 |
if (os == NULL) { |
1096 |
dpavlin |
14 |
quiet_mode = 0; |
1097 |
|
|
cpu_register_dump(cpu->machine, cpu, 1, 0); |
1098 |
|
|
printf("\n"); |
1099 |
dpavlin |
22 |
fatal("[ of: unimplemented service \"%s\" with %i input " |
1100 |
|
|
"args and %i output values ]\n", service, nargs, nret); |
1101 |
dpavlin |
14 |
cpu->running = 0; |
1102 |
|
|
} |
1103 |
|
|
|
1104 |
dpavlin |
22 |
for (i=0; i<nargs; i++) |
1105 |
|
|
free(arg[i]); |
1106 |
|
|
|
1107 |
|
|
/* Return: */ |
1108 |
dpavlin |
14 |
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 |
dpavlin |
22 |
default:fatal("of_emul(): TODO: unimplemented arch (Retval)\n"); |
1116 |
dpavlin |
14 |
exit(1); |
1117 |
|
|
} |
1118 |
|
|
|
1119 |
|
|
return 1; |
1120 |
|
|
} |
1121 |
|
|
|