1 /* This file is part of the program psim.
3 Copyright (C) 1994-1995, 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.
25 #ifndef STATIC_INLINE_DEVICES
26 #define STATIC_INLINE_DEVICES STATIC_INLINE
58 /* Helper functions */
60 /* Generic device init: Attaches the device of size <nr_bytes> (taken
61 from <name>@<int>,<nr_bytes>) to its parent at address zero and
62 with read/write access. */
64 STATIC_INLINE_DEVICES
void
65 generic_init_callback(const device
*me
,
70 if (scand_uw_u(me
->name
, &addr
, &nr_bytes
) != 2)
71 error("generic_init_callback() invalid nr_bytes in %s\n", me
->name
);
72 me
->parent
->callback
->attach_address(me
->parent
,
84 /* inimplemented versions of each function */
87 unimp_device_init(const device
*me
,
90 error("device_init_callback for %s not implemented\n", me
->name
);
94 unimp_device_attach_address(const device
*me
,
101 const device
*who
) /*callback/default*/
103 error("device_attach_address_callback for %s not implemented\n", me
->name
);
107 unimp_device_detach_address(const device
*me
,
114 const device
*who
) /*callback/default*/
116 error("device_detach_address_callback for %s not implemented\n", me
->name
);
119 INLINE_DEVICES
unsigned
120 unimp_device_io_read_buffer(const device
*me
,
128 error("device_io_read_buffer_callback for %s not implemented\n", me
->name
);
132 INLINE_DEVICES
unsigned
133 unimp_device_io_write_buffer(const device
*me
,
141 error("device_io_write_buffer_callback for %s not implemented\n", me
->name
);
145 INLINE_DEVICES
unsigned
146 unimp_device_dma_read_buffer(const device
*me
,
152 error("device_dma_read_buffer_callback for %s not implemented\n", me
->name
);
156 INLINE_DEVICES
unsigned
157 unimp_device_dma_write_buffer(const device
*me
,
162 int violate_read_only_section
)
164 error("device_dma_write_buffer_callback for %s not implemented\n", me
->name
);
169 unimp_device_attach_interrupt(const device
*me
,
174 error("device_attach_interrupt_callback for %s not implemented\n", me
->name
);
178 unimp_device_detach_interrupt(const device
*me
,
183 error("device_detach_interrupt_callback for %s not implemented\n", me
->name
);
187 unimp_device_interrupt(const device
*me
,
190 int interrupt_status
,
194 error("device_interrupt_callback for %s not implemented\n", me
->name
);
198 unimp_device_interrupt_ack(const device
*me
,
200 int interrupt_status
)
202 error("device_interrupt_ack_callback for %s not implemented\n", me
->name
);
206 unimp_device_ioctl(const device
*me
,
212 error("device_ioctl_callback for %s not implemented\n", me
->name
);
217 /* ignore/passthrough versions of each function */
220 ignore_device_init(const device
*me
,
227 pass_device_attach_address(const device
*me
,
234 const device
*who
) /*callback/default*/
236 DTRACE_ATTACH_ADDRESS(pass
);
237 me
->parent
->callback
->attach_address(me
->parent
, name
, attach
,
238 space
, addr
, nr_bytes
,
244 pass_device_detach_address(const device
*me
,
251 const device
*who
) /*callback/default*/
253 DTRACE_DETACH_ADDRESS(pass
);
254 me
->parent
->callback
->detach_address(me
->parent
, name
, attach
,
255 space
, addr
, nr_bytes
, access
,
259 INLINE_DEVICES
unsigned
260 pass_device_dma_read_buffer(const device
*me
,
266 DTRACE_DMA_READ_BUFFER(pass
);
267 return me
->parent
->callback
->dma_read_buffer(me
->parent
, dest
,
268 space
, addr
, nr_bytes
);
271 INLINE_DEVICES
unsigned
272 pass_device_dma_write_buffer(const device
*me
,
277 int violate_read_only_section
)
279 DTRACE_DMA_WRITE_BUFFER(pass
);
280 return me
->parent
->callback
->dma_write_buffer(me
->parent
, source
,
283 violate_read_only_section
);
287 pass_device_attach_interrupt(const device
*me
,
292 me
->parent
->callback
->attach_interrupt(me
->parent
, who
,
293 interrupt_line
, name
);
297 pass_device_detach_interrupt(const device
*me
,
302 me
->parent
->callback
->detach_interrupt(me
->parent
, who
,
303 interrupt_line
, name
);
308 pass_device_interrupt(const device
*me
,
311 int interrupt_status
,
315 me
->parent
->callback
->interrupt(me
->parent
, who
,
316 interrupt_line
, interrupt_status
,
322 /* Simple console device: console@)x<address>,16
324 Input characters are taken from the keyboard, output characters
325 sent to the terminal. Echoing of characters is not disabled.
327 The device has four registers:
334 Where a nonzero status register indicates that the device is ready
335 (input fifo contains a character or output fifo has space). */
337 typedef struct _console_buffer
{
340 event_entry_tag event_tag
;
343 typedef struct _console_device
{
344 console_buffer input
;
345 console_buffer output
;
349 console_read_buffer
= 0,
350 console_read_status
= 4,
351 console_write_buffer
= 8,
352 console_write_status
= 12,
353 console_offset_mask
= 0xc,
358 STATIC_INLINE_DEVICES
unsigned
359 console_io_read_buffer_callback(const device
*me
,
367 console_device
*console
= (console_device
*)me
->data
;
369 DTRACE_IO_READ_BUFFER(console
);
371 /* determine what was read */
375 case console_read_buffer
:
376 val
= console
->input
.buffer
;
379 case console_read_status
:
380 { /* check for input */
383 /* get the old status */
384 flags
= fcntl(0, F_GETFL
, 0);
390 /* temp, disable blocking IO */
391 status
= fcntl(0, F_SETFL
, flags
| O_NDELAY
);
398 status
= read(0, &console
->input
.buffer
, 1);
400 console
->input
.status
= 1;
403 console
->input
.status
= 0;
405 /* return to regular vewing */
406 fcntl(0, F_SETFL
, flags
);
408 val
= console
->input
.status
;
411 case console_write_buffer
:
412 val
= console
->output
.buffer
;
415 case console_write_status
:
416 val
= console
->output
.status
;
420 error("console_read_callback() internal error\n");
426 bzero(dest
, nr_bytes
);
427 *(unsigned_1
*)dest
= val
;
431 STATIC_INLINE_DEVICES
unsigned
432 console_io_write_buffer_callback(const device
*me
,
440 console_device
*console
= (console_device
*)me
->data
;
441 unsigned_1 val
= *(unsigned8
*)source
;
442 DTRACE_IO_WRITE_BUFFER(console
);
445 case console_read_buffer
:
446 console
->input
.buffer
= val
;
448 case console_read_status
:
449 console
->input
.status
= val
;
451 case console_write_buffer
:
452 DTRACE(console
, ("<%c:%d>", val
, val
));
453 printf_filtered("%c",val
) ;
454 console
->output
.buffer
= val
;
455 console
->output
.status
= 1;
457 case console_write_status
:
458 console
->output
.status
= val
;
461 error("console_write_callback() internal error\n");
468 static device_callbacks
const console_callbacks
= {
469 generic_init_callback
,
470 unimp_device_attach_address
,
471 unimp_device_detach_address
,
472 console_io_read_buffer_callback
,
473 console_io_write_buffer_callback
,
474 unimp_device_dma_read_buffer
,
475 unimp_device_dma_write_buffer
,
476 unimp_device_attach_interrupt
,
477 unimp_device_detach_interrupt
,
478 unimp_device_interrupt
,
479 unimp_device_interrupt_ack
,
484 STATIC_INLINE_DEVICES
const device
*
485 console_create(const char *name
,
486 const char *full_name
,
487 const device
*parent
)
489 /* create the descriptor */
490 console_device
*console
= ZALLOC(console_device
);
492 /* fill in the details */
493 console
->output
.status
= 1;
494 console
->output
.buffer
= '\0';
495 console
->input
.status
= 0;
496 console
->input
.buffer
= '\0';
498 /* insert into the device tree along with its address info */
499 return device_create_from(name
,
508 /* ICU device: icu@0x<address>,4
510 Single 4 byte register. Read returns processor number. Write
511 interrupts specified processor.
513 Illustrates passing of events to parent device. Passing of
514 interrupts to parent bus.
516 NB: For the sake of illustrating the passing of interrupts. This
517 device doesn't pass interrupt events to its parent. Instead it
518 passes them back to its self. */
520 STATIC_INLINE_DEVICES
unsigned
521 icu_io_read_buffer_callback(const device
*me
,
530 DTRACE_IO_READ_BUFFER(icu
);
531 val
= cpu_nr(processor
);
532 bzero(dest
, nr_bytes
);
533 *(unsigned_1
*)dest
= val
;
538 STATIC_INLINE_DEVICES
unsigned
539 icu_io_write_buffer_callback(const device
*me
,
547 unsigned_1 val
= H2T_1(*(unsigned_1
*)source
);
548 DTRACE_IO_WRITE_BUFFER(icu
);
549 /* tell the parent device that the interrupt lines have changed.
550 For this fake ICU. The interrupt lines just indicate the cpu to
552 me
->parent
->callback
->interrupt(me
->parent
, me
,
559 static device_callbacks
const icu_callbacks
= {
560 generic_init_callback
,
561 unimp_device_attach_address
,
562 unimp_device_detach_address
,
563 icu_io_read_buffer_callback
,
564 icu_io_write_buffer_callback
,
565 unimp_device_dma_read_buffer
,
566 unimp_device_dma_write_buffer
,
567 unimp_device_attach_interrupt
,
568 unimp_device_detach_interrupt
,
569 unimp_device_interrupt
,
570 unimp_device_interrupt_ack
,
576 /* HALT device: halt@0x<address>,4
578 With real hardware, the processor operation is normally terminated
579 through a reset. This device illustrates how a reset device could
580 be attached to an address */
583 STATIC_INLINE_DEVICES
unsigned
584 halt_io_read_buffer_callback(const device
*me
,
592 DTRACE_IO_READ_BUFFER(halt
);
593 cpu_halt(processor
, cia
, was_exited
, 0);
598 STATIC_INLINE_DEVICES
unsigned
599 halt_io_write_buffer_callback(const device
*me
,
607 DTRACE_IO_WRITE_BUFFER(halt
);
608 cpu_halt(processor
, cia
, was_exited
, 0);
613 static device_callbacks
const halt_callbacks
= {
614 generic_init_callback
,
615 unimp_device_attach_address
,
616 unimp_device_detach_address
,
617 halt_io_read_buffer_callback
,
618 halt_io_write_buffer_callback
,
619 unimp_device_dma_read_buffer
,
620 unimp_device_dma_write_buffer
,
621 unimp_device_attach_interrupt
,
622 unimp_device_detach_interrupt
,
623 unimp_device_interrupt
,
624 unimp_device_interrupt_ack
,
630 /* Register init device: register@<name>,0x<value>[,<processor>]
632 This strange device is used to initialize the processors registers
633 as part of the initialization. */
635 STATIC_INLINE_DEVICES
void
636 register_init_callback(const device
*me
,
643 DTRACE_INIT(register);
644 status
= scand_c_uw_u(me
->name
, name
, sizeof(name
), &value
, &which_cpu
);
646 case 2: /* register@<name>,<value> */
647 psim_write_register(system
, -1, &value
, name
, cooked_transfer
);
649 case 3: /* register@<name>,<value>,<processor> */
650 psim_write_register(system
, which_cpu
, &value
, name
, cooked_transfer
);
653 error("register_init_callback() invalid register init %s\n", me
->name
);
659 static device_callbacks
const register_callbacks
= {
660 register_init_callback
,
661 unimp_device_attach_address
,
662 unimp_device_detach_address
,
663 unimp_device_io_read_buffer
,
664 unimp_device_io_write_buffer
,
665 unimp_device_dma_read_buffer
,
666 unimp_device_dma_write_buffer
,
667 unimp_device_attach_interrupt
,
668 unimp_device_detach_interrupt
,
669 unimp_device_interrupt
,
670 unimp_device_interrupt_ack
,
676 /* VEA VM device: vm@0x<stack-base>,<nr_bytes>
678 A VEA mode device. This sets its self up as the default memory
679 device capturing all accesses (reads/writes) to currently unmapped
680 addresses. If the unmaped access falls within unallocated stack or
681 heap address ranges then memory is allocated and the access is
684 During init phase, this device expects to receive `attach' requests
685 from its children for the text/data/bss memory areas. Typically,
686 this would be done by the binary device.
688 STACK: The location of the stack in memory is specified as part of
689 the devices name. Unmaped accesses that fall within the stack
690 space result in the allocated stack being grown downwards so that
691 it includes the page of the culprit access.
693 HEAP: During initialization, the vm device monitors all `attach'
694 operations from its children using this to determine the initial
695 location of the heap. The heap is then extended by system calls
696 that frob the heap upper bound variable (see system.c). */
699 typedef struct _vm_device
{
700 /* area of memory valid for stack addresses */
701 unsigned_word stack_base
; /* min possible stack value */
702 unsigned_word stack_bound
;
703 unsigned_word stack_lower_limit
;
704 /* area of memory valid for heap addresses */
705 unsigned_word heap_base
;
706 unsigned_word heap_bound
;
707 unsigned_word heap_upper_limit
;
711 STATIC_INLINE_DEVICES
void
712 vm_init_callback(const device
*me
,
715 vm_device
*vm
= (vm_device
*)me
->data
;
718 /* revert the stack/heap variables to their defaults */
719 vm
->stack_lower_limit
= vm
->stack_bound
;
722 vm
->heap_upper_limit
= 0;
724 /* establish this device as the default memory handler */
725 me
->parent
->callback
->attach_address(me
->parent
,
728 0 /*address space - ignore*/,
730 0 /*nr_bytes - ignore*/,
731 access_read_write
/*access*/,
736 STATIC_INLINE_DEVICES
void
737 vm_attach_address(const device
*me
,
744 const device
*who
) /*callback/default*/
746 vm_device
*vm
= (vm_device
*)me
->data
;
747 DTRACE_ATTACH_ADDRESS(vm
);
748 /* update end of bss if necessary */
749 if (vm
->heap_base
< addr
+ nr_bytes
) {
750 vm
->heap_base
= addr
+ nr_bytes
;
751 vm
->heap_bound
= addr
+ nr_bytes
;
752 vm
->heap_upper_limit
= addr
+ nr_bytes
;
754 me
->parent
->callback
->attach_address(me
->parent
,
755 "vm@0x0,0", /* stop remap */
765 STATIC_INLINE_DEVICES
unsigned
766 add_vm_space(const device
*me
,
772 vm_device
*vm
= (vm_device
*)me
->data
;
773 unsigned_word block_addr
;
774 unsigned block_nr_bytes
;
776 /* an address in the stack area, allocate just down to the addressed
778 if (addr
>= vm
->stack_base
&& addr
< vm
->stack_lower_limit
) {
779 block_addr
= FLOOR_PAGE(addr
);
780 block_nr_bytes
= vm
->stack_lower_limit
- block_addr
;
781 vm
->stack_lower_limit
= block_addr
;
783 /* an address in the heap area, allocate all of the required heap */
784 else if (addr
>= vm
->heap_upper_limit
&& addr
< vm
->heap_bound
) {
785 block_addr
= vm
->heap_upper_limit
;
786 block_nr_bytes
= vm
->heap_bound
- vm
->heap_upper_limit
;
787 vm
->heap_upper_limit
= vm
->heap_bound
;
789 /* oops - an invalid address - abort the cpu */
790 else if (processor
!= NULL
) {
791 cpu_halt(processor
, cia
, was_signalled
, SIGSEGV
);
794 /* 2*oops - an invalid address and no processor */
799 /* got the parameters, allocate the space */
800 me
->parent
->callback
->attach_address(me
->parent
,
801 "vm@0x0,0", /* stop remap */
808 return block_nr_bytes
;
812 STATIC_INLINE_DEVICES
unsigned
813 vm_io_read_buffer_callback(const device
*me
,
821 DTRACE_IO_READ_BUFFER(vm
);
822 if (add_vm_space(me
, addr
, nr_bytes
, processor
, cia
) >= nr_bytes
) {
823 bzero(dest
, nr_bytes
); /* always initialized to zero */
831 STATIC_INLINE_DEVICES
unsigned
832 vm_io_write_buffer_callback(const device
*me
,
840 DTRACE_IO_WRITE_BUFFER(vm
);
841 if (add_vm_space(me
, addr
, nr_bytes
, processor
, cia
) >= nr_bytes
) {
842 return me
->parent
->callback
->dma_write_buffer(me
->parent
, source
,
845 0/*violate_read_only*/);
853 vm_ioctl_callback(const device
*me
,
859 /* While the caller is notified that the heap has grown by the
860 requested amount, the heap is infact extended out to a page
862 vm_device
*vm
= (vm_device
*)me
->data
;
863 unsigned_word new_break
= ALIGN_8(cpu_registers(processor
)->gpr
[3]);
864 unsigned_word old_break
= vm
->heap_bound
;
865 signed_word delta
= new_break
- old_break
;
867 vm
->heap_bound
= ALIGN_PAGE(new_break
);
868 cpu_registers(processor
)->gpr
[0] = 0;
869 cpu_registers(processor
)->gpr
[3] = new_break
;
873 static device_callbacks
const vm_callbacks
= {
876 pass_device_detach_address
,
877 vm_io_read_buffer_callback
,
878 vm_io_write_buffer_callback
,
879 unimp_device_dma_read_buffer
,
880 pass_device_dma_write_buffer
,
881 unimp_device_attach_interrupt
,
882 unimp_device_detach_interrupt
,
883 unimp_device_interrupt
,
884 unimp_device_interrupt_ack
,
889 STATIC_INLINE_DEVICES
const device
*
890 vea_vm_create(const char *name
,
891 const char *full_name
,
892 const device
*parent
)
894 vm_device
*vm
= ZALLOC(vm_device
);
898 /* extract out the stack parameters */
899 if (scand_uw_u(name
, &addr
, &nr_bytes
) != 2)
900 error("vm_device_create() invalid vm device %s\n", name
);
901 vm
->stack_base
= addr
;
902 vm
->stack_bound
= addr
+ nr_bytes
;
904 /* insert in the tree including the buffer */
905 return device_create_from(name
,
914 /* Memory init device: memory@0x<addr>,<size>,<access>
916 This strange device is used create sections of memory */
918 STATIC_INLINE_DEVICES
void
919 memory_init_callback(const device
*me
,
928 nr_args
= scand_uw_u_u(me
->name
, &addr
, &nr_bytes
, &access
);
931 access
= access_read_write_exec
;
936 error("memory_init_callback() invalid memory device %s\n", me
->name
);
940 me
->parent
->callback
->attach_address(me
->parent
,
951 static device_callbacks
const memory_callbacks
= {
952 memory_init_callback
,
953 unimp_device_attach_address
,
954 unimp_device_detach_address
,
955 unimp_device_io_read_buffer
,
956 unimp_device_io_write_buffer
,
957 unimp_device_dma_read_buffer
,
958 unimp_device_dma_write_buffer
,
959 unimp_device_attach_interrupt
,
960 unimp_device_detach_interrupt
,
961 unimp_device_interrupt
,
962 unimp_device_interrupt_ack
,
968 /* IOBUS device: iobus@<address>
970 Simple bus on which some IO devices live */
972 STATIC_INLINE_DEVICES
void
973 iobus_attach_address_callback(const device
*me
,
980 const device
*who
) /*callback/default*/
982 unsigned_word iobus_addr
;
984 if (type
== attach_default
)
985 error("iobus_attach_address_callback() no default for %s/%s\n",
988 error("iobus_attach_address_callback() no space for %s/%s\n",
990 /* get the bus address */
991 if (scand_uw(me
->name
, &iobus_addr
) != 1)
992 error("iobus_attach_address_callback() invalid address for %s\n",
994 me
->parent
->callback
->attach_address(me
->parent
,
1005 STATIC_INLINE_DEVICES
void
1006 iobus_do_interrupt(event_queue
*queue
,
1009 cpu
*target
= (cpu
*)data
;
1010 /* try to interrupt the processor. If the attempt fails, try again
1012 if (!external_interrupt(target
))
1013 event_queue_schedule(queue
, 1, iobus_do_interrupt
, target
);
1017 STATIC_INLINE_DEVICES
void
1018 iobus_interrupt_callback(const device
*me
,
1021 int interrupt_status
,
1025 /* the interrupt controler can't interrupt a cpu at any time.
1026 Rather it must synchronize with the system clock before
1027 performing an interrupt on the given processor */
1028 psim
*system
= cpu_system(processor
);
1029 cpu
*target
= psim_cpu(system
, interrupt_status
);
1030 if (target
!= NULL
) {
1031 event_queue
*events
= cpu_event_queue(target
);
1032 event_queue_schedule(events
, 1, iobus_do_interrupt
, target
);
1037 static device_callbacks
const iobus_callbacks
= {
1039 iobus_attach_address_callback
,
1040 unimp_device_detach_address
,
1041 unimp_device_io_read_buffer
,
1042 unimp_device_io_write_buffer
,
1043 unimp_device_dma_read_buffer
,
1044 unimp_device_dma_write_buffer
,
1045 unimp_device_attach_interrupt
,
1046 unimp_device_detach_interrupt
,
1047 iobus_interrupt_callback
,
1048 unimp_device_interrupt_ack
,
1054 /* FILE device: file@0x<address>,<file-name>
1055 (later - file@0x<address>,<size>,<file-offset>,<file-name>)
1057 Specifies a file to read directly into memory starting at <address> */
1060 STATIC_INLINE_DEVICES
void
1061 file_init_callback(const device
*me
,
1071 if ((file_name
= strchr(me
->name
, ',')) == NULL
1072 || scand_uw(me
->name
, &addr
) != 1)
1073 error("file_init_callback() invalid file device %s\n", me
->name
);
1075 /* open the file to load */
1076 file_name
++; /* skip the `,' */
1077 image
= fopen(file_name
, "r");
1079 error("file_init_callback() file open failed for %s\n", me
->name
);
1081 /* read it in slowly */
1083 while (fread(&buf
, 1, 1, image
) > 0) {
1084 if (me
->parent
->callback
->dma_write_buffer(me
->parent
,
1086 0 /*address-space*/,
1089 1 /*violate ro*/) != 1)
1090 error("file_init_callback() failed to write to address 0x%x, offset %d\n",
1095 /* close down again */
1100 static device_callbacks
const file_callbacks
= {
1102 unimp_device_attach_address
,
1103 unimp_device_detach_address
,
1104 unimp_device_io_read_buffer
,
1105 unimp_device_io_write_buffer
,
1106 unimp_device_dma_read_buffer
,
1107 unimp_device_dma_write_buffer
,
1108 unimp_device_attach_interrupt
,
1109 unimp_device_detach_interrupt
,
1110 unimp_device_interrupt
,
1111 unimp_device_interrupt_ack
,
1117 /* HTAB: htab@0x<address>,<nr_bytes>
1118 PTE: pte@0x<effective-address>,0x<real-address>,<nr_bytes>
1120 HTAB defines the location (in physical memory) of a HASH table.
1121 PTE (as a child of HTAB) defines a mapping that is to be entered
1124 NB: All the work in this device is done during init by the PTE.
1125 The pte, looks up its parent to determine the address of the HTAB
1126 and then uses DMA calls to establish the required mapping. */
1129 STATIC_INLINE_DEVICES
void
1130 htab_init_callback(const device
*me
,
1134 /* only the pte does work */
1135 if (strncmp(me
->name
, "pte@", strlen("pte@")) == 0) {
1136 unsigned_word htab_ra
;
1137 unsigned htab_nr_bytes
;
1138 unsigned_word pte_ea
;
1139 unsigned_word pte_ra
;
1140 unsigned pte_nr_bytes
;
1141 /* determine the location/size of the hash table */
1142 if (scand_uw_u(me
->parent
->name
, &htab_ra
, &htab_nr_bytes
) != 2)
1143 error("htab_init_callback() htab entry %s invalid\n",
1145 /* determine the location/size of the mapping */
1146 if (scand_uw_uw_u(me
->name
, &pte_ea
, &pte_ra
, &pte_nr_bytes
) != 3)
1147 error("htab_init_callback() pte entry %s invalid\n", me
->name
);
1148 error("Map ea=0x%x, ra=0x%x, nr_bytes=%d using htab=0x%x, nr_bytes=%d\n",
1149 pte_ea
, pte_ra
, pte_nr_bytes
, htab_ra
, htab_nr_bytes
);
1154 static device_callbacks
const htab_callbacks
= {
1156 unimp_device_attach_address
,
1157 unimp_device_detach_address
,
1158 unimp_device_io_read_buffer
,
1159 unimp_device_io_write_buffer
,
1160 unimp_device_dma_read_buffer
,
1161 unimp_device_dma_write_buffer
,
1162 unimp_device_attach_interrupt
,
1163 unimp_device_detach_interrupt
,
1164 unimp_device_interrupt
,
1165 unimp_device_interrupt_ack
,
1171 /* Simulator device: sim@0x<address>,<nr_bytes>
1173 Eventually gives access to the hardware configuration. For
1174 instance, it could allow the setting (on the fly) of variables such
1175 as hardware floating-point or strict-alignment.
1177 It's intended use is as part of testing the simulators
1180 static device_callbacks
const sim_callbacks
= {
1182 unimp_device_attach_address
,
1183 unimp_device_detach_address
,
1184 unimp_device_io_read_buffer
,
1185 unimp_device_io_write_buffer
,
1186 unimp_device_dma_read_buffer
,
1187 unimp_device_dma_write_buffer
,
1188 unimp_device_attach_interrupt
,
1189 unimp_device_detach_interrupt
,
1190 unimp_device_interrupt
,
1191 unimp_device_interrupt_ack
,
1197 /* Load device: *binary@<file-name>
1199 Assuming that <file-name> is an executable file understood by BFD,
1200 this device loads or maps the relevant text/data segments into
1201 memory using dma. */
1203 STATIC_INLINE_DEVICES
void
1204 update_for_binary_section(bfd
*abfd
,
1205 asection
*the_section
,
1208 unsigned_word section_vma
;
1209 unsigned_word section_size
;
1211 device
*me
= (device
*)obj
;
1213 /* skip the section if no memory to allocate */
1214 if (! (bfd_get_section_flags(abfd
, the_section
) & SEC_ALLOC
))
1217 /* check/ignore any sections of size zero */
1218 section_size
= bfd_get_section_size_before_reloc(the_section
);
1219 if (section_size
== 0)
1222 /* find where it is to go */
1223 section_vma
= bfd_get_section_vma(abfd
, the_section
);
1226 ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
1227 bfd_get_section_name(abfd
, the_section
),
1230 (long)bfd_get_section_flags(abfd
, the_section
),
1231 bfd_get_section_flags(abfd
, the_section
) & SEC_LOAD
? " LOAD" : "",
1232 bfd_get_section_flags(abfd
, the_section
) & SEC_CODE
? " CODE" : "",
1233 bfd_get_section_flags(abfd
, the_section
) & SEC_DATA
? " DATA" : "",
1234 bfd_get_section_flags(abfd
, the_section
) & SEC_ALLOC
? " ALLOC" : "",
1235 bfd_get_section_flags(abfd
, the_section
) & SEC_READONLY
? " READONLY" : ""
1238 /* determine the devices access */
1239 access
= access_read
;
1240 if (bfd_get_section_flags(abfd
, the_section
) & SEC_CODE
)
1241 access
|= access_exec
;
1242 if (!(bfd_get_section_flags(abfd
, the_section
) & SEC_READONLY
))
1243 access
|= access_write
;
1245 /* if a map, pass up a request to create the memory in core */
1246 if (strncmp(me
->name
, "map-binary@", strlen("map-binary@")) == 0)
1247 me
->parent
->callback
->attach_address(me
->parent
,
1250 0 /*address space*/,
1256 /* if a load dma in the required data */
1257 if (bfd_get_section_flags(abfd
, the_section
) & SEC_LOAD
) {
1258 void *section_init
= zalloc(section_size
);
1259 if (!bfd_get_section_contents(abfd
,
1263 bfd_perror("core:load_section()");
1264 error("load of data failed");
1267 if (me
->parent
->callback
->dma_write_buffer(me
->parent
,
1272 1 /*violate_read_only*/)
1274 error("data_init_callback() broken transfer for %s\n", me
->name
);
1275 zfree(section_init
); /* only free if load */
1280 STATIC_INLINE_DEVICES
void
1281 binary_init_callback(const device
*me
,
1284 char file_name
[100];
1286 DTRACE_INIT(binary
);
1288 /* get a file name */
1289 if (scand_c(me
->name
, file_name
, sizeof(file_name
)) != 1)
1290 error("load_binary_init_callback() invalid load-binary device %s\n",
1294 image
= bfd_openr(file_name
, NULL
);
1295 if (image
== NULL
) {
1296 bfd_perror("open failed:");
1297 error("nothing loaded\n");
1300 /* check it is valid */
1301 if (!bfd_check_format(image
, bfd_object
)) {
1302 printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
1303 printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name
);
1308 /* and the data sections */
1309 bfd_map_over_sections(image
,
1310 update_for_binary_section
,
1317 static device_callbacks
const binary_callbacks
= {
1318 binary_init_callback
,
1319 unimp_device_attach_address
,
1320 unimp_device_detach_address
,
1321 unimp_device_io_read_buffer
,
1322 unimp_device_io_write_buffer
,
1323 unimp_device_dma_read_buffer
,
1324 unimp_device_dma_write_buffer
,
1325 unimp_device_attach_interrupt
,
1326 unimp_device_detach_interrupt
,
1327 unimp_device_interrupt
,
1328 unimp_device_interrupt_ack
,
1334 /* Stack device: stack@<type>
1336 Has a single IOCTL to create a stack frame of the specified type.
1337 If <type> is elf or xcoff then a corresponding stack is created.
1338 Any other value of type is ignored.
1340 The IOCTL takes the additional arguments:
1342 unsigned_word stack_end -- where the stack should come down from
1348 STATIC_INLINE_DEVICES
int
1349 sizeof_argument_strings(char **arg
)
1351 int sizeof_strings
= 0;
1357 /* add up all the string sizes (padding as we go) */
1358 for (; *arg
!= NULL
; arg
++) {
1359 int len
= strlen(*arg
) + 1;
1360 sizeof_strings
+= ALIGN_8(len
);
1363 return sizeof_strings
;
1366 STATIC_INLINE_DEVICES
int
1367 number_of_arguments(char **arg
)
1372 for (nr
= 0; *arg
!= NULL
; arg
++, nr
++);
1376 STATIC_INLINE_DEVICES
int
1377 sizeof_arguments(char **arg
)
1379 return ALIGN_8((number_of_arguments(arg
) + 1) * sizeof(unsigned_word
));
1382 STATIC_INLINE_DEVICES
void
1383 write_stack_arguments(psim
*system
,
1385 unsigned_word start_block
,
1386 unsigned_word end_block
,
1387 unsigned_word start_arg
,
1388 unsigned_word end_arg
)
1391 ("write_stack_arguments(system=0x%lx, arg=0x%lx, start_block=0x%lx, end_block=0x%lx, start_arg=0x%lx, end_arg=0x%lx)\n",
1392 (long)system
, (long)arg
, (long)start_block
, (long)end_block
, (long)start_arg
, (long)end_arg
));
1394 error("write_arguments: character array NULL\n");
1395 /* only copy in arguments, memory is already zero */
1396 for (; *arg
!= NULL
; arg
++) {
1397 int len
= strlen(*arg
)+1;
1398 unsigned_word target_start_block
;
1400 ("write_stack_arguments() write %s=%s at %s=0x%lx %s=0x%lx %s=0x%lx\n",
1401 "**arg", *arg
, "start_block", (long)start_block
,
1402 "len", (long)len
, "start_arg", (long)start_arg
));
1403 if (psim_write_memory(system
, 0, *arg
,
1405 0/*violate_readonly*/) != len
)
1406 error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
1408 target_start_block
= H2T_word(start_block
);
1409 if (psim_write_memory(system
, 0, &target_start_block
,
1410 start_arg
, sizeof(target_start_block
),
1411 0) != sizeof(target_start_block
))
1412 error("write_stack_arguments() - write of *arg failed\n");
1413 start_block
+= ALIGN_8(len
);
1414 start_arg
+= sizeof(start_block
);
1416 start_arg
+= sizeof(start_block
); /*the null at the end*/
1417 if (start_block
!= end_block
1418 || ALIGN_8(start_arg
) != end_arg
)
1419 error("write_stack_arguments - possible corruption\n");
1421 ("write_stack_arguments() = void\n"));
1424 STATIC_INLINE_DEVICES
void
1425 create_elf_stack_frame(psim
*system
,
1426 unsigned_word bottom_of_stack
,
1430 /* fixme - this is over aligned */
1432 /* information block */
1433 const unsigned sizeof_envp_block
= sizeof_argument_strings(envp
);
1434 const unsigned_word start_envp_block
= bottom_of_stack
- sizeof_envp_block
;
1435 const unsigned sizeof_argv_block
= sizeof_argument_strings(argv
);
1436 const unsigned_word start_argv_block
= start_envp_block
- sizeof_argv_block
;
1438 /* auxiliary vector - contains only one entry */
1439 const unsigned sizeof_aux_entry
= 2*sizeof(unsigned_word
); /* magic */
1440 const unsigned_word start_aux
= start_argv_block
- ALIGN_8(sizeof_aux_entry
);
1442 /* environment points (including null sentinal) */
1443 const unsigned sizeof_envp
= sizeof_arguments(envp
);
1444 const unsigned_word start_envp
= start_aux
- sizeof_envp
;
1446 /* argument pointers (including null sentinal) */
1447 const int argc
= number_of_arguments(argv
);
1448 const unsigned sizeof_argv
= sizeof_arguments(argv
);
1449 const unsigned_word start_argv
= start_envp
- sizeof_argv
;
1451 /* link register save address - alligned to a 16byte boundary */
1452 const unsigned_word top_of_stack
= ((start_argv
1453 - 2 * sizeof(unsigned_word
))
1456 /* install arguments on stack */
1457 write_stack_arguments(system
, envp
,
1458 start_envp_block
, bottom_of_stack
,
1459 start_envp
, start_aux
);
1460 write_stack_arguments(system
, argv
,
1461 start_argv_block
, start_envp_block
,
1462 start_argv
, start_envp
);
1464 /* set up the registers */
1465 psim_write_register(system
, -1,
1466 &top_of_stack
, "sp", cooked_transfer
);
1467 psim_write_register(system
, -1,
1468 &argc
, "r3", cooked_transfer
);
1469 psim_write_register(system
, -1,
1470 &start_argv
, "r4", cooked_transfer
);
1471 psim_write_register(system
, -1,
1472 &start_envp
, "r5", cooked_transfer
);
1473 psim_write_register(system
, -1,
1474 &start_aux
, "r6", cooked_transfer
);
1477 STATIC_INLINE_DEVICES
void
1478 create_aix_stack_frame(psim
*system
,
1479 unsigned_word bottom_of_stack
,
1483 unsigned_word core_envp
;
1484 unsigned_word core_argv
;
1485 unsigned_word core_argc
;
1486 unsigned_word core_aux
;
1487 unsigned_word top_of_stack
;
1489 /* cheat - create an elf stack frame */
1490 create_elf_stack_frame(system
, bottom_of_stack
, argv
, envp
);
1492 /* extract argument addresses from registers */
1493 psim_read_register(system
, 0, &top_of_stack
, "r1", cooked_transfer
);
1494 psim_read_register(system
, 0, &core_argc
, "r3", cooked_transfer
);
1495 psim_read_register(system
, 0, &core_argv
, "r4", cooked_transfer
);
1496 psim_read_register(system
, 0, &core_envp
, "r5", cooked_transfer
);
1497 psim_read_register(system
, 0, &core_aux
, "r6", cooked_transfer
);
1499 /* extract arguments from registers */
1500 error("create_aix_stack_frame() - what happens next?\n");
1506 stack_ioctl_callback(const device
*me
,
1513 unsigned_word stack_pointer
;
1517 stack_pointer
= va_arg(ap
, unsigned_word
);
1518 argv
= va_arg(ap
, char **);
1519 envp
= va_arg(ap
, char **);
1522 ("stack_ioctl_callback(me=0x%lx:%s, system=0x%lx, processor=0x%lx, cia=0x%lx, argv=0x%lx, envp=0x%lx)\n",
1523 (long)me
, me
->full_name
, (long)system
, (long)processor
, (long)cia
, (long)argv
, (long)envp
));
1524 if (strcmp(me
->name
, "stack@elf") == 0)
1525 create_elf_stack_frame(system
, stack_pointer
, argv
, envp
);
1526 else if (strcmp(me
->name
, "stack@xcoff") == 0)
1527 create_aix_stack_frame(system
, stack_pointer
, argv
, envp
);
1529 ("stack_ioctl_callback() = void\n"));
1533 static device_callbacks
const stack_callbacks
= {
1535 unimp_device_attach_address
,
1536 unimp_device_detach_address
,
1537 unimp_device_io_read_buffer
,
1538 unimp_device_io_write_buffer
,
1539 unimp_device_dma_read_buffer
,
1540 unimp_device_dma_write_buffer
,
1541 unimp_device_attach_interrupt
,
1542 unimp_device_detach_interrupt
,
1543 unimp_device_interrupt
,
1544 unimp_device_interrupt_ack
,
1545 stack_ioctl_callback
,
1550 /* Table of all the devices and a function to lookup/create a device
1553 typedef const device
*(device_creator
)
1555 const char *full_name
,
1556 const device
*parent
);
1558 typedef struct _device_descriptor device_descriptor
;
1559 struct _device_descriptor
{
1561 device_creator
*creator
;
1562 const device_callbacks
*callbacks
;
1565 static device_descriptor devices
[] = {
1566 { "console", console_create
, NULL
},
1567 { "memory", NULL
, &memory_callbacks
},
1568 { "vm", vea_vm_create
, NULL
},
1569 { "halt", NULL
, &halt_callbacks
},
1570 { "icu", NULL
, &icu_callbacks
},
1571 { "register", NULL
, ®ister_callbacks
},
1572 { "iobus", NULL
, &iobus_callbacks
},
1573 { "file", NULL
, &file_callbacks
},
1574 { "htab", NULL
, &htab_callbacks
},
1575 { "pte", NULL
, &htab_callbacks
}, /* yep - uses htab's table */
1576 { "stack", NULL
, &stack_callbacks
},
1577 { "sim", NULL
, &sim_callbacks
},
1578 { "load-binary", NULL
, &binary_callbacks
},
1579 { "map-binary", NULL
, &binary_callbacks
},
1584 INLINE_DEVICES
const device
*
1585 device_create(const char *name
,
1586 const char *full_name
,
1587 const device
*parent
)
1589 device_descriptor
*device
;
1592 chp
= strchr(name
, '@');
1593 name_len
= (chp
== NULL
? strlen(name
) : chp
- name
);
1594 for (device
= devices
; device
->name
!= NULL
; device
++) {
1595 if (strncmp(name
, device
->name
, name_len
) == 0
1596 && (device
->name
[name_len
] == '\0'
1597 || device
->name
[name_len
] == '@'))
1598 if (device
->creator
!= NULL
)
1599 return device
->creator(name
, full_name
, parent
);
1601 return device_create_from(name
,
1607 error("device_create() unknown device %s\n", name
);
1612 INLINE_DEVICES
const device
*
1613 device_create_from(const char *name
,
1614 const char *full_name
,
1616 const device_callbacks
*callback
,
1617 const device
*parent
)
1619 device
*me
= ZALLOC(device
);
1620 me
->name
= strdup(name
);
1621 me
->full_name
= strdup(full_name
);
1623 me
->callback
= callback
;
1624 me
->parent
= parent
;
1629 INLINE_DEVICES
const device_callbacks
*
1630 passthrough_device_callbacks(void)
1632 static const device_callbacks callbacks
= {
1634 pass_device_attach_address
,
1635 pass_device_detach_address
,
1636 unimp_device_io_read_buffer
,
1637 unimp_device_io_write_buffer
,
1638 pass_device_dma_read_buffer
,
1639 pass_device_dma_write_buffer
,
1640 pass_device_attach_interrupt
,
1641 pass_device_detach_interrupt
,
1642 pass_device_interrupt
,
1643 unimp_device_interrupt_ack
,
1651 #endif /* _DEVICES_C_ */