1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #ifndef _EMUL_BUGAPI_C_
23 #define _EMUL_BUGAPI_C_
25 /* Note: this module is called via a table. There is no benefit in
28 #include "emul_generic.h"
29 #include "emul_bugapi.h"
40 /* from PowerPCBug Debugging Package User's Manual, part 2 of 2 and also bug.S - Dale Rahn */
41 #define _INCHR 0x000 /* Input character */
42 #define _INSTAT 0x001 /* Input serial port status */
43 #define _INLN 0x002 /* Input line (pointer / pointer format) */
44 #define _READSTR 0x003 /* Input string (pointer / count format) */
45 #define _READLN 0x004 /* Input line (pointer / count format) */
46 #define _CHKBRK 0x005 /* Check for break */
47 #define _DSKRD 0x010 /* Disk read */
48 #define _DSKWR 0x011 /* Disk write */
49 #define _DSKCFIG 0x012 /* Disk configure */
50 #define _DSKFMT 0x014 /* Disk format */
51 #define _DSKCTRL 0x015 /* Disk control */
52 #define _NETRD 0x018 /* Read from host */
53 #define _NETWR 0x019 /* Write to host */
54 #define _NETCFIG 0x01a /* Configure network parameters */
55 #define _NETOPN 0x01b /* Open file for reading */
56 #define _NETFRD 0x01c /* Retreive specified file blocks */
57 #define _NETCTRL 0x01d /* Implement special control functions */
58 #define _OUTCHR 0x020 /* Output character (pointer / pointer format) */
59 #define _OUTSTR 0x021 /* Output string (pointer / pointer format) */
60 #define _OUTLN 0x022 /* Output line (pointer / pointer format) */
61 #define _WRITE 0x023 /* Output string (pointer / count format) */
62 #define _WRITELN 0x024 /* Output line (pointer / count format) */
63 #define _WRITDLN 0x025 /* Output line with data (pointer / count format) */
64 #define _PCRLF 0x026 /* Output carriage return and line feed */
65 #define _ERASLN 0x027 /* Erase line */
66 #define _WRITD 0x028 /* Output string with data (pointer / count format) */
67 #define _SNDBRK 0x029 /* Send break */
68 #define _DELAY 0x043 /* Timer delay */
69 #define _RTC_TM 0x050 /* Time initialization for RTC */
70 #define _RTC_DT 0x051 /* Date initialization for RTC */
71 #define _RTC_DSP 0x052 /* Display RTC time and date */
72 #define _RTC_RD 0x053 /* Read the RTC registers */
73 #define _REDIR 0x060 /* Redirect I/O of a system call function */
74 #define _REDIR_I 0x061 /* Redirect input */
75 #define _REDIR_O 0x062 /* Redirect output */
76 #define _RETURN 0x063 /* Return to PPCbug */
77 #define _BINDEC 0x064 /* Convert binary to binary coded decimal (BCD) */
78 #define _CHANGEV 0x067 /* Parse value */
79 #define _STRCMP 0x068 /* Compare two strings (pointer / count format) */
80 #define _MULU32 0x069 /* Multiply two 32-bit unsigned integers */
81 #define _DIVU32 0x06a /* Divide two 32-bit unsigned integers */
82 #define _CHK_SUM 0x06b /* Generate checksum */
83 #define _BRD_ID 0x070 /* Return pointer to board ID packet */
84 #define _ENVIRON 0x071 /* Access boot environment parameters */
85 #define _DIAGFCN 0x074 /* Diagnostic function(s) */
86 #define _SIOPEPS 0x090 /* Retrieve SCSI pointers */
87 #define _IOINQ 0x120 /* Port inquire */
88 #define _IOINFORM 0x124 /* Port inform */
89 #define _IOCONFIG 0x128 /* Port configure */
90 #define _IODELETE 0x12c /* Port delete */
91 #define _SYMBOLTA 0x130 /* Attach symbol table */
92 #define _SYMBOLDA 0x131 /* Detach symbol table */
99 static const struct bug_map bug_mapping
[] = {
100 { _INCHR
, ".INCHR -- Input character" },
101 { _INSTAT
, ".INSTAT -- Input serial port status" },
102 { _INLN
, ".INLN -- Input line (pointer / pointer format)" },
103 { _READSTR
, ".READSTR -- Input string (pointer / count format)" },
104 { _READLN
, ".READLN -- Input line (pointer / count format)" },
105 { _CHKBRK
, ".CHKBRK -- Check for break" },
106 { _DSKRD
, ".DSKRD -- Disk read" },
107 { _DSKWR
, ".DSKWR -- Disk write" },
108 { _DSKCFIG
, ".DSKCFIG -- Disk configure" },
109 { _DSKFMT
, ".DSKFMT -- Disk format" },
110 { _DSKCTRL
, ".DSKCTRL -- Disk control" },
111 { _NETRD
, ".NETRD -- Read from host" },
112 { _NETWR
, ".NETWR -- Write to host" },
113 { _NETCFIG
, ".NETCFIG -- Configure network parameters" },
114 { _NETOPN
, ".NETOPN -- Open file for reading" },
115 { _NETFRD
, ".NETFRD -- Retreive specified file blocks" },
116 { _NETCTRL
, ".NETCTRL -- Implement special control functions" },
117 { _OUTCHR
, ".OUTCHR -- Output character" },
118 { _OUTSTR
, ".OUTSTR -- Output string (pointer / pointer format)" },
119 { _OUTLN
, ".OUTLN -- Output line (pointer / pointer format)" },
120 { _WRITE
, ".WRITE -- Output string (pointer / count format)" },
121 { _WRITELN
, ".WRITELN -- Output line (pointer / count format)" },
122 { _WRITDLN
, ".WRITDLN -- Output line with data (pointer / count format)" },
123 { _PCRLF
, ".PCRLF -- Output carriage return and line feed" },
124 { _ERASLN
, ".ERASLN -- Erase line" },
125 { _WRITD
, ".WRITD -- Output string with data (pointer / count format)" },
126 { _SNDBRK
, ".SNDBRK -- Send break" },
127 { _DELAY
, ".DELAY -- Timer delay" },
128 { _RTC_TM
, ".RTC_TM -- Time initialization for RTC" },
129 { _RTC_DT
, ".RTC_DT -- Date initialization for RTC" },
130 { _RTC_DSP
, ".RTC_DSP -- Display RTC time and date" },
131 { _RTC_RD
, ".RTC_RD -- Read the RTC registers" },
132 { _REDIR
, ".REDIR -- Redirect I/O of a system call function" },
133 { _REDIR
, ".REDIR -- Redirect input" },
134 { _REDIR
, ".REDIR -- Redirect output" },
135 { _RETURN
, ".RETURN -- Return to PPCbug" },
136 { _BINDEC
, ".BINDEC -- Convert binary to binary coded decimal (BCD)" },
137 { _CHANGEV
, ".CHANGEV -- Parse value" },
138 { _STRCMP
, ".STRCMP -- Compare two strings (pointer / count format)" },
139 { _MULU32
, ".MULU32 -- Multiply two 32-bit unsigned integers" },
140 { _DIVU32
, ".DIVU32 -- Divide two 32-bit unsigned integers" },
141 { _CHK_SUM
, ".CHK_SUM -- Generate checksum" },
142 { _BRD_ID
, ".BRD_ID -- Return pointer to board ID packet" },
143 { _ENVIRON
, ".ENVIRON -- Access boot environment parameters" },
144 { _DIAGFCN
, ".DIAGFCN -- Diagnostic function(s)" },
145 { _SIOPEPS
, ".SIOPEPS -- Retrieve SCSI pointers" },
146 { _IOINQ
, ".IOINQ -- Port inquire" },
147 { _IOINFORM
, ".IOINFORM -- Port inform" },
148 { _IOCONFIG
, ".IOCONFIG -- Port configure" },
149 { _IODELETE
, ".IODELETE -- Port delete" },
150 { _SYMBOLTA
, ".SYMBOLTA -- Attach symbol table" },
151 { _SYMBOLDA
, ".SYMBOLDA -- Detach symbol table" },
154 #ifndef BUGAPI_END_ADDRESS
155 #define BUGAPI_END_ADDRESS 0x100000
160 struct _os_emul_data
{
162 unsigned_word memory_size
;
163 unsigned_word top_of_stack
;
164 int interrupt_prefix
;
165 unsigned_word interrupt_vector_address
;
166 unsigned_word system_call_address
;
167 unsigned_word stall_cpu_loop_address
;
169 int floating_point_available
;
171 device_instance
*output
;
172 device_instance
*input
;
173 device_instance
*disk
;
177 static os_emul_data
*
178 emul_bugapi_create(device
*root
,
184 os_emul_data
*bugapi
;
186 /* check it really is for us */
188 && strcmp(name
, "bugapi") != 0
189 && strcmp(name
, "bug") != 0)
193 && bfd_get_start_address(image
) >= BUGAPI_END_ADDRESS
)
196 bugapi
= ZALLOC(os_emul_data
);
199 elf_binary
= image
->xvec
->flavour
== bfd_target_elf_flavour
;
202 emul_add_tree_options(root
, image
, "bug", "oea",
203 1 /*oea-interrupt-prefix*/);
205 /* add some real hardware */
206 emul_add_tree_hardware(root
);
211 = device_find_integer_property(root
, "/openprom/options/oea-memory-size");
212 bugapi
->interrupt_prefix
=
213 device_find_integer_property(root
, "/openprom/options/oea-interrupt-prefix");
214 bugapi
->interrupt_vector_address
= (bugapi
->interrupt_prefix
217 bugapi
->system_call_address
= (bugapi
->interrupt_vector_address
+ 0x00c00);
218 bugapi
->stall_cpu_loop_address
= (bugapi
->system_call_address
+ 0x000f0);
219 bugapi
->top_of_stack
= bugapi
->memory_size
- 0x1000;
220 bugapi
->little_endian
221 = device_find_boolean_property(root
, "/options/little-endian?");
222 bugapi
->floating_point_available
223 = device_find_boolean_property(root
, "/openprom/options/floating-point?");
224 bugapi
->input
= NULL
;
225 bugapi
->output
= NULL
;
228 device_tree_add_parsed(root
, "/openprom/init/register/0.pc 0x%lx",
229 (unsigned long)bfd_get_start_address(image
));
230 device_tree_add_parsed(root
, "/openprom/init/register/pc 0x%lx",
231 (unsigned long)bugapi
->stall_cpu_loop_address
);
232 device_tree_add_parsed(root
, "/openprom/init/register/sp 0x%lx",
233 (unsigned long)(bugapi
->top_of_stack
- 16));
234 device_tree_add_parsed(root
, "/openprom/init/register/msr 0x%x",
235 (msr_recoverable_interrupt
236 | (bugapi
->little_endian
237 ? (msr_little_endian_mode
238 | msr_interrupt_little_endian_mode
)
240 | (bugapi
->floating_point_available
241 ? msr_floating_point_available
243 | (bugapi
->interrupt_prefix
244 ? msr_interrupt_prefix
248 /* patch the system call instruction to call this emulation and then
250 node
= device_tree_add_parsed(root
, "/openprom/init/data@0x%lx",
251 (unsigned long)bugapi
->system_call_address
);
252 device_tree_add_parsed(node
, "./real-address 0x%lx",
253 (unsigned long)bugapi
->system_call_address
);
254 device_tree_add_parsed(node
, "./data 0x%x",
255 emul_call_instruction
);
256 node
= device_tree_add_parsed(root
, "/openprom/init/data@0x%lx",
257 (unsigned long)bugapi
->system_call_address
+ 4);
258 device_tree_add_parsed(node
, "./real-address 0x%lx",
259 (unsigned long)bugapi
->system_call_address
+ 4);
260 device_tree_add_parsed(node
, "./data 0x%x",
261 emul_rfi_instruction
);
263 /* patch the end of the system call instruction so that it contains
264 a loop to self instruction and point all the cpu's at this */
265 node
= device_tree_add_parsed(root
, "/openprom/init/data@0x%lx",
266 (unsigned long)bugapi
->stall_cpu_loop_address
);
267 device_tree_add_parsed(node
, "./real-address 0x%lx",
268 (unsigned long)bugapi
->stall_cpu_loop_address
);
269 device_tree_add_parsed(node
, "./data 0x%lx",
270 (unsigned long)emul_loop_instruction
);
272 device_tree_add_parsed(root
, "/openprom/init/stack/stack-type %s",
273 elf_binary
? "ppc-elf" : "ppc-xcoff");
275 device_tree_add_parsed(root
, "/openprom/init/load-binary/file-name \"%s",
276 bfd_get_filename(image
));
282 emul_bugapi_init(os_emul_data
*bugapi
,
285 /* get the current input/output devices that were created during
286 device tree initialization */
287 bugapi
->input
= device_find_ihandle_property(bugapi
->root
, "/chosen/stdin");
288 bugapi
->output
= device_find_ihandle_property(bugapi
->root
, "/chosen/stdout");
289 bugapi
->disk
= device_find_ihandle_property(bugapi
->root
, "/chosen/disk");
293 emul_bugapi_instruction_name(int call_id
)
295 static char buffer
[40];
298 for (i
= 0; i
< sizeof (bug_mapping
) / sizeof (bug_mapping
[0]); i
++)
300 if (bug_mapping
[i
].value
== call_id
)
301 return bug_mapping
[i
].info
;
304 (void) sprintf (buffer
, "Unknown bug call 0x%x", call_id
);
309 emul_bugapi_do_read(os_emul_data
*bugapi
,
315 unsigned char *scratch_buffer
;
318 /* get a tempoary bufer */
319 scratch_buffer
= (unsigned char *) zalloc(nbytes
);
321 /* check if buffer exists by reading it */
322 emul_read_buffer((void *)scratch_buffer
, buf
, nbytes
, processor
, cia
);
325 status
= device_instance_read(bugapi
->input
,
326 (void *)scratch_buffer
, nbytes
);
328 /* -1 = error, -2 = nothing available - see "serial" [IEEE1275] */
334 emul_write_buffer((void *)scratch_buffer
, buf
, status
, processor
, cia
);
336 /* Bugapi chops off the trailing n, but leaves it in the buffer */
337 if (scratch_buffer
[status
-1] == '\n' || scratch_buffer
[status
-1] == '\r')
341 zfree(scratch_buffer
);
346 emul_bugapi_do_diskio(os_emul_data
*bugapi
,
349 unsigned_word descriptor_addr
,
352 struct dskio_descriptor
{
356 unsigned_word pbuffer
;
360 #define BUG_FILE_MARK 0x80
361 #define IGNORE_FILENUM 0x02
362 #define END_OF_FILE 0x01
366 emul_read_buffer(&descriptor
, descriptor_addr
, sizeof(descriptor
),
368 T2H(descriptor
.ctrl_lun
);
369 T2H(descriptor
.dev_lun
);
370 T2H(descriptor
.status
);
371 T2H(descriptor
.pbuffer
);
372 T2H(descriptor
.blk_num
);
373 T2H(descriptor
.blk_cnt
);
374 T2H(descriptor
.flag
);
375 T2H(descriptor
.addr_mod
);
376 for (block
= 0; block
< descriptor
.blk_cnt
; block
++) {
377 unsigned_1 buf
[512]; /*????*/
378 unsigned_word block_nr
= descriptor
.blk_num
+ block
;
379 unsigned_word byte_nr
= block_nr
* sizeof(buf
);
380 unsigned_word block_addr
= descriptor
.pbuffer
+ block
*sizeof(buf
);
381 if (device_instance_seek(bugapi
->disk
, 0, byte_nr
) < 0)
382 error("emul_bugapi_do_diskio: bad seek\n");
385 if (device_instance_read(bugapi
->disk
, buf
, sizeof(buf
)) != sizeof(buf
))
386 error("emul_bugapi_do_diskio: bad read\n");
387 emul_write_buffer(buf
, block_addr
, sizeof(buf
), processor
, cia
);
390 emul_read_buffer(buf
, block_addr
, sizeof(buf
), processor
, cia
);
391 if (device_instance_write(bugapi
->disk
, buf
, sizeof(buf
)) != sizeof(buf
))
392 error("emul_bugapi_do_diskio: bad write\n");
395 error("emul_bugapi_do_diskio: bad switch\n");
401 emul_bugapi_do_write(os_emul_data
*bugapi
,
408 void *scratch_buffer
= NULL
;
411 /* get a tempoary bufer */
414 scratch_buffer
= zalloc(nbytes
);
417 nr_moved
= vm_data_map_read_buffer(cpu_data_map(processor
),
421 if (nr_moved
!= nbytes
) {
422 /* FIXME - should handle better */
423 error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
428 device_instance_write(bugapi
->output
, scratch_buffer
, nbytes
);
430 zfree(scratch_buffer
);
434 device_instance_write(bugapi
->output
, suffix
, strlen(suffix
));
440 emul_bugapi_instruction_call(cpu
*processor
,
443 os_emul_data
*bugapi
)
445 const int call_id
= cpu_registers(processor
)->gpr
[10];
448 #define MY_INDEX itable_instruction_call
449 ITRACE (trace_os_emul
,
450 (" 0x%x %s, r3 = 0x%lx, r4 = 0x%lx\n",
451 call_id
, emul_bugapi_instruction_name (call_id
),
452 (long)cpu_registers(processor
)->gpr
[3],
453 (long)cpu_registers(processor
)->gpr
[4]));;
455 /* check that this isn't an invalid instruction */
456 if (cia
!= bugapi
->system_call_address
)
460 error("emul-bugapi: unimplemented bugapi %s from address 0x%lx\n",
461 emul_bugapi_instruction_name (call_id
), SRR0
);
463 /* read a single character, output r3 = byte */
464 /* FIXME: Add support to unbuffer input */
466 if (device_instance_read(bugapi
->input
, (void *)&uc
, 1) <= 0)
468 cpu_registers(processor
)->gpr
[3] = uc
;
470 /* read a line of at most 256 bytes, r3 = ptr to 1st byte, output r3 = ptr to last byte+1 */
472 cpu_registers(processor
)->gpr
[3] += emul_bugapi_do_read(bugapi
,
474 cpu_registers(processor
)->gpr
[3],
477 /* output a character, r3 = character */
480 char out
= (char)cpu_registers(processor
)->gpr
[3];
481 device_instance_write(bugapi
->output
, &out
, 1);
484 /* output a string, r3 = ptr to 1st byte, r4 = ptr to last byte+1 */
486 emul_bugapi_do_write(bugapi
,
488 cpu_registers(processor
)->gpr
[3],
489 cpu_registers(processor
)->gpr
[4] - cpu_registers(processor
)->gpr
[3],
492 /* output a string followed by \r\n, r3 = ptr to 1st byte, r4 = ptr to last byte+1 */
495 emul_bugapi_do_write(bugapi
,
497 cpu_registers(processor
)->gpr
[3],
498 cpu_registers(processor
)->gpr
[4] - cpu_registers(processor
)->gpr
[3],
503 device_instance_write(bugapi
->output
, "\n", 1);
505 /* read/write blocks of data to/from the disk */
508 emul_bugapi_do_diskio(bugapi
, processor
, cia
,
509 cpu_registers(processor
)->gpr
[3],
512 /* return to ppcbug monitor (exiting with gpr[3] as status is not
513 part of the bug monitor) */
515 cpu_halt(processor
, cia
, was_exited
, cpu_registers(processor
)->gpr
[3]);
519 /* the instruction following this one is a RFI. Thus by just
520 continuing the return from system call is performed */
523 const os_emul emul_bugapi
= {
528 emul_bugapi_instruction_call
,