xref: /netbsd/external/gpl3/gdb.old/dist/sim/ppc/hw_vm.c (revision 6ca2c52a)
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
hw_vm_init_address_callback(device * me)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
hw_vm_attach_address(device * me,attach_type attach,int space,unsigned_word addr,unsigned nr_bytes,access_type access,device * client)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
hw_vm_add_space(device * me,unsigned_word addr,unsigned nr_bytes,cpu * processor,unsigned_word cia)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
hw_vm_io_read_buffer_callback(device * me,void * dest,int space,unsigned_word addr,unsigned nr_bytes,cpu * processor,unsigned_word cia)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
hw_vm_io_write_buffer_callback(device * me,const void * source,int space,unsigned_word addr,unsigned nr_bytes,cpu * processor,unsigned_word cia)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
hw_vm_ioctl(device * me,cpu * processor,unsigned_word cia,device_ioctl_request request,va_list ap)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 *
hw_vm_create(const char * name,const device_unit * address,const char * args)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_ */
275