1 |
dpavlin |
2 |
/* |
2 |
|
|
* Copyright (C) 2003-2005 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: arcbios.c,v 1.96 2005/03/20 11:11:39 debug Exp $ |
29 |
|
|
* |
30 |
|
|
* ARCBIOS emulation. |
31 |
|
|
* |
32 |
|
|
* This whole file is a mess. |
33 |
|
|
* |
34 |
|
|
* TODO: Fix. |
35 |
|
|
* |
36 |
|
|
* TODO: FACTOR OUT COMMON PARTS OF THE 64-bit and 32-bit stuff!! |
37 |
|
|
*/ |
38 |
|
|
|
39 |
|
|
#include <stdio.h> |
40 |
|
|
#include <stdlib.h> |
41 |
|
|
#include <string.h> |
42 |
|
|
#include <time.h> |
43 |
|
|
#include <unistd.h> |
44 |
|
|
#include <sys/time.h> |
45 |
|
|
#include <sys/types.h> |
46 |
|
|
#include <sys/resource.h> |
47 |
|
|
|
48 |
|
|
#include "arcbios.h" |
49 |
|
|
#include "console.h" |
50 |
|
|
#include "cpu.h" |
51 |
|
|
#include "cpu_mips.h" |
52 |
|
|
#include "diskimage.h" |
53 |
|
|
#include "machine.h" |
54 |
|
|
#include "memory.h" |
55 |
|
|
#include "misc.h" |
56 |
|
|
|
57 |
|
|
|
58 |
|
|
extern int quiet_mode; |
59 |
|
|
|
60 |
|
|
|
61 |
|
|
/* |
62 |
|
|
* TODO: all this should be _per machine_! |
63 |
|
|
*/ |
64 |
|
|
|
65 |
|
|
/* Configuration data: */ |
66 |
|
|
#define MAX_CONFIG_DATA 50 |
67 |
|
|
static int n_configuration_data = 0; |
68 |
|
|
static uint64_t configuration_data_next_addr = ARC_CONFIG_DATA_ADDR; |
69 |
|
|
static uint64_t configuration_data_component[MAX_CONFIG_DATA]; |
70 |
|
|
static int configuration_data_len[MAX_CONFIG_DATA]; |
71 |
|
|
static uint64_t configuration_data_configdata[MAX_CONFIG_DATA]; |
72 |
|
|
|
73 |
|
|
static int arc_64bit = 0; /* For some SGI modes */ |
74 |
|
|
static int arc_wordlen = sizeof(uint32_t); |
75 |
|
|
|
76 |
|
|
static uint64_t scsicontroller = 0; |
77 |
|
|
|
78 |
|
|
static int arc_n_memdescriptors = 0; |
79 |
|
|
static uint64_t arcbios_memdescriptor_base = ARC_MEMDESC_ADDR; |
80 |
|
|
|
81 |
|
|
static uint64_t arcbios_next_component_address = FIRST_ARC_COMPONENT; |
82 |
|
|
static int n_arc_components = 0; |
83 |
|
|
|
84 |
|
|
static uint64_t arcbios_console_vram = 0; |
85 |
|
|
static uint64_t arcbios_console_ctrlregs = 0; |
86 |
|
|
#define MAX_ESC 16 |
87 |
|
|
static char arcbios_escape_sequence[MAX_ESC+1]; |
88 |
|
|
static int arcbios_in_escape_sequence; |
89 |
|
|
static int arcbios_console_maxx, arcbios_console_maxy; |
90 |
|
|
int arcbios_console_curx = 0, arcbios_console_cury = 0; |
91 |
|
|
static int arcbios_console_reverse = 0; |
92 |
|
|
int arcbios_console_curcolor = 0x1f; |
93 |
|
|
|
94 |
|
|
/* Open file handles: */ |
95 |
|
|
#define MAX_OPEN_STRINGLEN 200 |
96 |
|
|
#define MAX_HANDLES 10 |
97 |
|
|
static int file_handle_in_use[MAX_HANDLES]; |
98 |
|
|
static unsigned char *file_handle_string[MAX_HANDLES]; |
99 |
|
|
static uint64_t arcbios_current_seek_offset[MAX_HANDLES]; |
100 |
|
|
|
101 |
|
|
#define MAX_STRING_TO_COMPONENT 20 |
102 |
|
|
static char *arcbios_string_to_component[MAX_STRING_TO_COMPONENT]; |
103 |
|
|
static uint64_t arcbios_string_to_component_value[MAX_STRING_TO_COMPONENT]; |
104 |
|
|
static int arcbios_n_string_to_components = 0; |
105 |
|
|
|
106 |
|
|
|
107 |
|
|
/* |
108 |
|
|
* arcbios_add_string_to_component(): |
109 |
|
|
*/ |
110 |
|
|
void arcbios_add_string_to_component(char *string, uint64_t component) |
111 |
|
|
{ |
112 |
|
|
if (arcbios_n_string_to_components >= MAX_STRING_TO_COMPONENT) { |
113 |
|
|
printf("Too many string-to-component mappings.\n"); |
114 |
|
|
exit(1); |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
arcbios_string_to_component[arcbios_n_string_to_components] = |
118 |
|
|
strdup(string); |
119 |
|
|
if (arcbios_string_to_component[arcbios_n_string_to_components] == |
120 |
|
|
NULL) { |
121 |
|
|
fprintf(stderr, "out of memory in " |
122 |
|
|
"arcbios_add_string_to_component()\n"); |
123 |
|
|
exit(1); |
124 |
|
|
} |
125 |
|
|
debug("adding ARC component mapping: 0x%08x = %s\n", |
126 |
|
|
(int)component, string); |
127 |
|
|
|
128 |
|
|
arcbios_string_to_component_value[arcbios_n_string_to_components] = |
129 |
|
|
component; |
130 |
|
|
arcbios_n_string_to_components ++; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
|
134 |
|
|
/* |
135 |
|
|
* arcbios_get_dsp_stat(): |
136 |
|
|
* |
137 |
|
|
* Fills in an arcbios_dsp_stat struct with valid data. |
138 |
|
|
*/ |
139 |
|
|
void arcbios_get_dsp_stat(struct cpu *cpu, struct arcbios_dsp_stat *dspstat) |
140 |
|
|
{ |
141 |
|
|
memset(dspstat, 0, sizeof(struct arcbios_dsp_stat)); |
142 |
|
|
|
143 |
|
|
store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> |
144 |
|
|
CursorXPosition, arcbios_console_curx + 1); |
145 |
|
|
store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> |
146 |
|
|
CursorYPosition, arcbios_console_cury + 1); |
147 |
|
|
store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> |
148 |
|
|
CursorMaxXPosition, ARC_CONSOLE_MAX_X); |
149 |
|
|
store_16bit_word_in_host(cpu, (unsigned char *)&dspstat-> |
150 |
|
|
CursorMaxYPosition, ARC_CONSOLE_MAX_Y); |
151 |
|
|
dspstat->ForegroundColor = arcbios_console_curcolor; |
152 |
|
|
dspstat->HighIntensity = arcbios_console_curcolor ^ 0x08; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
|
156 |
|
|
/* |
157 |
|
|
* arcbios_putcell(): |
158 |
|
|
*/ |
159 |
|
|
static void arcbios_putcell(struct cpu *cpu, int ch, int x, int y) |
160 |
|
|
{ |
161 |
|
|
unsigned char buf[2]; |
162 |
|
|
buf[0] = ch; |
163 |
|
|
buf[1] = arcbios_console_curcolor; |
164 |
|
|
if (arcbios_console_reverse) |
165 |
|
|
buf[1] = ((buf[1] & 0x70) >> 4) | ((buf[1] & 7) << 4) |
166 |
|
|
| (buf[1] & 0x88); |
167 |
|
|
cpu->memory_rw(cpu, cpu->mem, arcbios_console_vram + |
168 |
|
|
2*(x + arcbios_console_maxx * y), |
169 |
|
|
&buf[0], sizeof(buf), MEM_WRITE, |
170 |
|
|
CACHE_NONE | PHYSICAL); |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
|
174 |
|
|
/* |
175 |
|
|
* arcbios_console_init(): |
176 |
|
|
* |
177 |
|
|
* Called from machine.c whenever an ARC-based machine is running with |
178 |
|
|
* a graphical VGA-style framebuffer, which can be used as console. |
179 |
|
|
*/ |
180 |
|
|
void arcbios_console_init(struct cpu *cpu, |
181 |
|
|
uint64_t vram, uint64_t ctrlregs, int maxx, int maxy) |
182 |
|
|
{ |
183 |
|
|
int x, y; |
184 |
|
|
|
185 |
|
|
arcbios_console_vram = vram; |
186 |
|
|
arcbios_console_ctrlregs = ctrlregs; |
187 |
|
|
arcbios_console_maxx = maxx; |
188 |
|
|
arcbios_console_maxy = maxy; |
189 |
|
|
arcbios_in_escape_sequence = 0; |
190 |
|
|
arcbios_escape_sequence[0] = '\0'; |
191 |
|
|
arcbios_console_curcolor = 0x1f; |
192 |
|
|
|
193 |
|
|
for (y=1; y<arcbios_console_maxy; y++) |
194 |
|
|
for (x=0; x<arcbios_console_maxx; x++) |
195 |
|
|
arcbios_putcell(cpu, ' ', x, y); |
196 |
|
|
|
197 |
|
|
arcbios_console_curx = 0; |
198 |
|
|
arcbios_console_cury = 1; |
199 |
|
|
} |
200 |
|
|
|
201 |
|
|
|
202 |
|
|
/* |
203 |
|
|
* handle_esc_seq(): |
204 |
|
|
* |
205 |
|
|
* Used by arcbios_putchar(). |
206 |
|
|
*/ |
207 |
|
|
static void handle_esc_seq(struct cpu *cpu) |
208 |
|
|
{ |
209 |
|
|
int i, len = strlen(arcbios_escape_sequence); |
210 |
|
|
int row, col, color, code, start, stop; |
211 |
|
|
char *p; |
212 |
|
|
|
213 |
|
|
if (arcbios_escape_sequence[0] != '[') |
214 |
|
|
return; |
215 |
|
|
|
216 |
|
|
code = arcbios_escape_sequence[len-1]; |
217 |
|
|
arcbios_escape_sequence[len-1] = '\0'; |
218 |
|
|
|
219 |
|
|
switch (code) { |
220 |
|
|
case 'm': |
221 |
|
|
color = atoi(arcbios_escape_sequence + 1); |
222 |
|
|
switch (color) { |
223 |
|
|
case 0: /* Default. */ |
224 |
|
|
arcbios_console_curcolor = 0x1f; |
225 |
|
|
arcbios_console_reverse = 0; break; |
226 |
|
|
case 1: /* "Bold". */ |
227 |
|
|
arcbios_console_curcolor |= 0x08; break; |
228 |
|
|
case 7: /* "Reverse". */ |
229 |
|
|
arcbios_console_reverse = 1; break; |
230 |
|
|
case 30: /* Black foreground. */ |
231 |
|
|
arcbios_console_curcolor &= 0xf0; |
232 |
|
|
arcbios_console_curcolor |= 0x00; break; |
233 |
|
|
case 31: /* Red foreground. */ |
234 |
|
|
arcbios_console_curcolor &= 0xf0; |
235 |
|
|
arcbios_console_curcolor |= 0x04; break; |
236 |
|
|
case 32: /* Green foreground. */ |
237 |
|
|
arcbios_console_curcolor &= 0xf0; |
238 |
|
|
arcbios_console_curcolor |= 0x02; break; |
239 |
|
|
case 33: /* Yellow foreground. */ |
240 |
|
|
arcbios_console_curcolor &= 0xf0; |
241 |
|
|
arcbios_console_curcolor |= 0x06; break; |
242 |
|
|
case 34: /* Blue foreground. */ |
243 |
|
|
arcbios_console_curcolor &= 0xf0; |
244 |
|
|
arcbios_console_curcolor |= 0x01; break; |
245 |
|
|
case 35: /* Red-blue foreground. */ |
246 |
|
|
arcbios_console_curcolor &= 0xf0; |
247 |
|
|
arcbios_console_curcolor |= 0x05; break; |
248 |
|
|
case 36: /* Green-blue foreground. */ |
249 |
|
|
arcbios_console_curcolor &= 0xf0; |
250 |
|
|
arcbios_console_curcolor |= 0x03; break; |
251 |
|
|
case 37: /* White foreground. */ |
252 |
|
|
arcbios_console_curcolor &= 0xf0; |
253 |
|
|
arcbios_console_curcolor |= 0x07; break; |
254 |
|
|
case 40: /* Black background. */ |
255 |
|
|
arcbios_console_curcolor &= 0x0f; |
256 |
|
|
arcbios_console_curcolor |= 0x00; break; |
257 |
|
|
case 41: /* Red background. */ |
258 |
|
|
arcbios_console_curcolor &= 0x0f; |
259 |
|
|
arcbios_console_curcolor |= 0x40; break; |
260 |
|
|
case 42: /* Green background. */ |
261 |
|
|
arcbios_console_curcolor &= 0x0f; |
262 |
|
|
arcbios_console_curcolor |= 0x20; break; |
263 |
|
|
case 43: /* Yellow background. */ |
264 |
|
|
arcbios_console_curcolor &= 0x0f; |
265 |
|
|
arcbios_console_curcolor |= 0x60; break; |
266 |
|
|
case 44: /* Blue background. */ |
267 |
|
|
arcbios_console_curcolor &= 0x0f; |
268 |
|
|
arcbios_console_curcolor |= 0x10; break; |
269 |
|
|
case 45: /* Red-blue background. */ |
270 |
|
|
arcbios_console_curcolor &= 0x0f; |
271 |
|
|
arcbios_console_curcolor |= 0x50; break; |
272 |
|
|
case 46: /* Green-blue background. */ |
273 |
|
|
arcbios_console_curcolor &= 0x0f; |
274 |
|
|
arcbios_console_curcolor |= 0x30; break; |
275 |
|
|
case 47: /* White background. */ |
276 |
|
|
arcbios_console_curcolor &= 0x0f; |
277 |
|
|
arcbios_console_curcolor |= 0x70; break; |
278 |
|
|
default:fatal("{ handle_esc_seq: color %i }\n", color); |
279 |
|
|
} |
280 |
|
|
return; |
281 |
|
|
case 'H': |
282 |
|
|
p = strchr(arcbios_escape_sequence, ';'); |
283 |
|
|
if (p == NULL) |
284 |
|
|
return; /* TODO */ |
285 |
|
|
row = atoi(arcbios_escape_sequence + 1); |
286 |
|
|
col = atoi(p + 1); |
287 |
|
|
if (col < 1) |
288 |
|
|
col = 1; |
289 |
|
|
if (row < 1) |
290 |
|
|
row = 1; |
291 |
|
|
arcbios_console_curx = col - 1; |
292 |
|
|
arcbios_console_cury = row - 1; |
293 |
|
|
return; |
294 |
|
|
case 'J': |
295 |
|
|
/* |
296 |
|
|
* J = clear screen below cursor, and the rest of the |
297 |
|
|
* current line, |
298 |
|
|
* 2J = clear whole screen. |
299 |
|
|
*/ |
300 |
|
|
i = atoi(arcbios_escape_sequence + 1); |
301 |
|
|
if (i != 0 && i != 2) |
302 |
|
|
fatal("{ handle_esc_seq(): %iJ }\n", i); |
303 |
|
|
if (i == 0) |
304 |
|
|
for (col = arcbios_console_curx; |
305 |
|
|
col < arcbios_console_maxx; col++) |
306 |
|
|
arcbios_putcell(cpu, ' ', col, |
307 |
|
|
arcbios_console_cury); |
308 |
|
|
for (col = 0; col < arcbios_console_maxx; col++) |
309 |
|
|
for (row = i? 0 : arcbios_console_cury+1; |
310 |
|
|
row < arcbios_console_maxy; row++) |
311 |
|
|
arcbios_putcell(cpu, ' ', col, row); |
312 |
|
|
return; |
313 |
|
|
case 'K': |
314 |
|
|
col = atoi(arcbios_escape_sequence + 1); |
315 |
|
|
/* 2 = clear line to the right. 1 = to the left (?) */ |
316 |
|
|
start = 0; stop = arcbios_console_curx; |
317 |
|
|
if (col == 2) { |
318 |
|
|
start = arcbios_console_curx; |
319 |
|
|
stop = arcbios_console_maxx-1; |
320 |
|
|
} |
321 |
|
|
for (i=start; i<=stop; i++) |
322 |
|
|
arcbios_putcell(cpu, ' ', i, arcbios_console_cury); |
323 |
|
|
|
324 |
|
|
return; |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
fatal("{ handle_esc_seq(): unimplemented escape sequence: "); |
328 |
|
|
for (i=0; i<len; i++) { |
329 |
|
|
int x = arcbios_escape_sequence[i]; |
330 |
|
|
if (i == len-1) |
331 |
|
|
x = code; |
332 |
|
|
|
333 |
|
|
if (x >= ' ' && x < 127) |
334 |
|
|
fatal("%c", x); |
335 |
|
|
else |
336 |
|
|
fatal("[0x%02x]", x); |
337 |
|
|
} |
338 |
|
|
fatal(" }\n"); |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
|
342 |
|
|
/* |
343 |
|
|
* scroll_if_necessary(): |
344 |
|
|
*/ |
345 |
|
|
static void scroll_if_necessary(struct cpu *cpu) |
346 |
|
|
{ |
347 |
|
|
/* Scroll? */ |
348 |
|
|
if (arcbios_console_cury >= arcbios_console_maxy) { |
349 |
|
|
unsigned char buf[2]; |
350 |
|
|
int x, y; |
351 |
|
|
for (y=0; y<arcbios_console_maxy-1; y++) |
352 |
|
|
for (x=0; x<arcbios_console_maxx; x++) { |
353 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
354 |
|
|
arcbios_console_vram + |
355 |
|
|
2*(x + arcbios_console_maxx * (y+1)), |
356 |
|
|
&buf[0], sizeof(buf), MEM_READ, |
357 |
|
|
CACHE_NONE | PHYSICAL); |
358 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
359 |
|
|
arcbios_console_vram + |
360 |
|
|
2*(x + arcbios_console_maxx * y), |
361 |
|
|
&buf[0], sizeof(buf), MEM_WRITE, |
362 |
|
|
CACHE_NONE | PHYSICAL); |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
arcbios_console_cury = arcbios_console_maxy - 1; |
366 |
|
|
|
367 |
|
|
for (x=0; x<arcbios_console_maxx; x++) |
368 |
|
|
arcbios_putcell(cpu, ' ', x, arcbios_console_cury); |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
|
373 |
|
|
/* |
374 |
|
|
* arcbios_putchar(): |
375 |
|
|
* |
376 |
|
|
* If we're using X11 with VGA-style console, then output to that console. |
377 |
|
|
* Otherwise, use console_putchar(). |
378 |
|
|
*/ |
379 |
|
|
static void arcbios_putchar(struct cpu *cpu, int ch) |
380 |
|
|
{ |
381 |
|
|
int addr; |
382 |
|
|
unsigned char byte; |
383 |
|
|
|
384 |
|
|
if (!cpu->machine->use_x11) { |
385 |
|
|
/* Text console output: */ |
386 |
|
|
|
387 |
|
|
/* Hack for Windows NT, which uses 0x9b instead of ESC + [ */ |
388 |
|
|
if (ch == 0x9b) { |
389 |
|
|
console_putchar(cpu->machine->main_console_handle, 27); |
390 |
|
|
ch = '['; |
391 |
|
|
} |
392 |
|
|
console_putchar(cpu->machine->main_console_handle, ch); |
393 |
|
|
return; |
394 |
|
|
} |
395 |
|
|
|
396 |
|
|
if (arcbios_in_escape_sequence) { |
397 |
|
|
int len = strlen(arcbios_escape_sequence); |
398 |
|
|
arcbios_escape_sequence[len] = ch; |
399 |
|
|
len++; |
400 |
|
|
if (len >= MAX_ESC) |
401 |
|
|
len = MAX_ESC; |
402 |
|
|
arcbios_escape_sequence[len] = '\0'; |
403 |
|
|
if ((ch >= 'a' && ch <= 'z') || |
404 |
|
|
(ch >= 'A' && ch <= 'Z') || len >= MAX_ESC) { |
405 |
|
|
handle_esc_seq(cpu); |
406 |
|
|
arcbios_in_escape_sequence = 0; |
407 |
|
|
} |
408 |
|
|
} else { |
409 |
|
|
if (ch == 27) { |
410 |
|
|
arcbios_in_escape_sequence = 1; |
411 |
|
|
arcbios_escape_sequence[0] = '\0'; |
412 |
|
|
} else if (ch == 0x9b) { |
413 |
|
|
arcbios_in_escape_sequence = 1; |
414 |
|
|
arcbios_escape_sequence[0] = '['; |
415 |
|
|
arcbios_escape_sequence[1] = '\0'; |
416 |
|
|
} else if (ch == '\b') { |
417 |
|
|
if (arcbios_console_curx > 0) |
418 |
|
|
arcbios_console_curx --; |
419 |
|
|
} else if (ch == '\r') { |
420 |
|
|
arcbios_console_curx = 0; |
421 |
|
|
} else if (ch == '\n') { |
422 |
|
|
arcbios_console_cury ++; |
423 |
|
|
} else if (ch == '\t') { |
424 |
|
|
arcbios_console_curx = |
425 |
|
|
((arcbios_console_curx - 1) | 7) + 1; |
426 |
|
|
/* TODO: Print spaces? */ |
427 |
|
|
} else { |
428 |
|
|
/* Put char: */ |
429 |
|
|
if (arcbios_console_curx >= arcbios_console_maxx) { |
430 |
|
|
arcbios_console_curx = 0; |
431 |
|
|
arcbios_console_cury ++; |
432 |
|
|
scroll_if_necessary(cpu); |
433 |
|
|
} |
434 |
|
|
arcbios_putcell(cpu, ch, arcbios_console_curx, |
435 |
|
|
arcbios_console_cury); |
436 |
|
|
arcbios_console_curx ++; |
437 |
|
|
} |
438 |
|
|
} |
439 |
|
|
|
440 |
|
|
scroll_if_necessary(cpu); |
441 |
|
|
|
442 |
|
|
/* Update cursor position: */ |
443 |
|
|
addr = (arcbios_console_curx >= arcbios_console_maxx? |
444 |
|
|
arcbios_console_maxx-1 : arcbios_console_curx) + |
445 |
|
|
arcbios_console_cury * arcbios_console_maxx; |
446 |
|
|
byte = 0x0e; |
447 |
|
|
cpu->memory_rw(cpu, cpu->mem, arcbios_console_ctrlregs + 0x14, |
448 |
|
|
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
449 |
|
|
byte = (addr >> 8) & 255; |
450 |
|
|
cpu->memory_rw(cpu, cpu->mem, arcbios_console_ctrlregs + 0x15, |
451 |
|
|
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
452 |
|
|
byte = 0x0f; |
453 |
|
|
cpu->memory_rw(cpu, cpu->mem, arcbios_console_ctrlregs + 0x14, |
454 |
|
|
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
455 |
|
|
byte = addr & 255; |
456 |
|
|
cpu->memory_rw(cpu, cpu->mem, arcbios_console_ctrlregs + 0x15, |
457 |
|
|
&byte, sizeof(byte), MEM_WRITE, CACHE_NONE | PHYSICAL); |
458 |
|
|
} |
459 |
|
|
|
460 |
|
|
|
461 |
|
|
/* |
462 |
|
|
* arcbios_register_scsicontroller(): |
463 |
|
|
*/ |
464 |
|
|
void arcbios_register_scsicontroller(uint64_t scsicontroller_component) |
465 |
|
|
{ |
466 |
|
|
scsicontroller = scsicontroller_component; |
467 |
|
|
} |
468 |
|
|
|
469 |
|
|
|
470 |
|
|
/* |
471 |
|
|
* arcbios_get_scsicontroller(): |
472 |
|
|
*/ |
473 |
|
|
uint64_t arcbios_get_scsicontroller(void) |
474 |
|
|
{ |
475 |
|
|
return scsicontroller; |
476 |
|
|
} |
477 |
|
|
|
478 |
|
|
|
479 |
|
|
/* |
480 |
|
|
* arcbios_add_memory_descriptor(): |
481 |
|
|
* |
482 |
|
|
* NOTE: arctype is the ARC type, not the SGI type. This function takes |
483 |
|
|
* care of converting, when necessary. |
484 |
|
|
*/ |
485 |
|
|
void arcbios_add_memory_descriptor(struct cpu *cpu, |
486 |
|
|
uint64_t base, uint64_t len, int arctype) |
487 |
|
|
{ |
488 |
|
|
uint64_t memdesc_addr; |
489 |
|
|
int s; |
490 |
|
|
struct arcbios_mem arcbios_mem; |
491 |
|
|
struct arcbios_mem64 arcbios_mem64; |
492 |
|
|
|
493 |
|
|
base /= 4096; |
494 |
|
|
len /= 4096; |
495 |
|
|
|
496 |
|
|
/* |
497 |
|
|
* TODO: Huh? Why isn't it necessary to convert from arc to sgi types? |
498 |
|
|
* |
499 |
|
|
* TODO 2: It seems that it _is_ neccessary, but NetBSD's arcdiag |
500 |
|
|
* doesn't handle the sgi case separately. |
501 |
|
|
*/ |
502 |
|
|
#if 1 |
503 |
|
|
if (cpu->machine->machine_type == MACHINE_SGI) { |
504 |
|
|
/* arctype is SGI style */ |
505 |
|
|
/* printf("%i => ", arctype); */ |
506 |
|
|
switch (arctype) { |
507 |
|
|
case 0: arctype = 0; break; |
508 |
|
|
case 1: arctype = 1; break; |
509 |
|
|
case 2: arctype = 3; break; |
510 |
|
|
case 3: arctype = 4; break; |
511 |
|
|
case 4: arctype = 5; break; |
512 |
|
|
case 5: arctype = 6; break; |
513 |
|
|
case 6: arctype = 7; break; |
514 |
|
|
case 7: arctype = 2; break; |
515 |
|
|
} |
516 |
|
|
/* printf("%i\n", arctype); */ |
517 |
|
|
} |
518 |
|
|
#endif |
519 |
|
|
if (arc_64bit) |
520 |
|
|
s = sizeof(arcbios_mem64); |
521 |
|
|
else |
522 |
|
|
s = sizeof(arcbios_mem); |
523 |
|
|
|
524 |
|
|
memdesc_addr = arcbios_memdescriptor_base + |
525 |
|
|
arc_n_memdescriptors * s; |
526 |
|
|
|
527 |
|
|
if (arc_64bit) { |
528 |
|
|
memset(&arcbios_mem64, 0, s); |
529 |
|
|
store_32bit_word_in_host(cpu, |
530 |
|
|
(unsigned char *)&arcbios_mem64.Type, arctype); |
531 |
|
|
store_64bit_word_in_host(cpu, |
532 |
|
|
(unsigned char *)&arcbios_mem64.BasePage, base); |
533 |
|
|
store_64bit_word_in_host(cpu, |
534 |
|
|
(unsigned char *)&arcbios_mem64.PageCount, len); |
535 |
|
|
store_buf(cpu, memdesc_addr, (char *)&arcbios_mem64, s); |
536 |
|
|
} else { |
537 |
|
|
memset(&arcbios_mem, 0, s); |
538 |
|
|
store_32bit_word_in_host(cpu, |
539 |
|
|
(unsigned char *)&arcbios_mem.Type, arctype); |
540 |
|
|
store_32bit_word_in_host(cpu, |
541 |
|
|
(unsigned char *)&arcbios_mem.BasePage, base); |
542 |
|
|
store_32bit_word_in_host(cpu, |
543 |
|
|
(unsigned char *)&arcbios_mem.PageCount, len); |
544 |
|
|
store_buf(cpu, memdesc_addr, (char *)&arcbios_mem, s); |
545 |
|
|
} |
546 |
|
|
|
547 |
|
|
arc_n_memdescriptors ++; |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
|
551 |
|
|
/* |
552 |
|
|
* arcbios_addchild(): |
553 |
|
|
* |
554 |
|
|
* host_tmp_component is a temporary component, with data formated for |
555 |
|
|
* the host system. It needs to be translated/copied into emulated RAM. |
556 |
|
|
* |
557 |
|
|
* Return value is the virtual (emulated) address of the added component. |
558 |
|
|
* |
559 |
|
|
* TODO: This function doesn't care about memory management, but simply |
560 |
|
|
* stores the new child after the last stored child. |
561 |
|
|
* TODO: This stuff is really ugly. |
562 |
|
|
*/ |
563 |
|
|
static uint64_t arcbios_addchild(struct cpu *cpu, |
564 |
|
|
struct arcbios_component *host_tmp_component, |
565 |
|
|
char *identifier, uint32_t parent) |
566 |
|
|
{ |
567 |
|
|
uint64_t a = arcbios_next_component_address; |
568 |
|
|
uint32_t peer=0; |
569 |
|
|
uint32_t child=0; |
570 |
|
|
int n_left; |
571 |
|
|
uint64_t peeraddr = FIRST_ARC_COMPONENT; |
572 |
|
|
|
573 |
|
|
/* |
574 |
|
|
* This component has no children yet, but it may have peers (that is, |
575 |
|
|
* other components that share this component's parent) so we have to |
576 |
|
|
* set the peer value correctly. |
577 |
|
|
* |
578 |
|
|
* Also, if this is the first child of some parent, the parent's child |
579 |
|
|
* pointer should be set to point to this component. (But only if it |
580 |
|
|
* is the first.) |
581 |
|
|
* |
582 |
|
|
* This is really ugly: scan through all components, starting from |
583 |
|
|
* FIRST_ARC_COMPONENT, to find a component with the same parent as |
584 |
|
|
* this component will have. If such a component is found, and its |
585 |
|
|
* 'peer' value is NULL, then set it to this component's address (a). |
586 |
|
|
* |
587 |
|
|
* TODO: make this nicer |
588 |
|
|
*/ |
589 |
|
|
|
590 |
|
|
n_left = n_arc_components; |
591 |
|
|
while (n_left > 0) { |
592 |
|
|
/* Load parent, child, and peer values: */ |
593 |
|
|
uint32_t eparent, echild, epeer, tmp; |
594 |
|
|
unsigned char buf[4]; |
595 |
|
|
|
596 |
|
|
/* debug("[ addchild: peeraddr = 0x%08x ]\n", |
597 |
|
|
(int)peeraddr); */ |
598 |
|
|
|
599 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
600 |
|
|
peeraddr + 0 * arc_wordlen, &buf[0], sizeof(eparent), |
601 |
|
|
MEM_READ, CACHE_NONE); |
602 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
603 |
|
|
unsigned char tmp; |
604 |
|
|
tmp = buf[0]; buf[0] = buf[3]; buf[3] = tmp; |
605 |
|
|
tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; |
606 |
|
|
} |
607 |
|
|
epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); |
608 |
|
|
|
609 |
|
|
cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * arc_wordlen, |
610 |
|
|
&buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); |
611 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
612 |
|
|
unsigned char tmp; tmp = buf[0]; |
613 |
|
|
buf[0] = buf[3]; buf[3] = tmp; |
614 |
|
|
tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; |
615 |
|
|
} |
616 |
|
|
echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); |
617 |
|
|
|
618 |
|
|
cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * arc_wordlen, |
619 |
|
|
&buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); |
620 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
621 |
|
|
unsigned char tmp; tmp = buf[0]; |
622 |
|
|
buf[0] = buf[3]; buf[3] = tmp; |
623 |
|
|
tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; |
624 |
|
|
} |
625 |
|
|
eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); |
626 |
|
|
|
627 |
|
|
/* debug(" epeer=%x echild=%x eparent=%x\n", |
628 |
|
|
(int)epeer,(int)echild,(int)eparent); */ |
629 |
|
|
|
630 |
|
|
if ((uint32_t)eparent == (uint32_t)parent && |
631 |
|
|
(uint32_t)epeer == 0) { |
632 |
|
|
epeer = a; |
633 |
|
|
store_32bit_word(cpu, peeraddr + 0x00, epeer); |
634 |
|
|
/* debug("[ addchild: adding 0x%08x as peer " |
635 |
|
|
"to 0x%08x ]\n", (int)a, (int)peeraddr); */ |
636 |
|
|
} |
637 |
|
|
if ((uint32_t)peeraddr == (uint32_t)parent && |
638 |
|
|
(uint32_t)echild == 0) { |
639 |
|
|
echild = a; |
640 |
|
|
store_32bit_word(cpu, peeraddr + 0x04, echild); |
641 |
|
|
/* debug("[ addchild: adding 0x%08x as " |
642 |
|
|
"child to 0x%08x ]\n", (int)a, (int)peeraddr); */ |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
/* Go to the next component: */ |
646 |
|
|
cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x28, &buf[0], |
647 |
|
|
sizeof(eparent), MEM_READ, CACHE_NONE); |
648 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
649 |
|
|
unsigned char tmp; tmp = buf[0]; |
650 |
|
|
buf[0] = buf[3]; buf[3] = tmp; |
651 |
|
|
tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; |
652 |
|
|
} |
653 |
|
|
tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); |
654 |
|
|
peeraddr += 0x30; |
655 |
|
|
peeraddr += tmp + 1; |
656 |
|
|
peeraddr = ((peeraddr - 1) | 3) + 1; |
657 |
|
|
|
658 |
|
|
n_left --; |
659 |
|
|
} |
660 |
|
|
|
661 |
|
|
store_32bit_word(cpu, a + 0x00, peer); |
662 |
|
|
store_32bit_word(cpu, a + 0x04, child); |
663 |
|
|
store_32bit_word(cpu, a + 0x08, parent); |
664 |
|
|
store_32bit_word(cpu, a+ 0x0c, host_tmp_component->Class); |
665 |
|
|
store_32bit_word(cpu, a+ 0x10, host_tmp_component->Type); |
666 |
|
|
store_32bit_word(cpu, a+ 0x14, host_tmp_component->Flags + |
667 |
|
|
65536 * host_tmp_component->Version); |
668 |
|
|
store_32bit_word(cpu, a+ 0x18, host_tmp_component->Revision); |
669 |
|
|
store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Key); |
670 |
|
|
store_32bit_word(cpu, a+ 0x20, host_tmp_component->AffinityMask); |
671 |
|
|
store_32bit_word(cpu, a+ 0x24, host_tmp_component-> |
672 |
|
|
ConfigurationDataSize); |
673 |
|
|
store_32bit_word(cpu, a+ 0x28, host_tmp_component->IdentifierLength); |
674 |
|
|
store_32bit_word(cpu, a+ 0x2c, host_tmp_component->Identifier); |
675 |
|
|
|
676 |
|
|
arcbios_next_component_address += 0x30; |
677 |
|
|
|
678 |
|
|
if (host_tmp_component->IdentifierLength != 0) { |
679 |
|
|
store_32bit_word(cpu, a + 0x2c, a + 0x30); |
680 |
|
|
store_string(cpu, a + 0x30, identifier); |
681 |
|
|
if (identifier != NULL) |
682 |
|
|
arcbios_next_component_address += |
683 |
|
|
strlen(identifier) + 1; |
684 |
|
|
} |
685 |
|
|
|
686 |
|
|
arcbios_next_component_address ++; |
687 |
|
|
|
688 |
|
|
/* Round up to next 0x4 bytes: */ |
689 |
|
|
arcbios_next_component_address = |
690 |
|
|
((arcbios_next_component_address - 1) | 3) + 1; |
691 |
|
|
|
692 |
|
|
n_arc_components ++; |
693 |
|
|
|
694 |
|
|
return a; |
695 |
|
|
} |
696 |
|
|
|
697 |
|
|
|
698 |
|
|
/* |
699 |
|
|
* arcbios_addchild64(): |
700 |
|
|
* |
701 |
|
|
* host_tmp_component is a temporary component, with data formated for |
702 |
|
|
* the host system. It needs to be translated/copied into emulated RAM. |
703 |
|
|
* |
704 |
|
|
* Return value is the virtual (emulated) address of the added component. |
705 |
|
|
* |
706 |
|
|
* TODO: This function doesn't care about memory management, but simply |
707 |
|
|
* stores the new child after the last stored child. |
708 |
|
|
* TODO: This stuff is really ugly. |
709 |
|
|
*/ |
710 |
|
|
static uint64_t arcbios_addchild64(struct cpu *cpu, |
711 |
|
|
struct arcbios_component64 *host_tmp_component, |
712 |
|
|
char *identifier, uint64_t parent) |
713 |
|
|
{ |
714 |
|
|
uint64_t a = arcbios_next_component_address; |
715 |
|
|
uint64_t peer=0; |
716 |
|
|
uint64_t child=0; |
717 |
|
|
int n_left; |
718 |
|
|
uint64_t peeraddr = FIRST_ARC_COMPONENT; |
719 |
|
|
|
720 |
|
|
/* |
721 |
|
|
* This component has no children yet, but it may have peers (that is, |
722 |
|
|
* other components that share this component's parent) so we have to |
723 |
|
|
* set the peer value correctly. |
724 |
|
|
* |
725 |
|
|
* Also, if this is the first child of some parent, the parent's child |
726 |
|
|
* pointer should be set to point to this component. (But only if it |
727 |
|
|
* is the first.) |
728 |
|
|
* |
729 |
|
|
* This is really ugly: scan through all components, starting from |
730 |
|
|
* FIRST_ARC_COMPONENT, to find a component with the same parent as |
731 |
|
|
* this component will have. If such a component is found, and its |
732 |
|
|
* 'peer' value is NULL, then set it to this component's address (a). |
733 |
|
|
* |
734 |
|
|
* TODO: make this nicer |
735 |
|
|
*/ |
736 |
|
|
|
737 |
|
|
n_left = n_arc_components; |
738 |
|
|
while (n_left > 0) { |
739 |
|
|
/* Load parent, child, and peer values: */ |
740 |
|
|
uint64_t eparent, echild, epeer, tmp; |
741 |
|
|
unsigned char buf[8]; |
742 |
|
|
|
743 |
|
|
/* debug("[ addchild: peeraddr = 0x%016llx ]\n", |
744 |
|
|
(long long)peeraddr); */ |
745 |
|
|
|
746 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
747 |
|
|
peeraddr + 0 * arc_wordlen, &buf[0], sizeof(eparent), |
748 |
|
|
MEM_READ, CACHE_NONE); |
749 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
750 |
|
|
unsigned char tmp; |
751 |
|
|
tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; |
752 |
|
|
tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; |
753 |
|
|
tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; |
754 |
|
|
tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; |
755 |
|
|
} |
756 |
|
|
epeer = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) |
757 |
|
|
+ ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) |
758 |
|
|
+ ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); |
759 |
|
|
|
760 |
|
|
cpu->memory_rw(cpu, cpu->mem, peeraddr + 1 * arc_wordlen, |
761 |
|
|
&buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); |
762 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
763 |
|
|
unsigned char tmp; |
764 |
|
|
tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; |
765 |
|
|
tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; |
766 |
|
|
tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; |
767 |
|
|
tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; |
768 |
|
|
} |
769 |
|
|
echild = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) |
770 |
|
|
+ ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) |
771 |
|
|
+ ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); |
772 |
|
|
|
773 |
|
|
cpu->memory_rw(cpu, cpu->mem, peeraddr + 2 * arc_wordlen, |
774 |
|
|
&buf[0], sizeof(eparent), MEM_READ, CACHE_NONE); |
775 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
776 |
|
|
unsigned char tmp; |
777 |
|
|
tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; |
778 |
|
|
tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; |
779 |
|
|
tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; |
780 |
|
|
tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; |
781 |
|
|
} |
782 |
|
|
eparent = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24) |
783 |
|
|
+ ((uint64_t)buf[4] << 32) + ((uint64_t)buf[5] << 40) |
784 |
|
|
+ ((uint64_t)buf[6] << 48) + ((uint64_t)buf[7] << 56); |
785 |
|
|
|
786 |
|
|
/* debug(" epeer=%llx echild=%llx eparent=%llx\n", |
787 |
|
|
(long long)epeer, (long long)echild, |
788 |
|
|
(long long)eparent); */ |
789 |
|
|
|
790 |
|
|
if (eparent == parent && epeer == 0) { |
791 |
|
|
epeer = a; |
792 |
|
|
store_64bit_word(cpu, peeraddr + 0 * arc_wordlen, |
793 |
|
|
epeer); |
794 |
|
|
/* debug("[ addchild: adding 0x%016llx as peer " |
795 |
|
|
"to 0x%016llx ]\n", (long long)a, |
796 |
|
|
(long long)peeraddr); */ |
797 |
|
|
} |
798 |
|
|
if (peeraddr == parent && echild == 0) { |
799 |
|
|
echild = a; |
800 |
|
|
store_64bit_word(cpu, peeraddr + 1 * arc_wordlen, |
801 |
|
|
echild); |
802 |
|
|
/* debug("[ addchild: adding 0x%016llx as child " |
803 |
|
|
"to 0x%016llx ]\n", (long long)a, |
804 |
|
|
(long long)peeraddr); */ |
805 |
|
|
} |
806 |
|
|
|
807 |
|
|
/* Go to the next component: */ |
808 |
|
|
cpu->memory_rw(cpu, cpu->mem, peeraddr + 0x34, |
809 |
|
|
&buf[0], sizeof(uint32_t), MEM_READ, CACHE_NONE); |
810 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
811 |
|
|
unsigned char tmp; |
812 |
|
|
tmp = buf[0]; buf[0] = buf[3]; buf[3] = tmp; |
813 |
|
|
tmp = buf[1]; buf[1] = buf[2]; buf[2] = tmp; |
814 |
|
|
} |
815 |
|
|
tmp = buf[0] + (buf[1]<<8) + (buf[2]<<16) + (buf[3]<<24); |
816 |
|
|
|
817 |
|
|
tmp &= 0xfffff; |
818 |
|
|
|
819 |
|
|
peeraddr += 0x50; |
820 |
|
|
peeraddr += tmp + 1; |
821 |
|
|
peeraddr = ((peeraddr - 1) | 3) + 1; |
822 |
|
|
|
823 |
|
|
n_left --; |
824 |
|
|
} |
825 |
|
|
|
826 |
|
|
store_64bit_word(cpu, a + 0x00, peer); |
827 |
|
|
store_64bit_word(cpu, a + 0x08, child); |
828 |
|
|
store_64bit_word(cpu, a + 0x10, parent); |
829 |
|
|
store_32bit_word(cpu, a+ 0x18, host_tmp_component->Class); |
830 |
|
|
store_32bit_word(cpu, a+ 0x1c, host_tmp_component->Type); |
831 |
|
|
store_32bit_word(cpu, a+ 0x20, host_tmp_component->Flags); |
832 |
|
|
store_32bit_word(cpu, a+ 0x24, host_tmp_component->Version + |
833 |
|
|
((uint64_t)host_tmp_component->Revision << 16)); |
834 |
|
|
store_32bit_word(cpu, a+ 0x28, host_tmp_component->Key); |
835 |
|
|
store_64bit_word(cpu, a+ 0x30, host_tmp_component->AffinityMask); |
836 |
|
|
store_64bit_word(cpu, a+ 0x38, host_tmp_component-> |
837 |
|
|
ConfigurationDataSize); |
838 |
|
|
store_64bit_word(cpu, a+ 0x40, host_tmp_component->IdentifierLength); |
839 |
|
|
store_64bit_word(cpu, a+ 0x48, host_tmp_component->Identifier); |
840 |
|
|
|
841 |
|
|
/* TODO: Find out how a REAL ARCS64 implementation does it. */ |
842 |
|
|
|
843 |
|
|
arcbios_next_component_address += 0x50; |
844 |
|
|
|
845 |
|
|
if (host_tmp_component->IdentifierLength != 0) { |
846 |
|
|
store_64bit_word(cpu, a + 0x48, a + 0x50); |
847 |
|
|
store_string(cpu, a + 0x50, identifier); |
848 |
|
|
if (identifier != NULL) |
849 |
|
|
arcbios_next_component_address += |
850 |
|
|
strlen(identifier) + 1; |
851 |
|
|
} |
852 |
|
|
|
853 |
|
|
arcbios_next_component_address ++; |
854 |
|
|
|
855 |
|
|
/* Round up to next 0x8 bytes: */ |
856 |
|
|
arcbios_next_component_address = |
857 |
|
|
((arcbios_next_component_address - 1) | 7) + 1; |
858 |
|
|
|
859 |
|
|
n_arc_components ++; |
860 |
|
|
return a; |
861 |
|
|
} |
862 |
|
|
|
863 |
|
|
|
864 |
|
|
/* |
865 |
|
|
* arcbios_addchild_manual(): |
866 |
|
|
* |
867 |
|
|
* Used internally to set up component structures. |
868 |
|
|
* Parent may only be NULL for the first (system) component. |
869 |
|
|
* |
870 |
|
|
* Return value is the virtual (emulated) address of the added component. |
871 |
|
|
*/ |
872 |
|
|
uint64_t arcbios_addchild_manual(struct cpu *cpu, |
873 |
|
|
uint64_t class, uint64_t type, uint64_t flags, |
874 |
|
|
uint64_t version, uint64_t revision, uint64_t key, |
875 |
|
|
uint64_t affinitymask, char *identifier, uint64_t parent, |
876 |
|
|
void *config_data, size_t config_len) |
877 |
|
|
{ |
878 |
|
|
/* This component is only for temporary use: */ |
879 |
|
|
struct arcbios_component component; |
880 |
|
|
struct arcbios_component64 component64; |
881 |
|
|
|
882 |
|
|
if (config_data != NULL) { |
883 |
|
|
unsigned char *p = config_data; |
884 |
|
|
int i; |
885 |
|
|
|
886 |
|
|
if (n_configuration_data >= MAX_CONFIG_DATA) { |
887 |
|
|
printf("fatal error: you need to increase " |
888 |
|
|
"MAX_CONFIG_DATA\n"); |
889 |
|
|
exit(1); |
890 |
|
|
} |
891 |
|
|
|
892 |
|
|
for (i=0; i<config_len; i++) { |
893 |
|
|
unsigned char ch = p[i]; |
894 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
895 |
|
|
configuration_data_next_addr + i, |
896 |
|
|
&ch, 1, MEM_WRITE, CACHE_NONE); |
897 |
|
|
} |
898 |
|
|
|
899 |
|
|
configuration_data_len[n_configuration_data] = config_len; |
900 |
|
|
configuration_data_configdata[n_configuration_data] = |
901 |
|
|
configuration_data_next_addr; |
902 |
|
|
configuration_data_next_addr += config_len; |
903 |
|
|
configuration_data_component[n_configuration_data] = |
904 |
|
|
arcbios_next_component_address + (arc_64bit? 0x18 : 0x0c); |
905 |
|
|
|
906 |
|
|
/* printf("& ADDING %i: configdata=0x%016llx " |
907 |
|
|
"component=0x%016llx\n", n_configuration_data, |
908 |
|
|
(long long)configuration_data_configdata[ |
909 |
|
|
n_configuration_data], |
910 |
|
|
(long long)configuration_data_component[ |
911 |
|
|
n_configuration_data]); */ |
912 |
|
|
|
913 |
|
|
n_configuration_data ++; |
914 |
|
|
} |
915 |
|
|
|
916 |
|
|
if (!arc_64bit) { |
917 |
|
|
component.Class = class; |
918 |
|
|
component.Type = type; |
919 |
|
|
component.Flags = flags; |
920 |
|
|
component.Version = version; |
921 |
|
|
component.Revision = revision; |
922 |
|
|
component.Key = key; |
923 |
|
|
component.AffinityMask = affinitymask; |
924 |
|
|
component.ConfigurationDataSize = config_len; |
925 |
|
|
component.IdentifierLength = 0; |
926 |
|
|
component.Identifier = 0; |
927 |
|
|
if (identifier != NULL) { |
928 |
|
|
component.IdentifierLength = strlen(identifier) + 1; |
929 |
|
|
} |
930 |
|
|
return arcbios_addchild(cpu, &component, identifier, parent); |
931 |
|
|
} else { |
932 |
|
|
component64.Class = class; |
933 |
|
|
component64.Type = type; |
934 |
|
|
component64.Flags = flags; |
935 |
|
|
component64.Version = version; |
936 |
|
|
component64.Revision = revision; |
937 |
|
|
component64.Key = key; |
938 |
|
|
component64.AffinityMask = affinitymask; |
939 |
|
|
component64.ConfigurationDataSize = config_len; |
940 |
|
|
component64.IdentifierLength = 0; |
941 |
|
|
component64.Identifier = 0; |
942 |
|
|
if (identifier != NULL) { |
943 |
|
|
component64.IdentifierLength = strlen(identifier) + 1; |
944 |
|
|
} |
945 |
|
|
return arcbios_addchild64(cpu, &component64, identifier, |
946 |
|
|
parent); |
947 |
|
|
} |
948 |
|
|
} |
949 |
|
|
|
950 |
|
|
|
951 |
|
|
/* |
952 |
|
|
* arcbios_get_msdos_partition_size(): |
953 |
|
|
* |
954 |
|
|
* This function tries to parse MSDOS-style partition tables on a disk |
955 |
|
|
* image, and return the starting offset (counted in bytes), and the |
956 |
|
|
* size, of a specific partition. |
957 |
|
|
* |
958 |
|
|
* NOTE: partition_nr is 1-based! |
959 |
|
|
* |
960 |
|
|
* TODO: This is buggy, it doesn't really handle extended partitions. |
961 |
|
|
* |
962 |
|
|
* See http://www.nondot.org/sabre/os/files/Partitions/Partitions.html |
963 |
|
|
* for more info. |
964 |
|
|
*/ |
965 |
|
|
static void arcbios_get_msdos_partition_size(struct machine *machine, |
966 |
|
|
int scsi_id, int partition_nr, uint64_t *start, uint64_t *size) |
967 |
|
|
{ |
968 |
|
|
int res, i, partition_type, cur_partition = 0; |
969 |
|
|
unsigned char sector[512]; |
970 |
|
|
unsigned char buf[16]; |
971 |
|
|
uint64_t offset = 0, st; |
972 |
|
|
|
973 |
|
|
/* Partition 0 is the entire disk image: */ |
974 |
|
|
*start = 0; |
975 |
|
|
*size = diskimage_getsize(machine, scsi_id); |
976 |
|
|
if (partition_nr == 0) |
977 |
|
|
return; |
978 |
|
|
|
979 |
|
|
ugly_goto: |
980 |
|
|
*start = 0; *size = 0; |
981 |
|
|
|
982 |
|
|
/* printf("reading MSDOS partition from offset 0x%llx\n", |
983 |
|
|
(long long)offset); */ |
984 |
|
|
|
985 |
|
|
res = diskimage_access(machine, scsi_id, 0, offset, |
986 |
|
|
sector, sizeof(sector)); |
987 |
|
|
if (!res) { |
988 |
|
|
fatal("[ arcbios_get_msdos_partition_size(): couldn't " |
989 |
|
|
"read the disk image, id %i, offset 0x%llx ]\n", |
990 |
|
|
scsi_id, (long long)offset); |
991 |
|
|
return; |
992 |
|
|
} |
993 |
|
|
|
994 |
|
|
if (sector[510] != 0x55 || sector[511] != 0xaa) { |
995 |
|
|
fatal("[ arcbios_get_msdos_partition_size(): not an " |
996 |
|
|
"MSDOS partition table ]\n"); |
997 |
|
|
} |
998 |
|
|
|
999 |
|
|
#if 0 |
1000 |
|
|
/* Debug dump: */ |
1001 |
|
|
for (i=0; i<4; i++) { |
1002 |
|
|
int j; |
1003 |
|
|
printf(" partition %i: ", i+1); |
1004 |
|
|
for (j=0; j<16; j++) |
1005 |
|
|
printf(" %02x", sector[446 + i*16 + j]); |
1006 |
|
|
printf("\n"); |
1007 |
|
|
} |
1008 |
|
|
#endif |
1009 |
|
|
|
1010 |
|
|
for (i=0; i<4; i++) { |
1011 |
|
|
memmove(buf, sector + 446 + 16*i, 16); |
1012 |
|
|
|
1013 |
|
|
partition_type = buf[4]; |
1014 |
|
|
|
1015 |
|
|
if (partition_type == 0) |
1016 |
|
|
continue; |
1017 |
|
|
|
1018 |
|
|
st = (buf[8] + (buf[9] << 8) + (buf[10] << 16) + |
1019 |
|
|
(buf[11] << 24)) * 512; |
1020 |
|
|
|
1021 |
|
|
if (start != NULL) |
1022 |
|
|
*start = st; |
1023 |
|
|
if (size != NULL) |
1024 |
|
|
*size = (buf[12] + (buf[13] << 8) + (buf[14] << 16) + |
1025 |
|
|
(buf[15] << 24)) * 512; |
1026 |
|
|
|
1027 |
|
|
/* Extended DOS partition: */ |
1028 |
|
|
if (partition_type == 5) { |
1029 |
|
|
offset += st; |
1030 |
|
|
goto ugly_goto; |
1031 |
|
|
} |
1032 |
|
|
|
1033 |
|
|
/* Found the right partition? Then return. */ |
1034 |
|
|
cur_partition ++; |
1035 |
|
|
if (cur_partition == partition_nr) |
1036 |
|
|
return; |
1037 |
|
|
} |
1038 |
|
|
|
1039 |
|
|
fatal("[ partition(%i) NOT found ]\n", partition_nr); |
1040 |
|
|
} |
1041 |
|
|
|
1042 |
|
|
|
1043 |
|
|
/* |
1044 |
|
|
* arcbios_handle_to_scsi_id(): |
1045 |
|
|
*/ |
1046 |
|
|
static int arcbios_handle_to_scsi_id(int handle) |
1047 |
|
|
{ |
1048 |
|
|
int id, cdrom; |
1049 |
|
|
char *s; |
1050 |
|
|
|
1051 |
|
|
if (handle < 0 || handle >= MAX_HANDLES) |
1052 |
|
|
return -1; |
1053 |
|
|
|
1054 |
|
|
s = (char *)file_handle_string[handle]; |
1055 |
|
|
if (s == NULL) |
1056 |
|
|
return -1; |
1057 |
|
|
|
1058 |
|
|
/* |
1059 |
|
|
* s is something like "scsi(0)disk(0)rdisk(0)partition(0)". |
1060 |
|
|
* TODO: This is really ugly and hardcoded. |
1061 |
|
|
*/ |
1062 |
|
|
|
1063 |
|
|
if (strncmp(s, "scsi(", 5) != 0 || strlen(s) < 13) |
1064 |
|
|
return -1; |
1065 |
|
|
|
1066 |
|
|
cdrom = (s[7] == 'c'); |
1067 |
|
|
id = cdrom? atoi(s + 13) : atoi(s + 12); |
1068 |
|
|
|
1069 |
|
|
return id; |
1070 |
|
|
} |
1071 |
|
|
|
1072 |
|
|
|
1073 |
|
|
/* |
1074 |
|
|
* arcbios_handle_to_start_and_size(): |
1075 |
|
|
*/ |
1076 |
|
|
static void arcbios_handle_to_start_and_size(struct machine *machine, |
1077 |
|
|
int handle, uint64_t *start, uint64_t *size) |
1078 |
|
|
{ |
1079 |
|
|
char *s = (char *)file_handle_string[handle]; |
1080 |
|
|
char *s2; |
1081 |
|
|
int scsi_id = arcbios_handle_to_scsi_id(handle); |
1082 |
|
|
|
1083 |
|
|
if (scsi_id < 0) |
1084 |
|
|
return; |
1085 |
|
|
|
1086 |
|
|
/* This works for "partition(0)": */ |
1087 |
|
|
*start = 0; |
1088 |
|
|
*size = diskimage_getsize(machine, scsi_id); |
1089 |
|
|
|
1090 |
|
|
s2 = strstr(s, "partition("); |
1091 |
|
|
if (s2 != NULL) { |
1092 |
|
|
int partition_nr = atoi(s2 + 10); |
1093 |
|
|
/* printf("partition_nr = %i\n", partition_nr); */ |
1094 |
|
|
if (partition_nr != 0) |
1095 |
|
|
arcbios_get_msdos_partition_size(machine, |
1096 |
|
|
scsi_id, partition_nr, start, size); |
1097 |
|
|
} |
1098 |
|
|
} |
1099 |
|
|
|
1100 |
|
|
|
1101 |
|
|
/* |
1102 |
|
|
* arcbios_getfileinformation(): |
1103 |
|
|
* |
1104 |
|
|
* Fill in a GetFileInformation struct in emulated memory, |
1105 |
|
|
* for a specific file handle. (This is used to get the size |
1106 |
|
|
* and offsets of partitions on disk images.) |
1107 |
|
|
*/ |
1108 |
|
|
static int arcbios_getfileinformation(struct cpu *cpu) |
1109 |
|
|
{ |
1110 |
|
|
int handle = cpu->cd.mips.gpr[MIPS_GPR_A0]; |
1111 |
|
|
uint64_t addr = cpu->cd.mips.gpr[MIPS_GPR_A1]; |
1112 |
|
|
uint64_t start, size; |
1113 |
|
|
|
1114 |
|
|
arcbios_handle_to_start_and_size(cpu->machine, handle, &start, &size); |
1115 |
|
|
|
1116 |
|
|
store_64bit_word(cpu, addr + 0, 0); |
1117 |
|
|
store_64bit_word(cpu, addr + 8, size); |
1118 |
|
|
store_64bit_word(cpu, addr + 16, 0); |
1119 |
|
|
store_32bit_word(cpu, addr + 24, 1); |
1120 |
|
|
store_32bit_word(cpu, addr + 28, 0); |
1121 |
|
|
store_32bit_word(cpu, addr + 32, 0); |
1122 |
|
|
|
1123 |
|
|
/* printf("\n!!! size=0x%x start=0x%x\n", (int)size, (int)start); */ |
1124 |
|
|
|
1125 |
|
|
return ARCBIOS_ESUCCESS; |
1126 |
|
|
} |
1127 |
|
|
|
1128 |
|
|
|
1129 |
|
|
/* |
1130 |
|
|
* arcbios_private_emul(): |
1131 |
|
|
* |
1132 |
|
|
* TODO: This is probably SGI specific. (?) |
1133 |
|
|
* |
1134 |
|
|
* 0x04 get nvram table |
1135 |
|
|
*/ |
1136 |
|
|
void arcbios_private_emul(struct cpu *cpu) |
1137 |
|
|
{ |
1138 |
|
|
int vector = cpu->pc & 0xfff; |
1139 |
|
|
|
1140 |
|
|
switch (vector) { |
1141 |
|
|
case 0x04: |
1142 |
|
|
debug("[ ARCBIOS PRIVATE get nvram table(): TODO ]\n"); |
1143 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1144 |
|
|
break; |
1145 |
|
|
default: |
1146 |
|
|
cpu_register_dump(cpu->machine, cpu, 1, 0x1); |
1147 |
|
|
debug("a0 points to: "); |
1148 |
|
|
dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1149 |
|
|
debug("\n"); |
1150 |
|
|
fatal("ARCBIOS: unimplemented PRIVATE vector 0x%x\n", vector); |
1151 |
|
|
cpu->running = 0; |
1152 |
|
|
cpu->dead = 1; |
1153 |
|
|
} |
1154 |
|
|
} |
1155 |
|
|
|
1156 |
|
|
|
1157 |
|
|
/* |
1158 |
|
|
* arcbios_emul(): ARCBIOS emulation |
1159 |
|
|
* |
1160 |
|
|
* 0x0c Halt() |
1161 |
|
|
* 0x10 PowerDown() |
1162 |
|
|
* 0x14 Restart() |
1163 |
|
|
* 0x18 Reboot() |
1164 |
|
|
* 0x1c EnterInteractiveMode() |
1165 |
|
|
* 0x20 ReturnFromMain() |
1166 |
|
|
* 0x24 GetPeer(node) |
1167 |
|
|
* 0x28 GetChild(node) |
1168 |
|
|
* 0x2c GetParent(node) |
1169 |
|
|
* 0x30 GetConfigurationData(config_data, node) |
1170 |
|
|
* 0x3c GetComponent(name) |
1171 |
|
|
* 0x44 GetSystemId() |
1172 |
|
|
* 0x48 GetMemoryDescriptor(void *) |
1173 |
|
|
* 0x50 GetTime() |
1174 |
|
|
* 0x54 GetRelativeTime() |
1175 |
|
|
* 0x5c Open(path, mode, &fileid) |
1176 |
|
|
* 0x60 Close(handle) |
1177 |
|
|
* 0x64 Read(handle, &buf, len, &actuallen) |
1178 |
|
|
* 0x6c Write(handle, buf, len, &returnlen) |
1179 |
|
|
* 0x70 Seek(handle, &offset, len) |
1180 |
|
|
* 0x78 GetEnvironmentVariable(char *) |
1181 |
|
|
* 0x7c SetEnvironmentVariable(char *, char *) |
1182 |
|
|
* 0x80 GetFileInformation(handle, buf) |
1183 |
|
|
* 0x88 FlushAllCaches() |
1184 |
|
|
* 0x90 GetDisplayStatus(uint32_t handle) |
1185 |
|
|
* 0x100 undocumented IRIX (?) |
1186 |
|
|
*/ |
1187 |
|
|
int arcbios_emul(struct cpu *cpu) |
1188 |
|
|
{ |
1189 |
|
|
int vector = cpu->pc & 0xfff; |
1190 |
|
|
int i, j, handle; |
1191 |
|
|
unsigned char ch2; |
1192 |
|
|
unsigned char buf[40]; |
1193 |
|
|
|
1194 |
|
|
if (cpu->pc >= ARC_PRIVATE_ENTRIES && |
1195 |
|
|
cpu->pc < ARC_PRIVATE_ENTRIES + 100*sizeof(uint32_t)) { |
1196 |
|
|
arcbios_private_emul(cpu); |
1197 |
|
|
return 1; |
1198 |
|
|
} |
1199 |
|
|
|
1200 |
|
|
if (arc_64bit) |
1201 |
|
|
vector /= 2; |
1202 |
|
|
|
1203 |
|
|
/* Special case for reboot by jumping to 0xbfc00000: */ |
1204 |
|
|
if (vector == 0 && (cpu->pc & 0xffffffffULL) == 0xbfc00000ULL) |
1205 |
|
|
vector = 0x18; |
1206 |
|
|
|
1207 |
|
|
switch (vector) { |
1208 |
|
|
case 0x0c: /* Halt() */ |
1209 |
|
|
case 0x10: /* PowerDown() */ |
1210 |
|
|
case 0x14: /* Restart() */ |
1211 |
|
|
case 0x18: /* Reboot() */ |
1212 |
|
|
case 0x1c: /* EnterInteractiveMode() */ |
1213 |
|
|
case 0x20: /* ReturnFromMain() */ |
1214 |
|
|
debug("[ ARCBIOS Halt() or similar ]\n"); |
1215 |
|
|
/* Halt all CPUs. */ |
1216 |
|
|
for (i=0; i<cpu->machine->ncpus; i++) { |
1217 |
|
|
cpu->machine->cpus[i]->running = 0; |
1218 |
|
|
cpu->machine->cpus[i]->dead = 1; |
1219 |
|
|
} |
1220 |
|
|
cpu->machine->exit_without_entering_debugger = 1; |
1221 |
|
|
break; |
1222 |
|
|
case 0x24: /* GetPeer(node) */ |
1223 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { |
1224 |
|
|
/* NULL ptr argument: return NULL. */ |
1225 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1226 |
|
|
} else { |
1227 |
|
|
uint64_t peer; |
1228 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1229 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] - 3 * arc_wordlen, |
1230 |
|
|
&buf[0], arc_wordlen, MEM_READ, CACHE_NONE); |
1231 |
|
|
if (arc_64bit) { |
1232 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1233 |
|
|
unsigned char tmp; tmp = buf[0]; |
1234 |
|
|
buf[0] = buf[7]; buf[7] = tmp; |
1235 |
|
|
tmp = buf[1]; buf[1] = buf[6]; |
1236 |
|
|
buf[6] = tmp; |
1237 |
|
|
tmp = buf[2]; buf[2] = buf[5]; |
1238 |
|
|
buf[5] = tmp; |
1239 |
|
|
tmp = buf[3]; buf[3] = buf[4]; |
1240 |
|
|
buf[4] = tmp; |
1241 |
|
|
} |
1242 |
|
|
peer = (uint64_t)buf[0] + ((uint64_t)buf[1]<<8) |
1243 |
|
|
+ ((uint64_t)buf[2]<<16) |
1244 |
|
|
+ ((uint64_t)buf[3]<<24) |
1245 |
|
|
+ ((uint64_t)buf[4]<<32) |
1246 |
|
|
+ ((uint64_t)buf[5]<<40) |
1247 |
|
|
+ ((uint64_t)buf[6]<<48) |
1248 |
|
|
+ ((uint64_t)buf[7]<<56); |
1249 |
|
|
} else { |
1250 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1251 |
|
|
unsigned char tmp; tmp = buf[0]; |
1252 |
|
|
buf[0] = buf[3]; buf[3] = tmp; |
1253 |
|
|
tmp = buf[1]; buf[1] = buf[2]; |
1254 |
|
|
buf[2] = tmp; |
1255 |
|
|
} |
1256 |
|
|
peer = buf[0] + (buf[1]<<8) + (buf[2]<<16) |
1257 |
|
|
+ (buf[3]<<24); |
1258 |
|
|
} |
1259 |
|
|
|
1260 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = peer? |
1261 |
|
|
(peer + 3 * arc_wordlen) : 0; |
1262 |
|
|
if (!arc_64bit) |
1263 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) |
1264 |
|
|
(int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; |
1265 |
|
|
} |
1266 |
|
|
debug("[ ARCBIOS GetPeer(node 0x%016llx): 0x%016llx ]\n", |
1267 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1268 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_V0]); |
1269 |
|
|
break; |
1270 |
|
|
case 0x28: /* GetChild(node) */ |
1271 |
|
|
/* 0 for the root, non-0 for children: */ |
1272 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) |
1273 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1274 |
|
|
FIRST_ARC_COMPONENT + arc_wordlen * 3; |
1275 |
|
|
else { |
1276 |
|
|
uint64_t child = 0; |
1277 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1278 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] - 2 * arc_wordlen, |
1279 |
|
|
&buf[0], arc_wordlen, MEM_READ, CACHE_NONE); |
1280 |
|
|
if (arc_64bit) { |
1281 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1282 |
|
|
unsigned char tmp; tmp = buf[0]; |
1283 |
|
|
buf[0] = buf[7]; buf[7] = tmp; |
1284 |
|
|
tmp = buf[1]; buf[1] = buf[6]; |
1285 |
|
|
buf[6] = tmp; |
1286 |
|
|
tmp = buf[2]; buf[2] = buf[5]; |
1287 |
|
|
buf[5] = tmp; |
1288 |
|
|
tmp = buf[3]; buf[3] = buf[4]; |
1289 |
|
|
buf[4] = tmp; |
1290 |
|
|
} |
1291 |
|
|
child = (uint64_t)buf[0] + |
1292 |
|
|
((uint64_t)buf[1]<<8) + |
1293 |
|
|
((uint64_t)buf[2]<<16) + |
1294 |
|
|
((uint64_t)buf[3]<<24) + |
1295 |
|
|
((uint64_t)buf[4]<<32) + |
1296 |
|
|
((uint64_t)buf[5]<<40) + |
1297 |
|
|
((uint64_t)buf[6]<<48) + |
1298 |
|
|
((uint64_t)buf[7]<<56); |
1299 |
|
|
} else { |
1300 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1301 |
|
|
unsigned char tmp; tmp = buf[0]; |
1302 |
|
|
buf[0] = buf[3]; buf[3] = tmp; |
1303 |
|
|
tmp = buf[1]; buf[1] = buf[2]; |
1304 |
|
|
buf[2] = tmp; |
1305 |
|
|
} |
1306 |
|
|
child = buf[0] + (buf[1]<<8) + (buf[2]<<16) + |
1307 |
|
|
(buf[3]<<24); |
1308 |
|
|
} |
1309 |
|
|
|
1310 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = child? |
1311 |
|
|
(child + 3 * arc_wordlen) : 0; |
1312 |
|
|
if (!arc_64bit) |
1313 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) |
1314 |
|
|
(int32_t)cpu->cd.mips.gpr[MIPS_GPR_V0]; |
1315 |
|
|
} |
1316 |
|
|
debug("[ ARCBIOS GetChild(node 0x%016llx): 0x%016llx ]\n", |
1317 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1318 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_V0]); |
1319 |
|
|
break; |
1320 |
|
|
case 0x2c: /* GetParent(node) */ |
1321 |
|
|
{ |
1322 |
|
|
uint64_t parent; |
1323 |
|
|
|
1324 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1325 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] - 1 * arc_wordlen, |
1326 |
|
|
&buf[0], arc_wordlen, MEM_READ, CACHE_NONE); |
1327 |
|
|
|
1328 |
|
|
if (arc_64bit) { |
1329 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1330 |
|
|
unsigned char tmp; tmp = buf[0]; |
1331 |
|
|
buf[0] = buf[7]; buf[7] = tmp; |
1332 |
|
|
tmp = buf[1]; buf[1] = buf[6]; |
1333 |
|
|
buf[6] = tmp; |
1334 |
|
|
tmp = buf[2]; buf[2] = buf[5]; |
1335 |
|
|
buf[5] = tmp; |
1336 |
|
|
tmp = buf[3]; buf[3] = buf[4]; |
1337 |
|
|
buf[4] = tmp; |
1338 |
|
|
} |
1339 |
|
|
parent = (uint64_t)buf[0] + |
1340 |
|
|
((uint64_t)buf[1]<<8) + |
1341 |
|
|
((uint64_t)buf[2]<<16) + |
1342 |
|
|
((uint64_t)buf[3]<<24) + |
1343 |
|
|
((uint64_t)buf[4]<<32) + |
1344 |
|
|
((uint64_t)buf[5]<<40) + |
1345 |
|
|
((uint64_t)buf[6]<<48) + |
1346 |
|
|
((uint64_t)buf[7]<<56); |
1347 |
|
|
} else { |
1348 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1349 |
|
|
unsigned char tmp; tmp = buf[0]; |
1350 |
|
|
buf[0] = buf[3]; buf[3] = tmp; |
1351 |
|
|
tmp = buf[1]; buf[1] = buf[2]; |
1352 |
|
|
buf[2] = tmp; |
1353 |
|
|
} |
1354 |
|
|
parent = buf[0] + (buf[1]<<8) + |
1355 |
|
|
(buf[2]<<16) + (buf[3]<<24); |
1356 |
|
|
} |
1357 |
|
|
|
1358 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = parent? |
1359 |
|
|
(parent + 3 * arc_wordlen) : 0; |
1360 |
|
|
if (!arc_64bit) |
1361 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t) |
1362 |
|
|
(int32_t) cpu->cd.mips.gpr[MIPS_GPR_V0]; |
1363 |
|
|
} |
1364 |
|
|
debug("[ ARCBIOS GetParent(node 0x%016llx): 0x%016llx ]\n", |
1365 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1366 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_V0]); |
1367 |
|
|
break; |
1368 |
|
|
case 0x30: /* GetConfigurationData(void *configdata, void *node) */ |
1369 |
|
|
/* fatal("[ ARCBIOS GetConfigurationData(0x%016llx," |
1370 |
|
|
"0x%016llx) ]\n", (long long)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1371 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A1]); */ |
1372 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; |
1373 |
|
|
for (i=0; i<n_configuration_data; i++) { |
1374 |
|
|
/* fatal("configuration_data_component[%i] = " |
1375 |
|
|
"0x%016llx\n", i, |
1376 |
|
|
(long long)configuration_data_component[i]); */ |
1377 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A1] == |
1378 |
|
|
configuration_data_component[i]) { |
1379 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1380 |
|
|
for (j=0; j<configuration_data_len[i]; j++) { |
1381 |
|
|
unsigned char ch; |
1382 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1383 |
|
|
configuration_data_configdata[i] + |
1384 |
|
|
j, &ch, 1, MEM_READ, CACHE_NONE); |
1385 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1386 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] + j, |
1387 |
|
|
&ch, 1, MEM_WRITE, CACHE_NONE); |
1388 |
|
|
} |
1389 |
|
|
break; |
1390 |
|
|
} |
1391 |
|
|
} |
1392 |
|
|
break; |
1393 |
|
|
case 0x3c: /* GetComponent(char *name) */ |
1394 |
|
|
debug("[ ARCBIOS GetComponent(\""); |
1395 |
|
|
dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1396 |
|
|
debug("\") ]\n"); |
1397 |
|
|
|
1398 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { |
1399 |
|
|
fatal("[ ARCBIOS GetComponent: NULL ptr ]\n"); |
1400 |
|
|
} else { |
1401 |
|
|
unsigned char buf[500]; |
1402 |
|
|
int match_index = -1; |
1403 |
|
|
int match_len = 0; |
1404 |
|
|
|
1405 |
|
|
memset(buf, 0, sizeof(buf)); |
1406 |
|
|
for (i=0; i<sizeof(buf); i++) { |
1407 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1408 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] + i, |
1409 |
|
|
&buf[i], 1, MEM_READ, CACHE_NONE); |
1410 |
|
|
if (buf[i] == '\0') |
1411 |
|
|
i = sizeof(buf); |
1412 |
|
|
} |
1413 |
|
|
buf[sizeof(buf) - 1] = '\0'; |
1414 |
|
|
|
1415 |
|
|
/* "scsi(0)disk(0)rdisk(0)partition(0)" and such. */ |
1416 |
|
|
/* printf("GetComponent(\"%s\")\n", buf); */ |
1417 |
|
|
|
1418 |
|
|
/* Default to NULL return value. */ |
1419 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1420 |
|
|
|
1421 |
|
|
/* Scan the string to component table: */ |
1422 |
|
|
for (i=0; i<arcbios_n_string_to_components; i++) { |
1423 |
|
|
int m = 0; |
1424 |
|
|
while (buf[m] && arcbios_string_to_component |
1425 |
|
|
[i][m] && arcbios_string_to_component[i][m] |
1426 |
|
|
== buf[m]) |
1427 |
|
|
m++; |
1428 |
|
|
if (m > match_len) { |
1429 |
|
|
match_len = m; |
1430 |
|
|
match_index = i; |
1431 |
|
|
} |
1432 |
|
|
} |
1433 |
|
|
|
1434 |
|
|
if (match_index >= 0) { |
1435 |
|
|
/* printf("Longest match: '%s'\n", |
1436 |
|
|
arcbios_string_to_component[ |
1437 |
|
|
match_index]); */ |
1438 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1439 |
|
|
arcbios_string_to_component_value[ |
1440 |
|
|
match_index]; |
1441 |
|
|
} |
1442 |
|
|
} |
1443 |
|
|
break; |
1444 |
|
|
case 0x44: /* GetSystemId() */ |
1445 |
|
|
debug("[ ARCBIOS GetSystemId() ]\n"); |
1446 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = SGI_SYSID_ADDR; |
1447 |
|
|
break; |
1448 |
|
|
case 0x48: /* void *GetMemoryDescriptor(void *ptr) */ |
1449 |
|
|
debug("[ ARCBIOS GetMemoryDescriptor(0x%08x) ]\n", |
1450 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1451 |
|
|
|
1452 |
|
|
/* If a0=NULL, then return the first descriptor: */ |
1453 |
|
|
if ((uint32_t)cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) |
1454 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1455 |
|
|
arcbios_memdescriptor_base; |
1456 |
|
|
else { |
1457 |
|
|
int s = arc_64bit? sizeof(struct arcbios_mem64) |
1458 |
|
|
: sizeof(struct arcbios_mem); |
1459 |
|
|
int nr = cpu->cd.mips.gpr[MIPS_GPR_A0] - |
1460 |
|
|
arcbios_memdescriptor_base; |
1461 |
|
|
nr /= s; |
1462 |
|
|
nr ++; |
1463 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1464 |
|
|
arcbios_memdescriptor_base + s * nr; |
1465 |
|
|
if (nr >= arc_n_memdescriptors) |
1466 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1467 |
|
|
} |
1468 |
|
|
break; |
1469 |
|
|
case 0x50: /* GetTime() */ |
1470 |
|
|
debug("[ ARCBIOS GetTime() ]\n"); |
1471 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0xffffffff80001000ULL; |
1472 |
|
|
/* TODO! */ |
1473 |
|
|
break; |
1474 |
|
|
case 0x54: /* GetRelativeTime() */ |
1475 |
|
|
debug("[ ARCBIOS GetRelativeTime() ]\n"); |
1476 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = (int64_t)(int32_t)time(NULL); |
1477 |
|
|
break; |
1478 |
|
|
case 0x5c: /* Open(char *path, uint32_t mode, uint32_t *fileID) */ |
1479 |
|
|
debug("[ ARCBIOS Open(\""); |
1480 |
|
|
dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1481 |
|
|
debug("\",0x%x,0x%x)", (int)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1482 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A1], |
1483 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1484 |
|
|
|
1485 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ENOENT; |
1486 |
|
|
|
1487 |
|
|
handle = 3; |
1488 |
|
|
/* TODO: Starting at 0 would require some updates... */ |
1489 |
|
|
while (file_handle_in_use[handle]) { |
1490 |
|
|
handle ++; |
1491 |
|
|
if (handle >= MAX_HANDLES) { |
1492 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EMFILE; |
1493 |
|
|
break; |
1494 |
|
|
} |
1495 |
|
|
} |
1496 |
|
|
|
1497 |
|
|
if (handle >= MAX_HANDLES) { |
1498 |
|
|
fatal("[ ARCBIOS Open: out of file handles ]\n"); |
1499 |
|
|
} else if (cpu->cd.mips.gpr[MIPS_GPR_A0] == 0) { |
1500 |
|
|
fatal("[ ARCBIOS Open: NULL ptr ]\n"); |
1501 |
|
|
} else { |
1502 |
|
|
/* |
1503 |
|
|
* TODO: This is hardcoded to successfully open |
1504 |
|
|
* anything. It is used by the Windows NT SETUPLDR |
1505 |
|
|
* program to load stuff from the boot partition. |
1506 |
|
|
*/ |
1507 |
|
|
unsigned char *buf = malloc(MAX_OPEN_STRINGLEN); |
1508 |
|
|
if (buf == NULL) { |
1509 |
|
|
fprintf(stderr, "out of memory\n"); |
1510 |
|
|
exit(1); |
1511 |
|
|
} |
1512 |
|
|
memset(buf, 0, MAX_OPEN_STRINGLEN); |
1513 |
|
|
for (i=0; i<MAX_OPEN_STRINGLEN; i++) { |
1514 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1515 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] + i, |
1516 |
|
|
&buf[i], 1, MEM_READ, CACHE_NONE); |
1517 |
|
|
if (buf[i] == '\0') |
1518 |
|
|
i = MAX_OPEN_STRINGLEN; |
1519 |
|
|
} |
1520 |
|
|
buf[MAX_OPEN_STRINGLEN - 1] = '\0'; |
1521 |
|
|
file_handle_string[handle] = buf; |
1522 |
|
|
arcbios_current_seek_offset[handle] = 0; |
1523 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; |
1524 |
|
|
} |
1525 |
|
|
|
1526 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_V0] == ARCBIOS_ESUCCESS) { |
1527 |
|
|
debug(" = handle %i ]\n", (int)handle); |
1528 |
|
|
store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A2], |
1529 |
|
|
handle); |
1530 |
|
|
file_handle_in_use[handle] = 1; |
1531 |
|
|
} else |
1532 |
|
|
debug(" = ERROR %i ]\n", |
1533 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_V0]); |
1534 |
|
|
break; |
1535 |
|
|
case 0x60: /* Close(uint32_t handle) */ |
1536 |
|
|
debug("[ ARCBIOS Close(%i) ]\n", |
1537 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1538 |
|
|
if (!file_handle_in_use[cpu->cd.mips.gpr[MIPS_GPR_A0]]) { |
1539 |
|
|
fatal("ARCBIOS Close(%i): bad handle\n", |
1540 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1541 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; |
1542 |
|
|
} else { |
1543 |
|
|
file_handle_in_use[cpu->cd.mips.gpr[MIPS_GPR_A0]] = 0; |
1544 |
|
|
if (file_handle_string[cpu->cd.mips.gpr[MIPS_GPR_A0]] |
1545 |
|
|
!= NULL) |
1546 |
|
|
free(file_handle_string[cpu->cd.mips.gpr[ |
1547 |
|
|
MIPS_GPR_A0]]); |
1548 |
|
|
file_handle_string[cpu->cd.mips.gpr[MIPS_GPR_A0]] = |
1549 |
|
|
NULL; |
1550 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; |
1551 |
|
|
} |
1552 |
|
|
break; |
1553 |
|
|
case 0x64: /* Read(handle, void *buf, length, uint32_t *count) */ |
1554 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { |
1555 |
|
|
int i, nread = 0; |
1556 |
|
|
/* |
1557 |
|
|
* Before going into the loop, make sure stdout |
1558 |
|
|
* is flushed. If we're using an X11 VGA console, |
1559 |
|
|
* then it needs to be flushed as well. |
1560 |
|
|
*/ |
1561 |
|
|
fflush(stdin); |
1562 |
|
|
fflush(stdout); |
1563 |
|
|
/* NOTE/TODO: This gives a tick to _everything_ */ |
1564 |
|
|
for (i=0; i<cpu->machine->n_tick_entries; i++) |
1565 |
|
|
cpu->machine->tick_func[i](cpu, |
1566 |
|
|
cpu->machine->tick_extra[i]); |
1567 |
|
|
|
1568 |
|
|
for (i=0; i<cpu->cd.mips.gpr[MIPS_GPR_A2]; i++) { |
1569 |
|
|
int x; |
1570 |
|
|
unsigned char ch; |
1571 |
|
|
|
1572 |
|
|
/* Read from STDIN is blocking (at least |
1573 |
|
|
that seems to be how NetBSD's arcdiag |
1574 |
|
|
wants it) */ |
1575 |
|
|
x = console_readchar(cpu->machine-> |
1576 |
|
|
main_console_handle); |
1577 |
|
|
if (x < 0) |
1578 |
|
|
return 0; |
1579 |
|
|
|
1580 |
|
|
/* |
1581 |
|
|
* ESC + '[' should be transformed into 0x9b: |
1582 |
|
|
* |
1583 |
|
|
* NOTE/TODO: This makes the behaviour of just |
1584 |
|
|
* pressing ESC a bit harder to define. |
1585 |
|
|
*/ |
1586 |
|
|
if (x == 27) { |
1587 |
|
|
x = console_readchar(cpu-> |
1588 |
|
|
machine->main_console_handle); |
1589 |
|
|
if (x == '[' || x == 'O') |
1590 |
|
|
x = 0x9b; |
1591 |
|
|
} |
1592 |
|
|
|
1593 |
|
|
ch = x; |
1594 |
|
|
nread ++; |
1595 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1596 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A1] + i, |
1597 |
|
|
&ch, 1, MEM_WRITE, CACHE_NONE); |
1598 |
|
|
|
1599 |
|
|
/* NOTE: Only one char, from STDIN: */ |
1600 |
|
|
i = cpu->cd.mips.gpr[MIPS_GPR_A2]; /* :-) */ |
1601 |
|
|
} |
1602 |
|
|
store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], |
1603 |
|
|
nread); |
1604 |
|
|
/* TODO: not EAGAIN? */ |
1605 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1606 |
|
|
nread? ARCBIOS_ESUCCESS: ARCBIOS_EAGAIN; |
1607 |
|
|
} else { |
1608 |
|
|
int handle = cpu->cd.mips.gpr[MIPS_GPR_A0]; |
1609 |
|
|
int disk_id = arcbios_handle_to_scsi_id(handle); |
1610 |
|
|
uint64_t partition_offset = 0; |
1611 |
|
|
int res; |
1612 |
|
|
uint64_t size; /* dummy */ |
1613 |
|
|
unsigned char *tmp_buf; |
1614 |
|
|
|
1615 |
|
|
arcbios_handle_to_start_and_size(cpu->machine, |
1616 |
|
|
handle, &partition_offset, &size); |
1617 |
|
|
|
1618 |
|
|
debug("[ ARCBIOS Read(%i,0x%08x,0x%08x,0x%08x) ]\n", |
1619 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1620 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A1], |
1621 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2], |
1622 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A3]); |
1623 |
|
|
|
1624 |
|
|
tmp_buf = malloc(cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1625 |
|
|
if (tmp_buf == NULL) { |
1626 |
|
|
fprintf(stderr, "[ *** Out of memory in " |
1627 |
|
|
"arcbios.c, allocating %i bytes ]\n", |
1628 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1629 |
|
|
break; |
1630 |
|
|
} |
1631 |
|
|
|
1632 |
|
|
res = diskimage_access(cpu->machine, disk_id, 0, |
1633 |
|
|
partition_offset + arcbios_current_seek_offset[ |
1634 |
|
|
handle], tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1635 |
|
|
|
1636 |
|
|
/* If the transfer was successful, transfer the |
1637 |
|
|
data to emulated memory: */ |
1638 |
|
|
if (res) { |
1639 |
|
|
uint64_t dst = cpu->cd.mips.gpr[MIPS_GPR_A1]; |
1640 |
|
|
store_buf(cpu, dst, (char *)tmp_buf, |
1641 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1642 |
|
|
store_32bit_word(cpu, |
1643 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A3], |
1644 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1645 |
|
|
arcbios_current_seek_offset[handle] += |
1646 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A2]; |
1647 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1648 |
|
|
} else |
1649 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; |
1650 |
|
|
free(tmp_buf); |
1651 |
|
|
} |
1652 |
|
|
break; |
1653 |
|
|
case 0x68: /* GetReadStatus(handle) */ |
1654 |
|
|
/* |
1655 |
|
|
* According to arcbios_tty_getchar() in NetBSD's |
1656 |
|
|
* dev/arcbios/arcbios_tty.c, GetReadStatus should |
1657 |
|
|
* return 0 if there is something available. |
1658 |
|
|
* |
1659 |
|
|
* TODO: Error codes are things like ARCBIOS_EAGAIN. |
1660 |
|
|
*/ |
1661 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] == ARCBIOS_STDIN) { |
1662 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = console_charavail( |
1663 |
|
|
cpu->machine->main_console_handle)? 0 : 1; |
1664 |
|
|
} else { |
1665 |
|
|
fatal("[ ARCBIOS GetReadStatus(%i) from " |
1666 |
|
|
"something other than STDIN: TODO ]\n", |
1667 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1668 |
|
|
/* TODO */ |
1669 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 1; |
1670 |
|
|
} |
1671 |
|
|
break; |
1672 |
|
|
case 0x6c: /* Write(handle, buf, len, &returnlen) */ |
1673 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] != ARCBIOS_STDOUT) { |
1674 |
|
|
/* |
1675 |
|
|
* TODO: this is just a test |
1676 |
|
|
*/ |
1677 |
|
|
int handle = cpu->cd.mips.gpr[MIPS_GPR_A0]; |
1678 |
|
|
int disk_id = arcbios_handle_to_scsi_id(handle); |
1679 |
|
|
uint64_t partition_offset = 0; |
1680 |
|
|
int res, i; |
1681 |
|
|
uint64_t size; /* dummy */ |
1682 |
|
|
unsigned char *tmp_buf; |
1683 |
|
|
|
1684 |
|
|
arcbios_handle_to_start_and_size(cpu->machine, |
1685 |
|
|
handle, &partition_offset, &size); |
1686 |
|
|
|
1687 |
|
|
debug("[ ARCBIOS Write(%i,0x%08llx,%i,0x%08llx) ]\n", |
1688 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1689 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A1], |
1690 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2], |
1691 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A3]); |
1692 |
|
|
|
1693 |
|
|
tmp_buf = malloc(cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1694 |
|
|
if (tmp_buf == NULL) { |
1695 |
|
|
fprintf(stderr, "[ *** Out of memory in" |
1696 |
|
|
" arcbios.c, allocating %i bytes ]\n", |
1697 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1698 |
|
|
break; |
1699 |
|
|
} |
1700 |
|
|
|
1701 |
|
|
for (i=0; i<cpu->cd.mips.gpr[MIPS_GPR_A2]; i++) |
1702 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1703 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A1] + i, |
1704 |
|
|
&tmp_buf[i], sizeof(char), MEM_READ, |
1705 |
|
|
CACHE_NONE); |
1706 |
|
|
|
1707 |
|
|
res = diskimage_access(cpu->machine, disk_id, 1, |
1708 |
|
|
partition_offset + arcbios_current_seek_offset[ |
1709 |
|
|
handle], tmp_buf, cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1710 |
|
|
|
1711 |
|
|
if (res) { |
1712 |
|
|
store_32bit_word(cpu, |
1713 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A3], |
1714 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1715 |
|
|
arcbios_current_seek_offset[handle] += |
1716 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A2]; |
1717 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1718 |
|
|
} else |
1719 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EIO; |
1720 |
|
|
free(tmp_buf); |
1721 |
|
|
} else { |
1722 |
|
|
for (i=0; i<cpu->cd.mips.gpr[MIPS_GPR_A2]; i++) { |
1723 |
|
|
unsigned char ch = '\0'; |
1724 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1725 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A1] + i, |
1726 |
|
|
&ch, sizeof(ch), MEM_READ, CACHE_NONE); |
1727 |
|
|
|
1728 |
|
|
arcbios_putchar(cpu, ch); |
1729 |
|
|
} |
1730 |
|
|
} |
1731 |
|
|
store_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_A3], |
1732 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1733 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ |
1734 |
|
|
break; |
1735 |
|
|
case 0x70: /* Seek(uint32_t handle, int64_t *ofs, |
1736 |
|
|
uint32_t whence): uint32_t */ |
1737 |
|
|
debug("[ ARCBIOS Seek(%i,0x%08llx,%i): ", |
1738 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1739 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A1], |
1740 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1741 |
|
|
|
1742 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A2] != 0) { |
1743 |
|
|
fatal("[ ARCBIOS Seek(%i,0x%08llx,%i): " |
1744 |
|
|
"UNIMPLEMENTED whence=%i ]\n", |
1745 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1746 |
|
|
(long long)cpu->cd.mips.gpr[MIPS_GPR_A1], |
1747 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2], |
1748 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A2]); |
1749 |
|
|
} |
1750 |
|
|
|
1751 |
|
|
{ |
1752 |
|
|
unsigned char buf[8]; |
1753 |
|
|
uint64_t ofs; |
1754 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1755 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A1], &buf[0], |
1756 |
|
|
sizeof(buf), MEM_READ, CACHE_NONE); |
1757 |
|
|
if (cpu->byte_order == EMUL_BIG_ENDIAN) { |
1758 |
|
|
unsigned char tmp; |
1759 |
|
|
tmp = buf[0]; buf[0] = buf[7]; buf[7] = tmp; |
1760 |
|
|
tmp = buf[1]; buf[1] = buf[6]; buf[6] = tmp; |
1761 |
|
|
tmp = buf[2]; buf[2] = buf[5]; buf[5] = tmp; |
1762 |
|
|
tmp = buf[3]; buf[3] = buf[4]; buf[4] = tmp; |
1763 |
|
|
} |
1764 |
|
|
ofs = buf[0] + (buf[1] << 8) + (buf[2] << 16) + |
1765 |
|
|
(buf[3] << 24) + ((uint64_t)buf[4] << 32) + |
1766 |
|
|
((uint64_t)buf[5] << 40) + ((uint64_t)buf[6] << 48) |
1767 |
|
|
+ ((uint64_t)buf[7] << 56); |
1768 |
|
|
arcbios_current_seek_offset[ |
1769 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0]] = ofs; |
1770 |
|
|
debug("%016llx ]\n", (long long)ofs); |
1771 |
|
|
} |
1772 |
|
|
|
1773 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; /* Success. */ |
1774 |
|
|
|
1775 |
|
|
break; |
1776 |
|
|
case 0x78: /* GetEnvironmentVariable(char *) */ |
1777 |
|
|
/* Find the environment variable given by a0: */ |
1778 |
|
|
for (i=0; i<sizeof(buf); i++) |
1779 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1780 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0] + i, |
1781 |
|
|
&buf[i], sizeof(char), MEM_READ, CACHE_NONE); |
1782 |
|
|
buf[sizeof(buf)-1] = '\0'; |
1783 |
|
|
debug("[ ARCBIOS GetEnvironmentVariable(\"%s\") ]\n", buf); |
1784 |
|
|
for (i=0; i<0x1000; i++) { |
1785 |
|
|
/* Matching string at offset i? */ |
1786 |
|
|
int nmatches = 0; |
1787 |
|
|
for (j=0; j<strlen((char *)buf); j++) { |
1788 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1789 |
|
|
(uint64_t)(ARC_ENV_STRINGS + i + j), |
1790 |
|
|
&ch2, sizeof(char), MEM_READ, CACHE_NONE); |
1791 |
|
|
if (ch2 == buf[j]) |
1792 |
|
|
nmatches++; |
1793 |
|
|
} |
1794 |
|
|
cpu->memory_rw(cpu, cpu->mem, |
1795 |
|
|
(uint64_t)(ARC_ENV_STRINGS + i + |
1796 |
|
|
strlen((char *)buf)), &ch2, sizeof(char), |
1797 |
|
|
MEM_READ, CACHE_NONE); |
1798 |
|
|
if (nmatches == strlen((char *)buf) && ch2 == '=') { |
1799 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1800 |
|
|
ARC_ENV_STRINGS + i + |
1801 |
|
|
strlen((char *)buf) + 1; |
1802 |
|
|
return 1; |
1803 |
|
|
} |
1804 |
|
|
} |
1805 |
|
|
/* Return NULL if string wasn't found. */ |
1806 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1807 |
|
|
break; |
1808 |
|
|
case 0x7c: /* SetEnvironmentVariable(char *, char *) */ |
1809 |
|
|
debug("[ ARCBIOS SetEnvironmentVariable(\""); |
1810 |
|
|
dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1811 |
|
|
debug("\",\""); |
1812 |
|
|
dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A1]); |
1813 |
|
|
debug("\") ]\n"); |
1814 |
|
|
/* TODO: This is a dummy. */ |
1815 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_ESUCCESS; |
1816 |
|
|
break; |
1817 |
|
|
case 0x80: /* GetFileInformation() */ |
1818 |
|
|
debug("[ ARCBIOS GetFileInformation(%i,0x%x): ", |
1819 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0], |
1820 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A1]); |
1821 |
|
|
|
1822 |
|
|
if (cpu->cd.mips.gpr[MIPS_GPR_A0] >= MAX_HANDLES) { |
1823 |
|
|
debug("invalid file handle ]\n"); |
1824 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EINVAL; |
1825 |
|
|
} else if (!file_handle_in_use[cpu->cd.mips.gpr[MIPS_GPR_A0]]) { |
1826 |
|
|
debug("file handle not in use! ]\n"); |
1827 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARCBIOS_EBADF; |
1828 |
|
|
} else { |
1829 |
|
|
debug("'%s' ]\n", file_handle_string[ |
1830 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_A0]]); |
1831 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = |
1832 |
|
|
arcbios_getfileinformation(cpu); |
1833 |
|
|
} |
1834 |
|
|
break; |
1835 |
|
|
case 0x88: /* FlushAllCaches() */ |
1836 |
|
|
debug("[ ARCBIOS FlushAllCaches(): TODO ]\n"); |
1837 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1838 |
|
|
break; |
1839 |
|
|
case 0x90: /* void *GetDisplayStatus(handle) */ |
1840 |
|
|
debug("[ ARCBIOS GetDisplayStatus(%i) ]\n", |
1841 |
|
|
(int)cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1842 |
|
|
/* TODO: handle different values of 'handle'? */ |
1843 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = ARC_DSPSTAT_ADDR; |
1844 |
|
|
break; |
1845 |
|
|
case 0x100: |
1846 |
|
|
/* |
1847 |
|
|
* Undocumented, used by IRIX. |
1848 |
|
|
*/ |
1849 |
|
|
debug("[ ARCBIOS: IRIX 0x100 (?) ]\n"); |
1850 |
|
|
/* TODO */ |
1851 |
|
|
cpu->cd.mips.gpr[MIPS_GPR_V0] = 0; |
1852 |
|
|
break; |
1853 |
|
|
case 0x888: |
1854 |
|
|
/* |
1855 |
|
|
* Magical crash if there is no exception handling code. |
1856 |
|
|
*/ |
1857 |
|
|
fatal("EXCEPTION, but no exception handler installed yet.\n"); |
1858 |
|
|
quiet_mode = 0; |
1859 |
|
|
cpu_register_dump(cpu->machine, cpu, 1, 0x1); |
1860 |
|
|
cpu->running = 0; |
1861 |
|
|
cpu->dead = 1; |
1862 |
|
|
break; |
1863 |
|
|
default: |
1864 |
|
|
quiet_mode = 0; |
1865 |
|
|
cpu_register_dump(cpu->machine, cpu, 1, 0x1); |
1866 |
|
|
debug("a0 points to: "); |
1867 |
|
|
dump_mem_string(cpu, cpu->cd.mips.gpr[MIPS_GPR_A0]); |
1868 |
|
|
debug("\n"); |
1869 |
|
|
fatal("ARCBIOS: unimplemented vector 0x%x\n", vector); |
1870 |
|
|
cpu->running = 0; |
1871 |
|
|
cpu->dead = 1; |
1872 |
|
|
} |
1873 |
|
|
|
1874 |
|
|
return 1; |
1875 |
|
|
} |
1876 |
|
|
|
1877 |
|
|
|
1878 |
|
|
/* |
1879 |
|
|
* arcbios_set_64bit_mode(): |
1880 |
|
|
* |
1881 |
|
|
* Should be used for some SGI modes. |
1882 |
|
|
*/ |
1883 |
|
|
void arcbios_set_64bit_mode(int enable) |
1884 |
|
|
{ |
1885 |
|
|
arc_64bit = enable; |
1886 |
|
|
arc_wordlen = arc_64bit? sizeof(uint64_t) : sizeof(uint32_t); |
1887 |
|
|
} |
1888 |
|
|
|
1889 |
|
|
|
1890 |
|
|
/* |
1891 |
|
|
* arcbios_set_default_exception_handler(): |
1892 |
|
|
*/ |
1893 |
|
|
void arcbios_set_default_exception_handler(struct cpu *cpu) |
1894 |
|
|
{ |
1895 |
|
|
/* |
1896 |
|
|
* The default exception handlers simply jump to 0xbfc88888, |
1897 |
|
|
* which is then taken care of in arcbios_emul() above. |
1898 |
|
|
* |
1899 |
|
|
* 3c1abfc8 lui k0,0xbfc8 |
1900 |
|
|
* 375a8888 ori k0,k0,0x8888 |
1901 |
|
|
* 03400008 jr k0 |
1902 |
|
|
* 00000000 nop |
1903 |
|
|
*/ |
1904 |
|
|
store_32bit_word(cpu, 0xffffffff80000000ULL, 0x3c1abfc8); |
1905 |
|
|
store_32bit_word(cpu, 0xffffffff80000004ULL, 0x375a8888); |
1906 |
|
|
store_32bit_word(cpu, 0xffffffff80000008ULL, 0x03400008); |
1907 |
|
|
store_32bit_word(cpu, 0xffffffff8000000cULL, 0x00000000); |
1908 |
|
|
|
1909 |
|
|
store_32bit_word(cpu, 0xffffffff80000080ULL, 0x3c1abfc8); |
1910 |
|
|
store_32bit_word(cpu, 0xffffffff80000084ULL, 0x375a8888); |
1911 |
|
|
store_32bit_word(cpu, 0xffffffff80000088ULL, 0x03400008); |
1912 |
|
|
store_32bit_word(cpu, 0xffffffff8000008cULL, 0x00000000); |
1913 |
|
|
|
1914 |
|
|
store_32bit_word(cpu, 0xffffffff80000180ULL, 0x3c1abfc8); |
1915 |
|
|
store_32bit_word(cpu, 0xffffffff80000184ULL, 0x375a8888); |
1916 |
|
|
store_32bit_word(cpu, 0xffffffff80000188ULL, 0x03400008); |
1917 |
|
|
store_32bit_word(cpu, 0xffffffff8000018cULL, 0x00000000); |
1918 |
|
|
} |
1919 |
|
|
|
1920 |
|
|
|
1921 |
|
|
/* |
1922 |
|
|
* arcbios_init(): |
1923 |
|
|
* |
1924 |
|
|
* Should be called before any other arcbios function is used. |
1925 |
|
|
*/ |
1926 |
|
|
void arcbios_init(void) |
1927 |
|
|
{ |
1928 |
|
|
int i; |
1929 |
|
|
|
1930 |
|
|
/* File handles 0, 1, and 2 are stdin, stdout, and stderr. */ |
1931 |
|
|
for (i=0; i<MAX_HANDLES; i++) { |
1932 |
|
|
file_handle_in_use[i] = i<3? 1 : 0; |
1933 |
|
|
file_handle_string[i] = NULL; |
1934 |
|
|
arcbios_current_seek_offset[i] = 0; |
1935 |
|
|
} |
1936 |
|
|
} |
1937 |
|
|
|