* xcofflink.c (XCOFF_DEF_DYNAMIC): Rename from XCOFF_REF_DYNAMIC.
[deliverable/binutils-gdb.git] / sim / ppc / devices.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
4
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.
9
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.
14
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.
18
19 */
20
21
22 #ifndef _DEVICES_C_
23 #define _DEVICES_C_
24
25 #ifndef STATIC_INLINE_DEVICES
26 #define STATIC_INLINE_DEVICES STATIC_INLINE
27 #endif
28
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <stdarg.h>
33
34 #include "basics.h"
35 #include "devices.h"
36 #include "events.h"
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 #ifdef HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45
46 #ifdef HAVE_STRING_H
47 #include <string.h>
48 #else
49 #ifdef HAVE_STRINGS_H
50 #include <strings.h>
51 #endif
52 #endif
53
54 #include "cpu.h"
55
56 #include "bfd.h"
57
58 /* Helper functions */
59
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. */
63
64 STATIC_INLINE_DEVICES void
65 generic_init_callback(const device *me,
66 psim *system)
67 {
68 unsigned_word addr;
69 unsigned nr_bytes;
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,
73 me->name,
74 attach_callback,
75 0 /*space*/,
76 addr,
77 nr_bytes,
78 access_read_write,
79 me);
80 }
81
82
83 \f
84 /* inimplemented versions of each function */
85
86 INLINE_DEVICES void
87 unimp_device_init(const device *me,
88 psim *system)
89 {
90 error("device_init_callback for %s not implemented\n", me->name);
91 }
92
93 INLINE_DEVICES void
94 unimp_device_attach_address(const device *me,
95 const char *name,
96 attach_type type,
97 int space,
98 unsigned_word addr,
99 unsigned nr_bytes,
100 access_type access,
101 const device *who) /*callback/default*/
102 {
103 error("device_attach_address_callback for %s not implemented\n", me->name);
104 }
105
106 INLINE_DEVICES void
107 unimp_device_detach_address(const device *me,
108 const char *name,
109 attach_type type,
110 int space,
111 unsigned_word addr,
112 unsigned nr_bytes,
113 access_type access,
114 const device *who) /*callback/default*/
115 {
116 error("device_detach_address_callback for %s not implemented\n", me->name);
117 }
118
119 INLINE_DEVICES unsigned
120 unimp_device_io_read_buffer(const device *me,
121 void *dest,
122 int space,
123 unsigned_word addr,
124 unsigned nr_bytes,
125 cpu *processor,
126 unsigned_word cia)
127 {
128 error("device_io_read_buffer_callback for %s not implemented\n", me->name);
129 return 0;
130 }
131
132 INLINE_DEVICES unsigned
133 unimp_device_io_write_buffer(const device *me,
134 const void *source,
135 int space,
136 unsigned_word addr,
137 unsigned nr_bytes,
138 cpu *processor,
139 unsigned_word cia)
140 {
141 error("device_io_write_buffer_callback for %s not implemented\n", me->name);
142 return 0;
143 }
144
145 INLINE_DEVICES unsigned
146 unimp_device_dma_read_buffer(const device *me,
147 void *target,
148 int space,
149 unsigned_word addr,
150 unsigned nr_bytes)
151 {
152 error("device_dma_read_buffer_callback for %s not implemented\n", me->name);
153 return 0;
154 }
155
156 INLINE_DEVICES unsigned
157 unimp_device_dma_write_buffer(const device *me,
158 const void *source,
159 int space,
160 unsigned_word addr,
161 unsigned nr_bytes,
162 int violate_read_only_section)
163 {
164 error("device_dma_write_buffer_callback for %s not implemented\n", me->name);
165 return 0;
166 }
167
168 INLINE_DEVICES void
169 unimp_device_attach_interrupt(const device *me,
170 const device *who,
171 int interrupt_line,
172 const char *name)
173 {
174 error("device_attach_interrupt_callback for %s not implemented\n", me->name);
175 }
176
177 INLINE_DEVICES void
178 unimp_device_detach_interrupt(const device *me,
179 const device *who,
180 int interrupt_line,
181 const char *name)
182 {
183 error("device_detach_interrupt_callback for %s not implemented\n", me->name);
184 }
185
186 INLINE_DEVICES void
187 unimp_device_interrupt(const device *me,
188 const device *who,
189 int interrupt_line,
190 int interrupt_status,
191 cpu *processor,
192 unsigned_word cia)
193 {
194 error("device_interrupt_callback for %s not implemented\n", me->name);
195 }
196
197 INLINE_DEVICES void
198 unimp_device_interrupt_ack(const device *me,
199 int interrupt_line,
200 int interrupt_status)
201 {
202 error("device_interrupt_ack_callback for %s not implemented\n", me->name);
203 }
204
205 STATIC_DEVICES void
206 unimp_device_ioctl(const device *me,
207 psim *system,
208 cpu *processor,
209 unsigned_word cia,
210 ...)
211 {
212 error("device_ioctl_callback for %s not implemented\n", me->name);
213 }
214
215
216 \f
217 /* ignore/passthrough versions of each function */
218
219 INLINE_DEVICES void
220 ignore_device_init(const device *me,
221 psim *system)
222 {
223 /*null*/
224 }
225
226 INLINE_DEVICES void
227 pass_device_attach_address(const device *me,
228 const char *name,
229 attach_type attach,
230 int space,
231 unsigned_word addr,
232 unsigned nr_bytes,
233 access_type access,
234 const device *who) /*callback/default*/
235 {
236 DTRACE_ATTACH_ADDRESS(pass);
237 me->parent->callback->attach_address(me->parent, name, attach,
238 space, addr, nr_bytes,
239 access,
240 who);
241 }
242
243 INLINE_DEVICES void
244 pass_device_detach_address(const device *me,
245 const char *name,
246 attach_type attach,
247 int space,
248 unsigned_word addr,
249 unsigned nr_bytes,
250 access_type access,
251 const device *who) /*callback/default*/
252 {
253 DTRACE_DETACH_ADDRESS(pass);
254 me->parent->callback->detach_address(me->parent, name, attach,
255 space, addr, nr_bytes, access,
256 who);
257 }
258
259 INLINE_DEVICES unsigned
260 pass_device_dma_read_buffer(const device *me,
261 void *dest,
262 int space,
263 unsigned_word addr,
264 unsigned nr_bytes)
265 {
266 DTRACE_DMA_READ_BUFFER(pass);
267 return me->parent->callback->dma_read_buffer(me->parent, dest,
268 space, addr, nr_bytes);
269 }
270
271 INLINE_DEVICES unsigned
272 pass_device_dma_write_buffer(const device *me,
273 const void *source,
274 int space,
275 unsigned_word addr,
276 unsigned nr_bytes,
277 int violate_read_only_section)
278 {
279 DTRACE_DMA_WRITE_BUFFER(pass);
280 return me->parent->callback->dma_write_buffer(me->parent, source,
281 space, addr,
282 nr_bytes,
283 violate_read_only_section);
284 }
285
286 INLINE_DEVICES void
287 pass_device_attach_interrupt(const device *me,
288 const device *who,
289 int interrupt_line,
290 const char *name)
291 {
292 me->parent->callback->attach_interrupt(me->parent, who,
293 interrupt_line, name);
294 }
295
296 INLINE_DEVICES void
297 pass_device_detach_interrupt(const device *me,
298 const device *who,
299 int interrupt_line,
300 const char *name)
301 {
302 me->parent->callback->detach_interrupt(me->parent, who,
303 interrupt_line, name);
304 }
305
306
307 INLINE_DEVICES void
308 pass_device_interrupt(const device *me,
309 const device *who,
310 int interrupt_line,
311 int interrupt_status,
312 cpu *processor,
313 unsigned_word cia)
314 {
315 me->parent->callback->interrupt(me->parent, who,
316 interrupt_line, interrupt_status,
317 processor, cia);
318 }
319
320
321 \f
322 /* Simple console device: console@)x<address>,16
323
324 Input characters are taken from the keyboard, output characters
325 sent to the terminal. Echoing of characters is not disabled.
326
327 The device has four registers:
328
329 0x0: read
330 0x4: read-status
331 0x8: write
332 0xC: write-status
333
334 Where a nonzero status register indicates that the device is ready
335 (input fifo contains a character or output fifo has space). */
336
337 typedef struct _console_buffer {
338 char buffer;
339 int status;
340 event_entry_tag event_tag;
341 } console_buffer;
342
343 typedef struct _console_device {
344 console_buffer input;
345 console_buffer output;
346 } console_device;
347
348 typedef enum {
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,
354 console_size = 16,
355 } console_offsets;
356
357
358 STATIC_INLINE_DEVICES unsigned
359 console_io_read_buffer_callback(const device *me,
360 void *dest,
361 int space,
362 unsigned_word addr,
363 unsigned nr_bytes,
364 cpu *processor,
365 unsigned_word cia)
366 {
367 console_device *console = (console_device*)me->data;
368 unsigned_1 val;
369 DTRACE_IO_READ_BUFFER(console);
370
371 /* determine what was read */
372
373 switch (addr) {
374
375 case console_read_buffer:
376 val = console->input.buffer;
377 break;
378
379 case console_read_status:
380 { /* check for input */
381 int flags;
382 int status;
383 /* get the old status */
384 flags = fcntl(0, F_GETFL, 0);
385 if (flags == -1) {
386 perror("console");
387 val = 0;
388 break;
389 }
390 /* temp, disable blocking IO */
391 status = fcntl(0, F_SETFL, flags | O_NDELAY);
392 if (status == -1) {
393 perror("console");
394 val = 0;
395 break;
396 }
397 /* try for input */
398 status = read(0, &console->input.buffer, 1);
399 if (status == 1) {
400 console->input.status = 1;
401 }
402 else {
403 console->input.status = 0;
404 }
405 /* return to regular vewing */
406 fcntl(0, F_SETFL, flags);
407 }
408 val = console->input.status;
409 break;
410
411 case console_write_buffer:
412 val = console->output.buffer;
413 break;
414
415 case console_write_status:
416 val = console->output.status;
417 break;
418
419 default:
420 error("console_read_callback() internal error\n");
421 val = 0;
422 break;
423
424 }
425
426 bzero(dest, nr_bytes);
427 *(unsigned_1*)dest = val;
428 return nr_bytes;
429 }
430
431 STATIC_INLINE_DEVICES unsigned
432 console_io_write_buffer_callback(const device *me,
433 const void *source,
434 int space,
435 unsigned_word addr,
436 unsigned nr_bytes,
437 cpu *processor,
438 unsigned_word cia)
439 {
440 console_device *console = (console_device*)me->data;
441 unsigned_1 val = *(unsigned8*)source;
442 DTRACE_IO_WRITE_BUFFER(console);
443
444 switch (addr) {
445 case console_read_buffer:
446 console->input.buffer = val;
447 break;
448 case console_read_status:
449 console->input.status = val;
450 break;
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;
456 break;
457 case console_write_status:
458 console->output.status = val;
459 break;
460 default:
461 error("console_write_callback() internal error\n");
462 }
463
464 return nr_bytes;
465 }
466
467
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,
480 unimp_device_ioctl,
481 };
482
483
484 STATIC_INLINE_DEVICES const device *
485 console_create(const char *name,
486 const char *full_name,
487 const device *parent)
488 {
489 /* create the descriptor */
490 console_device *console = ZALLOC(console_device);
491
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';
497
498 /* insert into the device tree along with its address info */
499 return device_create_from(name,
500 full_name,
501 console, /* data */
502 &console_callbacks,
503 parent);
504 }
505
506
507 \f
508 /* ICU device: icu@0x<address>,4
509
510 Single 4 byte register. Read returns processor number. Write
511 interrupts specified processor.
512
513 Illustrates passing of events to parent device. Passing of
514 interrupts to parent bus.
515
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. */
519
520 STATIC_INLINE_DEVICES unsigned
521 icu_io_read_buffer_callback(const device *me,
522 void *dest,
523 int space,
524 unsigned_word addr,
525 unsigned nr_bytes,
526 cpu *processor,
527 unsigned_word cia)
528 {
529 unsigned_1 val;
530 DTRACE_IO_READ_BUFFER(icu);
531 val = cpu_nr(processor);
532 bzero(dest, nr_bytes);
533 *(unsigned_1*)dest = val;
534 return nr_bytes;
535 }
536
537
538 STATIC_INLINE_DEVICES unsigned
539 icu_io_write_buffer_callback(const device *me,
540 const void *source,
541 int space,
542 unsigned_word addr,
543 unsigned nr_bytes,
544 cpu *processor,
545 unsigned_word cia)
546 {
547 psim *system = cpu_system(processor);
548 unsigned_1 val = H2T_1(*(unsigned_1*)source);
549 DTRACE_IO_WRITE_BUFFER(icu);
550 /* tell the parent device that the interrupt lines have changed.
551 For this fake ICU. The interrupt lines just indicate the cpu to
552 interrupt next */
553 me->parent->callback->interrupt(me->parent, me,
554 val, val,
555 processor, cia);
556 return nr_bytes;
557 }
558
559
560 static device_callbacks const icu_callbacks = {
561 generic_init_callback,
562 unimp_device_attach_address,
563 unimp_device_detach_address,
564 icu_io_read_buffer_callback,
565 icu_io_write_buffer_callback,
566 unimp_device_dma_read_buffer,
567 unimp_device_dma_write_buffer,
568 unimp_device_attach_interrupt,
569 unimp_device_detach_interrupt,
570 unimp_device_interrupt,
571 unimp_device_interrupt_ack,
572 unimp_device_ioctl,
573 };
574
575
576 \f
577 /* HALT device: halt@0x<address>,4
578
579 With real hardware, the processor operation is normally terminated
580 through a reset. This device illustrates how a reset device could
581 be attached to an address */
582
583
584 STATIC_INLINE_DEVICES unsigned
585 halt_io_read_buffer_callback(const device *me,
586 void *dest,
587 int space,
588 unsigned_word addr,
589 unsigned nr_bytes,
590 cpu *processor,
591 unsigned_word cia)
592 {
593 DTRACE_IO_READ_BUFFER(halt);
594 cpu_halt(processor, cia, was_exited, 0);
595 return 0;
596 }
597
598
599 STATIC_INLINE_DEVICES unsigned
600 halt_io_write_buffer_callback(const device *me,
601 const void *source,
602 int space,
603 unsigned_word addr,
604 unsigned nr_bytes,
605 cpu *processor,
606 unsigned_word cia)
607 {
608 DTRACE_IO_WRITE_BUFFER(halt);
609 cpu_halt(processor, cia, was_exited, 0);
610 return 0;
611 }
612
613
614 static device_callbacks const halt_callbacks = {
615 generic_init_callback,
616 unimp_device_attach_address,
617 unimp_device_detach_address,
618 halt_io_read_buffer_callback,
619 halt_io_write_buffer_callback,
620 unimp_device_dma_read_buffer,
621 unimp_device_dma_write_buffer,
622 unimp_device_attach_interrupt,
623 unimp_device_detach_interrupt,
624 unimp_device_interrupt,
625 unimp_device_interrupt_ack,
626 unimp_device_ioctl,
627 };
628
629
630 \f
631 /* Register init device: register@<name>,0x<value>[,<processor>]
632
633 This strange device is used to initialize the processors registers
634 as part of the initialization. */
635
636 STATIC_INLINE_DEVICES void
637 register_init_callback(const device *me,
638 psim *system)
639 {
640 char name[100];
641 unsigned_word value;
642 unsigned which_cpu;
643 int status;
644 DTRACE_INIT(register);
645 status = scand_c_uw_u(me->name, name, sizeof(name), &value, &which_cpu);
646 switch (status) {
647 case 2: /* register@<name>,<value> */
648 psim_write_register(system, -1, &value, name, cooked_transfer);
649 break;
650 case 3: /* register@<name>,<value>,<processor> */
651 psim_write_register(system, which_cpu, &value, name, cooked_transfer);
652 break;
653 default:
654 error("register_init_callback() invalid register init %s\n", me->name);
655 break;
656 }
657 }
658
659
660 static device_callbacks const register_callbacks = {
661 register_init_callback,
662 unimp_device_attach_address,
663 unimp_device_detach_address,
664 unimp_device_io_read_buffer,
665 unimp_device_io_write_buffer,
666 unimp_device_dma_read_buffer,
667 unimp_device_dma_write_buffer,
668 unimp_device_attach_interrupt,
669 unimp_device_detach_interrupt,
670 unimp_device_interrupt,
671 unimp_device_interrupt_ack,
672 unimp_device_ioctl,
673 };
674
675
676 \f
677 /* VEA VM device: vm@0x<stack-base>,<nr_bytes>
678
679 A VEA mode device. This sets its self up as the default memory
680 device capturing all accesses (reads/writes) to currently unmapped
681 addresses. If the unmaped access falls within unallocated stack or
682 heap address ranges then memory is allocated and the access is
683 allowed to continue.
684
685 During init phase, this device expects to receive `attach' requests
686 from its children for the text/data/bss memory areas. Typically,
687 this would be done by the binary device.
688
689 STACK: The location of the stack in memory is specified as part of
690 the devices name. Unmaped accesses that fall within the stack
691 space result in the allocated stack being grown downwards so that
692 it includes the page of the culprit access.
693
694 HEAP: During initialization, the vm device monitors all `attach'
695 operations from its children using this to determine the initial
696 location of the heap. The heap is then extended by system calls
697 that frob the heap upper bound variable (see system.c). */
698
699
700 typedef struct _vm_device {
701 /* area of memory valid for stack addresses */
702 unsigned_word stack_base; /* min possible stack value */
703 unsigned_word stack_bound;
704 unsigned_word stack_lower_limit;
705 /* area of memory valid for heap addresses */
706 unsigned_word heap_base;
707 unsigned_word heap_bound;
708 unsigned_word heap_upper_limit;
709 } vm_device;
710
711
712 STATIC_INLINE_DEVICES void
713 vm_init_callback(const device *me,
714 psim *system)
715 {
716 vm_device *vm = (vm_device*)me->data;
717 DTRACE_INIT(vm);
718
719 /* revert the stack/heap variables to their defaults */
720 vm->stack_lower_limit = vm->stack_bound;
721 vm->heap_base = 0;
722 vm->heap_bound = 0;
723 vm->heap_upper_limit = 0;
724
725 /* establish this device as the default memory handler */
726 me->parent->callback->attach_address(me->parent,
727 me->name,
728 attach_default,
729 0 /*address space - ignore*/,
730 0 /*addr - ignore*/,
731 0 /*nr_bytes - ignore*/,
732 access_read_write /*access*/,
733 me);
734 }
735
736
737 STATIC_INLINE_DEVICES void
738 vm_attach_address(const device *me,
739 const char *name,
740 attach_type attach,
741 int space,
742 unsigned_word addr,
743 unsigned nr_bytes,
744 access_type access,
745 const device *who) /*callback/default*/
746 {
747 vm_device *vm = (vm_device*)me->data;
748 DTRACE_ATTACH_ADDRESS(vm);
749 /* update end of bss if necessary */
750 if (vm->heap_base < addr + nr_bytes) {
751 vm->heap_base = addr + nr_bytes;
752 vm->heap_bound = addr + nr_bytes;
753 vm->heap_upper_limit = addr + nr_bytes;
754 }
755 me->parent->callback->attach_address(me->parent,
756 "vm@0x0,0", /* stop remap */
757 attach_raw_memory,
758 0 /*address space*/,
759 addr,
760 nr_bytes,
761 access,
762 me);
763 }
764
765
766 STATIC_INLINE_DEVICES unsigned
767 add_vm_space(const device *me,
768 unsigned_word addr,
769 unsigned nr_bytes,
770 cpu *processor,
771 unsigned_word cia)
772 {
773 vm_device *vm = (vm_device*)me->data;
774 unsigned_word block_addr;
775 unsigned block_nr_bytes;
776
777 /* an address in the stack area, allocate just down to the addressed
778 page */
779 if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
780 block_addr = FLOOR_PAGE(addr);
781 block_nr_bytes = vm->stack_lower_limit - block_addr;
782 vm->stack_lower_limit = block_addr;
783 }
784 /* an address in the heap area, allocate all of the required heap */
785 else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
786 block_addr = vm->heap_upper_limit;
787 block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
788 vm->heap_upper_limit = vm->heap_bound;
789 }
790 /* oops - an invalid address - abort the cpu */
791 else if (processor != NULL) {
792 cpu_halt(processor, cia, was_signalled, SIGSEGV);
793 return 0;
794 }
795 /* 2*oops - an invalid address and no processor */
796 else {
797 return 0;
798 }
799
800 /* got the parameters, allocate the space */
801 me->parent->callback->attach_address(me->parent,
802 "vm@0x0,0", /* stop remap */
803 attach_raw_memory,
804 0 /*address space*/,
805 block_addr,
806 block_nr_bytes,
807 access_read_write,
808 me);
809 return block_nr_bytes;
810 }
811
812
813 STATIC_INLINE_DEVICES unsigned
814 vm_io_read_buffer_callback(const device *me,
815 void *dest,
816 int space,
817 unsigned_word addr,
818 unsigned nr_bytes,
819 cpu *processor,
820 unsigned_word cia)
821 {
822 DTRACE_IO_READ_BUFFER(vm);
823 if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
824 bzero(dest, nr_bytes); /* always initialized to zero */
825 return nr_bytes;
826 }
827 else
828 return 0;
829 }
830
831
832 STATIC_INLINE_DEVICES unsigned
833 vm_io_write_buffer_callback(const device *me,
834 const void *source,
835 int space,
836 unsigned_word addr,
837 unsigned nr_bytes,
838 cpu *processor,
839 unsigned_word cia)
840 {
841 DTRACE_IO_WRITE_BUFFER(vm);
842 if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
843 return me->parent->callback->dma_write_buffer(me->parent, source,
844 space, addr,
845 nr_bytes,
846 0/*violate_read_only*/);
847 }
848 else
849 return 0;
850 }
851
852
853 static void
854 vm_ioctl_callback(const device *me,
855 psim *system,
856 cpu *processor,
857 unsigned_word cia,
858 ...)
859 {
860 /* While the caller is notified that the heap has grown by the
861 requested amount, the heap is infact extended out to a page
862 boundary. */
863 vm_device *vm = (vm_device*)me->data;
864 unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
865 unsigned_word old_break = vm->heap_bound;
866 signed_word delta = new_break - old_break;
867 if (delta > 0)
868 vm->heap_bound = ALIGN_PAGE(new_break);
869 cpu_registers(processor)->gpr[0] = 0;
870 cpu_registers(processor)->gpr[3] = new_break;
871 }
872
873
874 static device_callbacks const vm_callbacks = {
875 vm_init_callback,
876 vm_attach_address,
877 pass_device_detach_address,
878 vm_io_read_buffer_callback,
879 vm_io_write_buffer_callback,
880 unimp_device_dma_read_buffer,
881 pass_device_dma_write_buffer,
882 unimp_device_attach_interrupt,
883 unimp_device_detach_interrupt,
884 unimp_device_interrupt,
885 unimp_device_interrupt_ack,
886 vm_ioctl_callback,
887 };
888
889
890 STATIC_INLINE_DEVICES const device *
891 vea_vm_create(const char *name,
892 const char *full_name,
893 const device *parent)
894 {
895 vm_device *vm = ZALLOC(vm_device);
896 unsigned_word addr;
897 unsigned nr_bytes;
898
899 /* extract out the stack parameters */
900 if (scand_uw_u(name, &addr, &nr_bytes) != 2)
901 error("vm_device_create() invalid vm device %s\n", name);
902 vm->stack_base = addr;
903 vm->stack_bound = addr + nr_bytes;
904
905 /* insert in the tree including the buffer */
906 return device_create_from(name,
907 full_name,
908 vm, /* data */
909 &vm_callbacks,
910 parent);
911 }
912
913
914 \f
915 /* Memory init device: memory@0x<addr>,<size>,<access>
916
917 This strange device is used create sections of memory */
918
919 STATIC_INLINE_DEVICES void
920 memory_init_callback(const device *me,
921 psim *system)
922 {
923 unsigned_word addr;
924 unsigned nr_bytes;
925 unsigned access;
926 int nr_args;
927 DTRACE_INIT(memory);
928
929 nr_args = scand_uw_u_u(me->name, &addr, &nr_bytes, &access);
930 switch (nr_args) {
931 case 2:
932 access = access_read_write_exec;
933 break;
934 case 3:
935 break;
936 default:
937 error("memory_init_callback() invalid memory device %s\n", me->name);
938 break;
939 }
940
941 me->parent->callback->attach_address(me->parent,
942 me->name,
943 attach_raw_memory,
944 0 /*address space*/,
945 addr,
946 nr_bytes,
947 (access_type)access,
948 me);
949 }
950
951
952 static device_callbacks const memory_callbacks = {
953 memory_init_callback,
954 unimp_device_attach_address,
955 unimp_device_detach_address,
956 unimp_device_io_read_buffer,
957 unimp_device_io_write_buffer,
958 unimp_device_dma_read_buffer,
959 unimp_device_dma_write_buffer,
960 unimp_device_attach_interrupt,
961 unimp_device_detach_interrupt,
962 unimp_device_interrupt,
963 unimp_device_interrupt_ack,
964 unimp_device_ioctl,
965 };
966
967
968 \f
969 /* IOBUS device: iobus@<address>
970
971 Simple bus on which some IO devices live */
972
973 STATIC_INLINE_DEVICES void
974 iobus_attach_address_callback(const device *me,
975 const char *name,
976 attach_type type,
977 int space,
978 unsigned_word addr,
979 unsigned nr_bytes,
980 access_type access,
981 const device *who) /*callback/default*/
982 {
983 unsigned_word iobus_addr;
984 /* sanity check */
985 if (type == attach_default)
986 error("iobus_attach_address_callback() no default for %s/%s\n",
987 me->name, name);
988 if (space != 0)
989 error("iobus_attach_address_callback() no space for %s/%s\n",
990 me->name, name);
991 /* get the bus address */
992 if (scand_uw(me->name, &iobus_addr) != 1)
993 error("iobus_attach_address_callback() invalid address for %s\n",
994 me->name);
995 me->parent->callback->attach_address(me->parent,
996 me->name,
997 type,
998 0 /*space*/,
999 iobus_addr + addr,
1000 nr_bytes,
1001 access,
1002 who);
1003 }
1004
1005
1006 STATIC_INLINE_DEVICES void
1007 iobus_do_interrupt(event_queue *queue,
1008 void *data)
1009 {
1010 cpu *target = (cpu*)data;
1011 /* try to interrupt the processor. If the attempt fails, try again
1012 on the next tick */
1013 if (!external_interrupt(target))
1014 event_queue_schedule(queue, 1, iobus_do_interrupt, target);
1015 }
1016
1017
1018 STATIC_INLINE_DEVICES void
1019 iobus_interrupt_callback(const device *me,
1020 const device *who,
1021 int interrupt_line,
1022 int interrupt_status,
1023 cpu *processor,
1024 unsigned_word cia)
1025 {
1026 /* the interrupt controler can't interrupt a cpu at any time.
1027 Rather it must synchronize with the system clock before
1028 performing an interrupt on the given processor */
1029 psim *system = cpu_system(processor);
1030 cpu *target = psim_cpu(system, interrupt_status);
1031 if (target != NULL) {
1032 event_queue *events = cpu_event_queue(target);
1033 event_queue_schedule(events, 1, iobus_do_interrupt, target);
1034 }
1035 }
1036
1037
1038 static device_callbacks const iobus_callbacks = {
1039 ignore_device_init,
1040 iobus_attach_address_callback,
1041 unimp_device_detach_address,
1042 unimp_device_io_read_buffer,
1043 unimp_device_io_write_buffer,
1044 unimp_device_dma_read_buffer,
1045 unimp_device_dma_write_buffer,
1046 unimp_device_attach_interrupt,
1047 unimp_device_detach_interrupt,
1048 iobus_interrupt_callback,
1049 unimp_device_interrupt_ack,
1050 unimp_device_ioctl,
1051 };
1052
1053
1054 \f
1055 /* FILE device: file@0x<address>,<file-name>
1056 (later - file@0x<address>,<size>,<file-offset>,<file-name>)
1057
1058 Specifies a file to read directly into memory starting at <address> */
1059
1060
1061 STATIC_INLINE_DEVICES void
1062 file_init_callback(const device *me,
1063 psim *system)
1064 {
1065 unsigned_word addr;
1066 unsigned count;
1067 char *file_name;
1068 char buf;
1069 FILE *image;
1070 DTRACE_INIT(file);
1071
1072 if ((file_name = strchr(me->name, ',')) == NULL
1073 || scand_uw(me->name, &addr) != 1)
1074 error("file_init_callback() invalid file device %s\n", me->name);
1075
1076 /* open the file to load */
1077 file_name++; /* skip the `,' */
1078 image = fopen(file_name, "r");
1079 if (image == NULL)
1080 error("file_init_callback() file open failed for %s\n", me->name);
1081
1082 /* read it in slowly */
1083 count = 0;
1084 while (fread(&buf, 1, 1, image) > 0) {
1085 if (me->parent->callback->dma_write_buffer(me->parent,
1086 &buf,
1087 0 /*address-space*/,
1088 addr+count,
1089 1 /*nr-bytes*/,
1090 1 /*violate ro*/) != 1)
1091 error("file_init_callback() failed to write to address 0x%x, offset %d\n",
1092 addr+count, count);
1093 count++;
1094 }
1095
1096 /* close down again */
1097 fclose(image);
1098 }
1099
1100
1101 static device_callbacks const file_callbacks = {
1102 file_init_callback,
1103 unimp_device_attach_address,
1104 unimp_device_detach_address,
1105 unimp_device_io_read_buffer,
1106 unimp_device_io_write_buffer,
1107 unimp_device_dma_read_buffer,
1108 unimp_device_dma_write_buffer,
1109 unimp_device_attach_interrupt,
1110 unimp_device_detach_interrupt,
1111 unimp_device_interrupt,
1112 unimp_device_interrupt_ack,
1113 unimp_device_ioctl,
1114 };
1115
1116
1117 \f
1118 /* HTAB: htab@0x<address>,<nr_bytes>
1119 PTE: pte@0x<effective-address>,0x<real-address>,<nr_bytes>
1120
1121 HTAB defines the location (in physical memory) of a HASH table.
1122 PTE (as a child of HTAB) defines a mapping that is to be entered
1123 into that table.
1124
1125 NB: All the work in this device is done during init by the PTE.
1126 The pte, looks up its parent to determine the address of the HTAB
1127 and then uses DMA calls to establish the required mapping. */
1128
1129
1130 STATIC_INLINE_DEVICES void
1131 htab_init_callback(const device *me,
1132 psim *system)
1133 {
1134 DTRACE_INIT(htab);
1135 /* only the pte does work */
1136 if (strncmp(me->name, "pte@", strlen("pte@")) == 0) {
1137 unsigned_word htab_ra;
1138 unsigned htab_nr_bytes;
1139 unsigned_word pte_ea;
1140 unsigned_word pte_ra;
1141 unsigned pte_nr_bytes;
1142 /* determine the location/size of the hash table */
1143 if (scand_uw_u(me->parent->name, &htab_ra, &htab_nr_bytes) != 2)
1144 error("htab_init_callback() htab entry %s invalid\n",
1145 me->parent->name);
1146 /* determine the location/size of the mapping */
1147 if (scand_uw_uw_u(me->name, &pte_ea, &pte_ra, &pte_nr_bytes) != 3)
1148 error("htab_init_callback() pte entry %s invalid\n", me->name);
1149 error("Map ea=0x%x, ra=0x%x, nr_bytes=%d using htab=0x%x, nr_bytes=%d\n",
1150 pte_ea, pte_ra, pte_nr_bytes, htab_ra, htab_nr_bytes);
1151 }
1152 }
1153
1154
1155 static device_callbacks const htab_callbacks = {
1156 htab_init_callback,
1157 unimp_device_attach_address,
1158 unimp_device_detach_address,
1159 unimp_device_io_read_buffer,
1160 unimp_device_io_write_buffer,
1161 unimp_device_dma_read_buffer,
1162 unimp_device_dma_write_buffer,
1163 unimp_device_attach_interrupt,
1164 unimp_device_detach_interrupt,
1165 unimp_device_interrupt,
1166 unimp_device_interrupt_ack,
1167 unimp_device_ioctl,
1168 };
1169
1170
1171 \f
1172 /* Simulator device: sim@0x<address>,<nr_bytes>
1173
1174 Eventually gives access to the hardware configuration. For
1175 instance, it could allow the setting (on the fly) of variables such
1176 as hardware floating-point or strict-alignment.
1177
1178 It's intended use is as part of testing the simulators
1179 functionality */
1180
1181 static device_callbacks const sim_callbacks = {
1182 ignore_device_init,
1183 unimp_device_attach_address,
1184 unimp_device_detach_address,
1185 unimp_device_io_read_buffer,
1186 unimp_device_io_write_buffer,
1187 unimp_device_dma_read_buffer,
1188 unimp_device_dma_write_buffer,
1189 unimp_device_attach_interrupt,
1190 unimp_device_detach_interrupt,
1191 unimp_device_interrupt,
1192 unimp_device_interrupt_ack,
1193 unimp_device_ioctl,
1194 };
1195
1196
1197 \f
1198 /* Load device: *binary@<file-name>
1199
1200 Assuming that <file-name> is an executable file understood by BFD,
1201 this device loads or maps the relevant text/data segments into
1202 memory using dma. */
1203
1204 STATIC_INLINE_DEVICES void
1205 update_for_binary_section(bfd *abfd,
1206 asection *the_section,
1207 PTR obj)
1208 {
1209 unsigned_word section_vma;
1210 unsigned_word section_size;
1211 access_type access;
1212 device *me = (device*)obj;
1213
1214 /* skip the section if no memory to allocate */
1215 if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
1216 return;
1217
1218 /* check/ignore any sections of size zero */
1219 section_size = bfd_get_section_size_before_reloc(the_section);
1220 if (section_size == 0)
1221 return;
1222
1223 /* find where it is to go */
1224 section_vma = bfd_get_section_vma(abfd, the_section);
1225
1226 DTRACE(binary,
1227 ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
1228 bfd_get_section_name(abfd, the_section),
1229 section_vma, section_size,
1230 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" : ""
1236 ));
1237
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;
1244
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,
1248 me->name,
1249 attach_raw_memory,
1250 0 /*address space*/,
1251 section_vma,
1252 section_size,
1253 access,
1254 me);
1255
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,
1260 the_section,
1261 section_init, 0,
1262 section_size)) {
1263 bfd_perror("core:load_section()");
1264 error("load of data failed");
1265 return;
1266 }
1267 if (me->parent->callback->dma_write_buffer(me->parent,
1268 section_init,
1269 0 /*space*/,
1270 section_vma,
1271 section_size,
1272 1 /*violate_read_only*/)
1273 != section_size)
1274 error("data_init_callback() broken transfer for %s\n", me->name);
1275 zfree(section_init); /* only free if load */
1276 }
1277 }
1278
1279
1280 STATIC_INLINE_DEVICES void
1281 binary_init_callback(const device *me,
1282 psim *system)
1283 {
1284 char file_name[100];
1285 bfd *image;
1286 DTRACE_INIT(binary);
1287
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",
1291 me->name);
1292
1293 /* open the file */
1294 image = bfd_openr(file_name, NULL);
1295 if (image == NULL) {
1296 bfd_perror("open failed:");
1297 error("nothing loaded\n");
1298 }
1299
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);
1304 bfd_close(image);
1305 image = NULL;
1306 }
1307
1308 /* and the data sections */
1309 bfd_map_over_sections(image,
1310 update_for_binary_section,
1311 (PTR)me);
1312
1313 bfd_close(image);
1314 }
1315
1316
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,
1329 unimp_device_ioctl,
1330 };
1331
1332
1333 \f
1334 /* Stack device: stack@<type>
1335
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.
1339
1340 The IOCTL takes the additional arguments:
1341
1342 unsigned_word stack_end -- where the stack should come down from
1343 char **argv -- ...
1344 char **envp -- ...
1345
1346 */
1347
1348 STATIC_INLINE_DEVICES int
1349 sizeof_argument_strings(char **arg)
1350 {
1351 int sizeof_strings = 0;
1352
1353 /* robust */
1354 if (arg == NULL)
1355 return 0;
1356
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);
1361 }
1362
1363 return sizeof_strings;
1364 }
1365
1366 STATIC_INLINE_DEVICES int
1367 number_of_arguments(char **arg)
1368 {
1369 int nr;
1370 if (arg == NULL)
1371 return 0;
1372 for (nr = 0; *arg != NULL; arg++, nr++);
1373 return nr;
1374 }
1375
1376 STATIC_INLINE_DEVICES int
1377 sizeof_arguments(char **arg)
1378 {
1379 return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
1380 }
1381
1382 STATIC_INLINE_DEVICES void
1383 write_stack_arguments(psim *system,
1384 char **arg,
1385 unsigned_word start_block,
1386 unsigned_word end_block,
1387 unsigned_word start_arg,
1388 unsigned_word end_arg)
1389 {
1390 DTRACE(stack,
1391 ("write_stack_arguments(system=0x%x, arg=0x%x, start_block=0x%x, end_block=0x%x, start_arg=0x%x, end_arg=0x%x)\n",
1392 system, arg, start_block, end_block, start_arg, end_arg));
1393 if (arg == NULL)
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;
1399 DTRACE(stack,
1400 ("write_stack_arguments() write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
1401 "**arg", *arg, "start_block", start_block,
1402 "len", len, "start_arg", start_arg));
1403 if (psim_write_memory(system, 0, *arg,
1404 start_block, len,
1405 0/*violate_readonly*/) != len)
1406 error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
1407 *arg, start_block);
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);
1415 }
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");
1420 DTRACE(stack,
1421 ("write_stack_arguments() = void\n"));
1422 }
1423
1424 STATIC_INLINE_DEVICES void
1425 create_elf_stack_frame(psim *system,
1426 unsigned_word bottom_of_stack,
1427 char **argv,
1428 char **envp)
1429 {
1430 /* fixme - this is over aligned */
1431
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;
1437
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);
1441
1442 /* environment points (including null sentinal) */
1443 const unsigned sizeof_envp = sizeof_arguments(envp);
1444 const unsigned_word start_envp = start_aux - sizeof_envp;
1445
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;
1450
1451 /* link register save address - alligned to a 16byte boundary */
1452 const unsigned_word top_of_stack = ((start_argv
1453 - 2 * sizeof(unsigned_word))
1454 & ~0xf);
1455
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);
1463
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);
1475 }
1476
1477 STATIC_INLINE_DEVICES void
1478 create_aix_stack_frame(psim *system,
1479 unsigned_word bottom_of_stack,
1480 char **argv,
1481 char **envp)
1482 {
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;
1488
1489 /* cheat - create an elf stack frame */
1490 create_elf_stack_frame(system, bottom_of_stack, argv, envp);
1491
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);
1498
1499 /* extract arguments from registers */
1500 error("create_aix_stack_frame() - what happens next?\n");
1501 }
1502
1503
1504
1505 static void
1506 stack_ioctl_callback(const device *me,
1507 psim *system,
1508 cpu *processor,
1509 unsigned_word cia,
1510 ...)
1511 {
1512 va_list ap;
1513 unsigned_word stack_pointer;
1514 char **argv;
1515 char **envp;
1516 va_start(ap, cia);
1517 stack_pointer = va_arg(ap, unsigned_word);
1518 argv = va_arg(ap, char **);
1519 envp = va_arg(ap, char **);
1520 va_end(ap);
1521 DTRACE(stack,
1522 ("stack_ioctl_callback(me=0x%x:%s, system=0x%x, processor=0x%x, cia=0x%x, argv=0x%x, envp=0x%x)\n",
1523 me, me->full_name, system, processor, cia, argv, 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);
1528 DTRACE(stack,
1529 ("stack_ioctl_callback() = void\n"));
1530 }
1531
1532
1533 static device_callbacks const stack_callbacks = {
1534 ignore_device_init,
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,
1546 };
1547
1548
1549 \f
1550 /* Table of all the devices and a function to lookup/create a device
1551 from its name */
1552
1553 typedef const device *(device_creator)
1554 (const char *name,
1555 const char *full_name,
1556 const device *parent);
1557
1558 typedef struct _device_descriptor device_descriptor;
1559 struct _device_descriptor {
1560 const char *name;
1561 device_creator *creator;
1562 const device_callbacks *callbacks;
1563 };
1564
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, &register_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 },
1580 { NULL },
1581 };
1582
1583
1584 INLINE_DEVICES const device *
1585 device_create(const char *name,
1586 const char *full_name,
1587 const device *parent)
1588 {
1589 device_descriptor *device;
1590 int name_len;
1591 char *chp;
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);
1600 else
1601 return device_create_from(name,
1602 full_name,
1603 NULL /* data */,
1604 device->callbacks,
1605 parent);
1606 }
1607 error("device_create() unknown device %s\n", name);
1608 return NULL;
1609 }
1610
1611
1612 INLINE_DEVICES const device *
1613 device_create_from(const char *name,
1614 const char *full_name,
1615 void *data,
1616 const device_callbacks *callback,
1617 const device *parent)
1618 {
1619 device *me = ZALLOC(device);
1620 me->name = strdup(name);
1621 me->full_name = strdup(full_name);
1622 me->data = data;
1623 me->callback = callback;
1624 me->parent = parent;
1625 return me;
1626 }
1627
1628
1629 INLINE_DEVICES const device_callbacks *
1630 passthrough_device_callbacks(void)
1631 {
1632 static const device_callbacks callbacks = {
1633 ignore_device_init,
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,
1644 unimp_device_ioctl,
1645 };
1646 return &callbacks;
1647 }
1648
1649
1650
1651 #endif /* _DEVICES_C_ */
This page took 0.081446 seconds and 4 git commands to generate.