Obey --silent
[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 ((int)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 ((int)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 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
551 interrupt next */
552 me->parent->callback->interrupt(me->parent, me,
553 val, val,
554 processor, cia);
555 return nr_bytes;
556 }
557
558
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,
571 unimp_device_ioctl,
572 };
573
574
575 \f
576 /* HALT device: halt@0x<address>,4
577
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 */
581
582
583 STATIC_INLINE_DEVICES unsigned
584 halt_io_read_buffer_callback(const device *me,
585 void *dest,
586 int space,
587 unsigned_word addr,
588 unsigned nr_bytes,
589 cpu *processor,
590 unsigned_word cia)
591 {
592 DTRACE_IO_READ_BUFFER(halt);
593 cpu_halt(processor, cia, was_exited, 0);
594 return 0;
595 }
596
597
598 STATIC_INLINE_DEVICES unsigned
599 halt_io_write_buffer_callback(const device *me,
600 const void *source,
601 int space,
602 unsigned_word addr,
603 unsigned nr_bytes,
604 cpu *processor,
605 unsigned_word cia)
606 {
607 DTRACE_IO_WRITE_BUFFER(halt);
608 cpu_halt(processor, cia, was_exited, 0);
609 return 0;
610 }
611
612
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,
625 unimp_device_ioctl,
626 };
627
628
629 \f
630 /* Register init device: register@<name>,0x<value>[,<processor>]
631
632 This strange device is used to initialize the processors registers
633 as part of the initialization. */
634
635 STATIC_INLINE_DEVICES void
636 register_init_callback(const device *me,
637 psim *system)
638 {
639 char name[100];
640 unsigned_word value;
641 unsigned which_cpu;
642 int status;
643 DTRACE_INIT(register);
644 status = scand_c_uw_u(me->name, name, sizeof(name), &value, &which_cpu);
645 switch (status) {
646 case 2: /* register@<name>,<value> */
647 psim_write_register(system, -1, &value, name, cooked_transfer);
648 break;
649 case 3: /* register@<name>,<value>,<processor> */
650 psim_write_register(system, which_cpu, &value, name, cooked_transfer);
651 break;
652 default:
653 error("register_init_callback() invalid register init %s\n", me->name);
654 break;
655 }
656 }
657
658
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,
671 unimp_device_ioctl,
672 };
673
674
675 \f
676 /* VEA VM device: vm@0x<stack-base>,<nr_bytes>
677
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
682 allowed to continue.
683
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.
687
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.
692
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). */
697
698
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;
708 } vm_device;
709
710
711 STATIC_INLINE_DEVICES void
712 vm_init_callback(const device *me,
713 psim *system)
714 {
715 vm_device *vm = (vm_device*)me->data;
716 DTRACE_INIT(vm);
717
718 /* revert the stack/heap variables to their defaults */
719 vm->stack_lower_limit = vm->stack_bound;
720 vm->heap_base = 0;
721 vm->heap_bound = 0;
722 vm->heap_upper_limit = 0;
723
724 /* establish this device as the default memory handler */
725 me->parent->callback->attach_address(me->parent,
726 me->name,
727 attach_default,
728 0 /*address space - ignore*/,
729 0 /*addr - ignore*/,
730 0 /*nr_bytes - ignore*/,
731 access_read_write /*access*/,
732 me);
733 }
734
735
736 STATIC_INLINE_DEVICES void
737 vm_attach_address(const device *me,
738 const char *name,
739 attach_type attach,
740 int space,
741 unsigned_word addr,
742 unsigned nr_bytes,
743 access_type access,
744 const device *who) /*callback/default*/
745 {
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;
753 }
754 me->parent->callback->attach_address(me->parent,
755 "vm@0x0,0", /* stop remap */
756 attach_raw_memory,
757 0 /*address space*/,
758 addr,
759 nr_bytes,
760 access,
761 me);
762 }
763
764
765 STATIC_INLINE_DEVICES unsigned
766 add_vm_space(const device *me,
767 unsigned_word addr,
768 unsigned nr_bytes,
769 cpu *processor,
770 unsigned_word cia)
771 {
772 vm_device *vm = (vm_device*)me->data;
773 unsigned_word block_addr;
774 unsigned block_nr_bytes;
775
776 /* an address in the stack area, allocate just down to the addressed
777 page */
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;
782 }
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;
788 }
789 /* oops - an invalid address - abort the cpu */
790 else if (processor != NULL) {
791 cpu_halt(processor, cia, was_signalled, SIGSEGV);
792 return 0;
793 }
794 /* 2*oops - an invalid address and no processor */
795 else {
796 return 0;
797 }
798
799 /* got the parameters, allocate the space */
800 me->parent->callback->attach_address(me->parent,
801 "vm@0x0,0", /* stop remap */
802 attach_raw_memory,
803 0 /*address space*/,
804 block_addr,
805 block_nr_bytes,
806 access_read_write,
807 me);
808 return block_nr_bytes;
809 }
810
811
812 STATIC_INLINE_DEVICES unsigned
813 vm_io_read_buffer_callback(const device *me,
814 void *dest,
815 int space,
816 unsigned_word addr,
817 unsigned nr_bytes,
818 cpu *processor,
819 unsigned_word cia)
820 {
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 */
824 return nr_bytes;
825 }
826 else
827 return 0;
828 }
829
830
831 STATIC_INLINE_DEVICES unsigned
832 vm_io_write_buffer_callback(const device *me,
833 const void *source,
834 int space,
835 unsigned_word addr,
836 unsigned nr_bytes,
837 cpu *processor,
838 unsigned_word cia)
839 {
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,
843 space, addr,
844 nr_bytes,
845 0/*violate_read_only*/);
846 }
847 else
848 return 0;
849 }
850
851
852 static void
853 vm_ioctl_callback(const device *me,
854 psim *system,
855 cpu *processor,
856 unsigned_word cia,
857 ...)
858 {
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
861 boundary. */
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;
866 if (delta > 0)
867 vm->heap_bound = ALIGN_PAGE(new_break);
868 cpu_registers(processor)->gpr[0] = 0;
869 cpu_registers(processor)->gpr[3] = new_break;
870 }
871
872
873 static device_callbacks const vm_callbacks = {
874 vm_init_callback,
875 vm_attach_address,
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,
885 vm_ioctl_callback,
886 };
887
888
889 STATIC_INLINE_DEVICES const device *
890 vea_vm_create(const char *name,
891 const char *full_name,
892 const device *parent)
893 {
894 vm_device *vm = ZALLOC(vm_device);
895 unsigned_word addr;
896 unsigned nr_bytes;
897
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;
903
904 /* insert in the tree including the buffer */
905 return device_create_from(name,
906 full_name,
907 vm, /* data */
908 &vm_callbacks,
909 parent);
910 }
911
912
913 \f
914 /* Memory init device: memory@0x<addr>,<size>,<access>
915
916 This strange device is used create sections of memory */
917
918 STATIC_INLINE_DEVICES void
919 memory_init_callback(const device *me,
920 psim *system)
921 {
922 unsigned_word addr;
923 unsigned nr_bytes;
924 unsigned access;
925 int nr_args;
926 DTRACE_INIT(memory);
927
928 nr_args = scand_uw_u_u(me->name, &addr, &nr_bytes, &access);
929 switch (nr_args) {
930 case 2:
931 access = access_read_write_exec;
932 break;
933 case 3:
934 break;
935 default:
936 error("memory_init_callback() invalid memory device %s\n", me->name);
937 break;
938 }
939
940 me->parent->callback->attach_address(me->parent,
941 me->name,
942 attach_raw_memory,
943 0 /*address space*/,
944 addr,
945 nr_bytes,
946 (access_type)access,
947 me);
948 }
949
950
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,
963 unimp_device_ioctl,
964 };
965
966
967 \f
968 /* IOBUS device: iobus@<address>
969
970 Simple bus on which some IO devices live */
971
972 STATIC_INLINE_DEVICES void
973 iobus_attach_address_callback(const device *me,
974 const char *name,
975 attach_type type,
976 int space,
977 unsigned_word addr,
978 unsigned nr_bytes,
979 access_type access,
980 const device *who) /*callback/default*/
981 {
982 unsigned_word iobus_addr;
983 /* sanity check */
984 if (type == attach_default)
985 error("iobus_attach_address_callback() no default for %s/%s\n",
986 me->name, name);
987 if (space != 0)
988 error("iobus_attach_address_callback() no space for %s/%s\n",
989 me->name, name);
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",
993 me->name);
994 me->parent->callback->attach_address(me->parent,
995 me->name,
996 type,
997 0 /*space*/,
998 iobus_addr + addr,
999 nr_bytes,
1000 access,
1001 who);
1002 }
1003
1004
1005 STATIC_INLINE_DEVICES void
1006 iobus_do_interrupt(event_queue *queue,
1007 void *data)
1008 {
1009 cpu *target = (cpu*)data;
1010 /* try to interrupt the processor. If the attempt fails, try again
1011 on the next tick */
1012 if (!external_interrupt(target))
1013 event_queue_schedule(queue, 1, iobus_do_interrupt, target);
1014 }
1015
1016
1017 STATIC_INLINE_DEVICES void
1018 iobus_interrupt_callback(const device *me,
1019 const device *who,
1020 int interrupt_line,
1021 int interrupt_status,
1022 cpu *processor,
1023 unsigned_word cia)
1024 {
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);
1033 }
1034 }
1035
1036
1037 static device_callbacks const iobus_callbacks = {
1038 ignore_device_init,
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,
1049 unimp_device_ioctl,
1050 };
1051
1052
1053 \f
1054 /* FILE device: file@0x<address>,<file-name>
1055 (later - file@0x<address>,<size>,<file-offset>,<file-name>)
1056
1057 Specifies a file to read directly into memory starting at <address> */
1058
1059
1060 STATIC_INLINE_DEVICES void
1061 file_init_callback(const device *me,
1062 psim *system)
1063 {
1064 unsigned_word addr;
1065 unsigned count;
1066 char *file_name;
1067 char buf;
1068 FILE *image;
1069 DTRACE_INIT(file);
1070
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);
1074
1075 /* open the file to load */
1076 file_name++; /* skip the `,' */
1077 image = fopen(file_name, "r");
1078 if (image == NULL)
1079 error("file_init_callback() file open failed for %s\n", me->name);
1080
1081 /* read it in slowly */
1082 count = 0;
1083 while (fread(&buf, 1, 1, image) > 0) {
1084 if (me->parent->callback->dma_write_buffer(me->parent,
1085 &buf,
1086 0 /*address-space*/,
1087 addr+count,
1088 1 /*nr-bytes*/,
1089 1 /*violate ro*/) != 1)
1090 error("file_init_callback() failed to write to address 0x%x, offset %d\n",
1091 addr+count, count);
1092 count++;
1093 }
1094
1095 /* close down again */
1096 fclose(image);
1097 }
1098
1099
1100 static device_callbacks const file_callbacks = {
1101 file_init_callback,
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,
1112 unimp_device_ioctl,
1113 };
1114
1115
1116 \f
1117 /* HTAB: htab@0x<address>,<nr_bytes>
1118 PTE: pte@0x<effective-address>,0x<real-address>,<nr_bytes>
1119
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
1122 into that table.
1123
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. */
1127
1128
1129 STATIC_INLINE_DEVICES void
1130 htab_init_callback(const device *me,
1131 psim *system)
1132 {
1133 DTRACE_INIT(htab);
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",
1144 me->parent->name);
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);
1150 }
1151 }
1152
1153
1154 static device_callbacks const htab_callbacks = {
1155 htab_init_callback,
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,
1166 unimp_device_ioctl,
1167 };
1168
1169
1170 \f
1171 /* Simulator device: sim@0x<address>,<nr_bytes>
1172
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.
1176
1177 It's intended use is as part of testing the simulators
1178 functionality */
1179
1180 static device_callbacks const sim_callbacks = {
1181 ignore_device_init,
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,
1192 unimp_device_ioctl,
1193 };
1194
1195
1196 \f
1197 /* Load device: *binary@<file-name>
1198
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. */
1202
1203 STATIC_INLINE_DEVICES void
1204 update_for_binary_section(bfd *abfd,
1205 asection *the_section,
1206 PTR obj)
1207 {
1208 unsigned_word section_vma;
1209 unsigned_word section_size;
1210 access_type access;
1211 device *me = (device*)obj;
1212
1213 /* skip the section if no memory to allocate */
1214 if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
1215 return;
1216
1217 /* check/ignore any sections of size zero */
1218 section_size = bfd_get_section_size_before_reloc(the_section);
1219 if (section_size == 0)
1220 return;
1221
1222 /* find where it is to go */
1223 section_vma = bfd_get_section_vma(abfd, the_section);
1224
1225 DTRACE(binary,
1226 ("name=%-7s, vma=0x%.8lx, size=%6ld, flags=%3lx(%s%s%s%s%s )\n",
1227 bfd_get_section_name(abfd, the_section),
1228 (long)section_vma,
1229 (long)section_size,
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" : ""
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%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));
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%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,
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%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);
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.064026 seconds and 4 git commands to generate.