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