sim: ppc: do not exit when parsing args w/gdb
[external/binutils.git] / sim / ppc / hw_vm.c
1 /*  This file is part of the program psim.
2     
3     Copyright (C) 1994-1996, 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 3 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, see <http://www.gnu.org/licenses/>.
17     
18     */
19
20
21 #ifndef _HW_VM_C_
22 #define _HW_VM_C_
23
24 #include "device_table.h"
25 #include "cpu.h"
26
27 #include <signal.h>
28
29 /* DEVICE
30
31    vm - virtual memory device for user simulation modes
32
33    DESCRIPTION
34
35    In user mode, mapped text, data and stack addresses are managed by
36    the core.  Unmapped addresses are passed onto this device (because
37    it establishes its self as the fallback device) for processing.
38
39    During initialization, children of this device will request the
40    mapping of the initial text and data segments.  Those requests are
41    passed onto the core device so that that may establish the initial
42    memory regions.
43
44    Once the simulation has started (as noted above) any access to an
45    unmapped address range will be passed down to this device as an IO
46    access.  This device will then either attach additional memory to
47    the core device or signal the access as being invalid.
48
49    The IOCTL function is used to notify this device of any changes to
50    the users `brk' point.
51
52    PROPERTIES
53
54    stack-base = <number>
55
56    Specifies the lower address of the stack segment in the users
57    virtual address space.  The initial stack page is defined by
58    stack-base + nr-bytes.
59
60    nr-bytes = <number>
61
62    Specifies the maximum size of the stack segment in the users
63    address space.
64
65    */
66
67 typedef struct _hw_vm_device {
68   /* area of memory valid for stack addresses */
69   unsigned_word stack_base; /* min possible stack value */
70   unsigned_word stack_bound;
71   unsigned_word stack_lower_limit;
72   /* area of memory valid for heap addresses */
73   unsigned_word heap_base;
74   unsigned_word heap_bound;
75   unsigned_word heap_upper_limit;
76 } hw_vm_device;
77
78
79 static void
80 hw_vm_init_address_callback(device *me)
81 {
82   hw_vm_device *vm = (hw_vm_device*)device_data(me);
83
84   /* revert the stack/heap variables to their defaults */
85   vm->stack_base = device_find_integer_property(me, "stack-base");
86   vm->stack_bound = (vm->stack_base
87                      + device_find_integer_property(me, "nr-bytes"));
88   vm->stack_lower_limit = vm->stack_bound;
89   vm->heap_base = 0;
90   vm->heap_bound = 0;
91   vm->heap_upper_limit = 0;
92
93   /* establish this device as the default memory handler */
94   device_attach_address(device_parent(me),
95                         attach_callback + 1,
96                         0 /*address space - ignore*/,
97                         0 /*addr - ignore*/,
98                         (((unsigned)0)-1) /*nr_bytes - ignore*/,
99                         access_read_write /*access*/,
100                         me);
101 }
102
103
104 static void
105 hw_vm_attach_address(device *me,
106                      attach_type attach,
107                      int space,
108                      unsigned_word addr,
109                      unsigned nr_bytes,
110                      access_type access,
111                      device *client) /*callback/default*/
112 {
113   hw_vm_device *vm = (hw_vm_device*)device_data(me);
114   /* update end of bss if necessary */
115   if (vm->heap_base < addr + nr_bytes) {
116     vm->heap_base = addr + nr_bytes;
117     vm->heap_bound = addr + nr_bytes;
118     vm->heap_upper_limit = addr + nr_bytes;
119   }
120   device_attach_address(device_parent(me),
121                         attach_raw_memory,
122                         0 /*address space*/,
123                         addr,
124                         nr_bytes,
125                         access,
126                         me);
127 }
128
129
130 static unsigned
131 hw_vm_add_space(device *me,
132                 unsigned_word addr,
133                 unsigned nr_bytes,
134                 cpu *processor,
135                 unsigned_word cia)
136 {
137   hw_vm_device *vm = (hw_vm_device*)device_data(me);
138   unsigned_word block_addr;
139   unsigned block_nr_bytes;
140
141   /* an address in the stack area, allocate just down to the addressed
142      page */
143   if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
144     block_addr = FLOOR_PAGE(addr);
145     block_nr_bytes = vm->stack_lower_limit - block_addr;
146     vm->stack_lower_limit = block_addr;
147   }
148   /* an address in the heap area, allocate all of the required heap */
149   else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
150     block_addr = vm->heap_upper_limit;
151     block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
152     vm->heap_upper_limit = vm->heap_bound;
153   }
154   /* oops - an invalid address - abort the cpu */
155   else if (processor != NULL) {
156     cpu_halt(processor, cia, was_signalled, SIGSEGV);
157     return 0;
158   }
159   /* 2*oops - an invalid address and no processor */
160   else {
161     return 0;
162   }
163
164   /* got the parameters, allocate the space */
165   device_attach_address(device_parent(me),
166                         attach_raw_memory,
167                         0 /*address space*/,
168                         block_addr,
169                         block_nr_bytes,
170                         access_read_write,
171                         me);
172   return block_nr_bytes;
173 }
174
175
176 static unsigned
177 hw_vm_io_read_buffer_callback(device *me,
178                            void *dest,
179                            int space,
180                            unsigned_word addr,
181                            unsigned nr_bytes,
182                            cpu *processor,
183                            unsigned_word cia)
184 {
185   if (hw_vm_add_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
186     memset(dest, 0, nr_bytes); /* always initialized to zero */
187     return nr_bytes;
188   }
189   else 
190     return 0;
191 }
192
193
194 static unsigned
195 hw_vm_io_write_buffer_callback(device *me,
196                             const void *source,
197                             int space,
198                             unsigned_word addr,
199                             unsigned nr_bytes,
200                             cpu *processor,
201                             unsigned_word cia)
202 {
203   if (hw_vm_add_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
204     return device_dma_write_buffer(device_parent(me), source,
205                                    space, addr,
206                                    nr_bytes,
207                                    0/*violate_read_only*/);
208   }
209   else
210     return 0;
211 }
212
213
214 static int
215 hw_vm_ioctl(device *me,
216             cpu *processor,
217             unsigned_word cia,
218             device_ioctl_request request,
219             va_list ap)
220 {
221   /* While the caller is notified that the heap has grown by the
222      requested amount, the heap is actually extended out to a page
223      boundary. */
224   hw_vm_device *vm = (hw_vm_device*)device_data(me);
225   switch (request) {
226   case device_ioctl_break:
227     {
228       unsigned_word requested_break = va_arg(ap, unsigned_word);
229       unsigned_word new_break = ALIGN_8(requested_break);
230       unsigned_word old_break = vm->heap_bound;
231       signed_word delta = new_break - old_break;
232       if (delta > 0)
233         vm->heap_bound = ALIGN_PAGE(new_break);
234       break;
235     }
236   default:
237     device_error(me, "Unsupported ioctl request");
238     break;
239   }
240   return 0;
241     
242 }
243
244
245 static device_callbacks const hw_vm_callbacks = {
246   { hw_vm_init_address_callback, },
247   { hw_vm_attach_address,
248     passthrough_device_address_detach, },
249   { hw_vm_io_read_buffer_callback,
250     hw_vm_io_write_buffer_callback, },
251   { NULL, passthrough_device_dma_write_buffer, },
252   { NULL, }, /* interrupt */
253   { generic_device_unit_decode,
254     generic_device_unit_encode, },
255   NULL, /* instance */
256   hw_vm_ioctl,
257 };
258
259
260 static void *
261 hw_vm_create(const char *name,
262              const device_unit *address,
263              const char *args)
264 {
265   hw_vm_device *vm = ZALLOC(hw_vm_device);
266   return vm;
267 }
268
269 const device_descriptor hw_vm_device_descriptor[] = {
270   { "vm", hw_vm_create, &hw_vm_callbacks },
271   { NULL },
272 };
273
274 #endif /* _HW_VM_C_ */