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