gdb: remove newlines from some linux_nat_debug_printf calls
[binutils-gdb.git] / sim / ppc / hw_memory.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1997, 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_MEMORY_C_
22 #define _HW_MEMORY_C_
23
24 #ifndef STATIC_INLINE_HW_MEMORY
25 #define STATIC_INLINE_HW_MEMORY STATIC_INLINE
26 #endif
27
28 /* This must come before any other includes. */
29 #include "defs.h"
30
31 #include <stdlib.h>
32
33 #include "device_table.h"
34
35 /* DEVICE
36
37
38 memory - description of system memory
39
40
41 DESCRIPTION
42
43
44 This device describes the size and location of the banks of
45 physical memory within the simulation.
46
47 In addition, this device supports the "claim" and "release" methods
48 that can be used by OpenBoot client programs to manage the
49 allocation of physical memory.
50
51
52 PROPERTIES
53
54
55 reg = { <address> <size> } (required)
56
57 Each pair specify one bank of memory.
58
59 available = { <address> <size> } (automatic)
60
61 Each pair specifies a block of memory that is currently unallocated.
62
63
64 BUGS
65
66
67 OpenFirmware doesn't make it clear if, when releasing memory the
68 same address + size pair as was used during the claim should be
69 specified.
70
71 It is assumed that #size-cells and #address-cells for the parent
72 node of this device are both one i.e. an address or size can be
73 specified using a single memory cell (word).
74
75 Significant work will be required before the <<memory>> device can
76 support 64bit addresses (#address-cells equal two).
77
78 */
79
80 typedef struct _memory_reg_spec {
81 unsigned_cell base;
82 unsigned_cell size;
83 } memory_reg_spec;
84
85 typedef struct _hw_memory_chunk hw_memory_chunk;
86 struct _hw_memory_chunk {
87 unsigned_word address;
88 unsigned_word size;
89 int available;
90 hw_memory_chunk *next;
91 };
92
93 typedef struct _hw_memory_device {
94 hw_memory_chunk *heap;
95 } hw_memory_device;
96
97
98 static void *
99 hw_memory_create(const char *name,
100 const device_unit *unit_address,
101 const char *args)
102 {
103 hw_memory_device *hw_memory = ZALLOC(hw_memory_device);
104 return hw_memory;
105 }
106
107
108 static void
109 hw_memory_set_available(device *me,
110 hw_memory_device *hw_memory)
111 {
112 hw_memory_chunk *chunk = NULL;
113 memory_reg_spec *available = NULL;
114 int nr_available = 0;
115 int curr = 0;
116 int sizeof_available = 0;
117 /* determine the nr of available chunks */
118 chunk = hw_memory->heap;
119 nr_available = 0;
120 while (chunk != NULL) {
121 if (chunk->available)
122 nr_available += 1;
123 ASSERT(chunk->next == NULL
124 || chunk->address < chunk->next->address);
125 ASSERT(chunk->next == NULL
126 || chunk->address + chunk->size == chunk->next->address);
127 chunk = chunk->next;
128 }
129 /* now create the available struct */
130 ASSERT(nr_available > 0);
131 sizeof_available = sizeof(memory_reg_spec) * nr_available;
132 available = zalloc(sizeof_available);
133 chunk = hw_memory->heap;
134 curr = 0;
135 while (chunk != NULL) {
136 if (chunk->available) {
137 available[curr].base = H2BE_cell(chunk->address);
138 available[curr].size = H2BE_cell(chunk->size);
139 curr += 1;
140 }
141 chunk = chunk->next;
142 }
143 /* update */
144 device_set_array_property(me, "available", available, sizeof_available);
145 free(available);
146 }
147
148
149 static void
150 hw_memory_init_address(device *me)
151 {
152 hw_memory_device *hw_memory = (hw_memory_device*)device_data(me);
153
154 /* free up any previous structures */
155 {
156 hw_memory_chunk *curr_chunk = hw_memory->heap;
157 hw_memory->heap = NULL;
158 while (curr_chunk != NULL) {
159 hw_memory_chunk *dead_chunk = curr_chunk;
160 curr_chunk = dead_chunk->next;
161 dead_chunk->next = NULL;
162 free(dead_chunk);
163 }
164 }
165
166 /* attach memory regions according to the "reg" property */
167 {
168 int reg_nr;
169 reg_property_spec reg;
170 for (reg_nr = 0;
171 device_find_reg_array_property(me, "reg", reg_nr, &reg);
172 reg_nr++) {
173 int i;
174 /* check that the entry meets restrictions */
175 for (i = 0; i < reg.address.nr_cells - 1; i++)
176 if (reg.address.cells[i] != 0)
177 device_error(me, "Only single celled addresses supported");
178 for (i = 0; i < reg.size.nr_cells - 1; i++)
179 if (reg.size.cells[i] != 0)
180 device_error(me, "Only single celled sizes supported");
181 /* attach the range */
182 device_attach_address(device_parent(me),
183 attach_raw_memory,
184 0 /*address space*/,
185 reg.address.cells[reg.address.nr_cells - 1],
186 reg.size.cells[reg.size.nr_cells - 1],
187 access_read_write_exec,
188 me);
189 }
190 }
191
192 /* create the initial `available memory' data structure */
193 if (device_find_property(me, "available") != NULL) {
194 hw_memory_chunk **curr_chunk = &hw_memory->heap;
195 int cell_nr;
196 signed_cell dummy;
197 int nr_cells = device_find_integer_array_property(me, "available", 0, &dummy);
198 if ((nr_cells % 2) != 0)
199 device_error(me, "property \"available\" invalid - contains an odd number of cells");
200 for (cell_nr = 0;
201 cell_nr < nr_cells;
202 cell_nr += 2) {
203 hw_memory_chunk *new_chunk = ZALLOC(hw_memory_chunk);
204 device_find_integer_array_property(me, "available", cell_nr,
205 (signed_cell *)&new_chunk->address);
206 device_find_integer_array_property(me, "available", cell_nr + 1,
207 (signed_cell *)&new_chunk->size);
208 new_chunk->available = 1;
209 *curr_chunk = new_chunk;
210 curr_chunk = &new_chunk->next;
211 }
212 }
213 else {
214 hw_memory_chunk **curr_chunk = &hw_memory->heap;
215 int reg_nr;
216 reg_property_spec reg;
217 for (reg_nr = 0;
218 device_find_reg_array_property(me, "reg", reg_nr, &reg);
219 reg_nr++) {
220 hw_memory_chunk *new_chunk;
221 new_chunk = ZALLOC(hw_memory_chunk);
222 new_chunk->address = reg.address.cells[reg.address.nr_cells - 1];
223 new_chunk->size = reg.size.cells[reg.size.nr_cells - 1];
224 new_chunk->available = 1;
225 *curr_chunk = new_chunk;
226 curr_chunk = &new_chunk->next;
227 }
228 }
229
230 /* initialize the alloc property for this device */
231 hw_memory_set_available(me, hw_memory);
232 }
233
234 static void
235 hw_memory_instance_delete(device_instance *instance)
236 {
237 return;
238 }
239
240 static int
241 hw_memory_instance_claim(device_instance *instance,
242 int n_stack_args,
243 unsigned_cell stack_args[/*n_stack_args*/],
244 int n_stack_returns,
245 unsigned_cell stack_returns[/*n_stack_returns*/])
246 {
247 hw_memory_device *hw_memory = device_instance_data(instance);
248 device *me = device_instance_device(instance);
249 int stackp = 0;
250 unsigned_word alignment;
251 unsigned_cell size;
252 unsigned_cell address;
253 hw_memory_chunk *chunk = NULL;
254
255 /* get the alignment from the stack */
256 if (n_stack_args < stackp + 1)
257 device_error(me, "claim - incorrect number of arguments (alignment missing)");
258 alignment = stack_args[stackp];
259 stackp++;
260
261 /* get the size from the stack */
262 {
263 int i;
264 int nr_cells = device_nr_size_cells(device_parent(me));
265 if (n_stack_args < stackp + nr_cells)
266 device_error(me, "claim - incorrect number of arguments (size missing)");
267 for (i = 0; i < nr_cells - 1; i++) {
268 if (stack_args[stackp] != 0)
269 device_error(me, "claim - multi-cell sizes not supported");
270 stackp++;
271 }
272 size = stack_args[stackp];
273 stackp++;
274 }
275
276 /* get the address from the stack */
277 {
278 int nr_cells = device_nr_address_cells(device_parent(me));
279 if (alignment != 0) {
280 if (n_stack_args != stackp) {
281 if (n_stack_args == stackp + nr_cells)
282 DTRACE(memory, ("claim - extra address argument ignored\n"));
283 else
284 device_error(me, "claim - incorrect number of arguments (optional addr)");
285 }
286 address = 0;
287 }
288 else {
289 int i;
290 if (n_stack_args != stackp + nr_cells)
291 device_error(me, "claim - incorrect number of arguments (addr missing)");
292 for (i = 0; i < nr_cells - 1; i++) {
293 if (stack_args[stackp] != 0)
294 device_error(me, "claim - multi-cell addresses not supported");
295 stackp++;
296 }
297 address = stack_args[stackp];
298 }
299 }
300
301 /* check that there is space for the result */
302 if (n_stack_returns != 0
303 && n_stack_returns != device_nr_address_cells(device_parent(me)))
304 device_error(me, "claim - invalid number of return arguments");
305
306 /* find a chunk candidate, either according to address or alignment */
307 if (alignment == 0) {
308 chunk = hw_memory->heap;
309 while (chunk != NULL) {
310 if ((address + size) <= (chunk->address + chunk->size))
311 break;
312 chunk = chunk->next;
313 }
314 if (chunk == NULL || address < chunk->address || !chunk->available)
315 device_error(me, "failed to allocate %ld bytes at 0x%lx",
316 (unsigned long)size, (unsigned long)address);
317 DTRACE(memory, ("claim - address=0x%lx size=0x%lx\n",
318 (unsigned long)address,
319 (unsigned long)size));
320 }
321 else {
322 /* adjust the alignment so that it is a power of two */
323 unsigned_word align_mask = 1;
324 while (align_mask < alignment && align_mask != 0)
325 align_mask <<= 1;
326 if (align_mask == 0)
327 device_error(me, "alignment 0x%lx is to large", (unsigned long)alignment);
328 align_mask -= 1;
329 /* now find an aligned chunk that fits */
330 chunk = hw_memory->heap;
331 while (chunk != NULL) {
332 address = ((chunk->address + align_mask) & ~align_mask);
333 if ((chunk->available)
334 && (chunk->address + chunk->size >= address + size))
335 break;
336 chunk = chunk->next;
337 }
338 if (chunk == NULL)
339 device_error(me, "failed to allocate %ld bytes with alignment %ld",
340 (unsigned long)size, (unsigned long)alignment);
341 DTRACE(memory, ("claim - size=0x%lx alignment=%ld (0x%lx), address=0x%lx\n",
342 (unsigned long)size,
343 (unsigned long)alignment,
344 (unsigned long)alignment,
345 (unsigned long)address));
346 }
347
348 /* break off a bit before this chunk if needed */
349 ASSERT(address >= chunk->address);
350 if (address > chunk->address) {
351 hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
352 /* insert a new chunk */
353 next_chunk->next = chunk->next;
354 chunk->next = next_chunk;
355 /* adjust the address/size */
356 next_chunk->address = address;
357 next_chunk->size = chunk->address + chunk->size - next_chunk->address;
358 next_chunk->available = 1;
359 chunk->size = next_chunk->address - chunk->address;
360 /* make this new chunk the one to allocate */
361 chunk = next_chunk;
362 }
363 ASSERT(address == chunk->address);
364
365 /* break off a bit after this chunk if needed */
366 ASSERT(address + size <= chunk->address + chunk->size);
367 if (address + size < chunk->address + chunk->size) {
368 hw_memory_chunk *next_chunk = ZALLOC(hw_memory_chunk);
369 /* insert it in to the list */
370 next_chunk->next = chunk->next;
371 chunk->next = next_chunk;
372 /* adjust the address/size */
373 next_chunk->address = address + size;
374 next_chunk->size = chunk->address + chunk->size - next_chunk->address;
375 next_chunk->available = 1;
376 chunk->size = next_chunk->address - chunk->address;
377 }
378 ASSERT(address + size == chunk->address + chunk->size);
379
380 /* now allocate/return it */
381 chunk->available = 0;
382 hw_memory_set_available(device_instance_device(instance), hw_memory);
383 if (n_stack_returns > 0) {
384 int i;
385 for (i = 0; i < n_stack_returns - 1; i++)
386 stack_returns[i] = 0;
387 stack_returns[n_stack_returns - 1] = address;
388 }
389
390 return 0;
391 }
392
393
394 static int
395 hw_memory_instance_release(device_instance *instance,
396 int n_stack_args,
397 unsigned_cell stack_args[/*n_stack_args*/],
398 int n_stack_returns,
399 unsigned_cell stack_returns[/*n_stack_returns*/])
400 {
401 hw_memory_device *hw_memory = device_instance_data(instance);
402 device *me = device_instance_device(instance);
403 unsigned_word length;
404 unsigned_word address;
405 int stackp = 0;
406 hw_memory_chunk *chunk;
407
408 /* get the length from the stack */
409 {
410 int i;
411 int nr_cells = device_nr_size_cells(device_parent(me));
412 if (n_stack_args < stackp + nr_cells)
413 device_error(me, "release - incorrect number of arguments (length missing)");
414 for (i = 0; i < nr_cells - 1; i++) {
415 if (stack_args[stackp] != 0)
416 device_error(me, "release - multi-cell length not supported");
417 stackp++;
418 }
419 length = stack_args[stackp];
420 stackp++;
421 }
422
423 /* get the address from the stack */
424 {
425 int i;
426 int nr_cells = device_nr_address_cells(device_parent(me));
427 if (n_stack_args != stackp + nr_cells)
428 device_error(me, "release - incorrect number of arguments (addr missing)");
429 for (i = 0; i < nr_cells - 1; i++) {
430 if (stack_args[stackp] != 0)
431 device_error(me, "release - multi-cell addresses not supported");
432 stackp++;
433 }
434 address = stack_args[stackp];
435 }
436
437 /* returns ok */
438 if (n_stack_returns != 0)
439 device_error(me, "release - nonzero number of results");
440
441 /* try to free the corresponding memory chunk */
442 chunk = hw_memory->heap;
443 while (chunk != NULL) {
444 if (chunk->address == address
445 && chunk->size == length) {
446 /* an exact match */
447 if (chunk->available)
448 device_error(me, "memory chunk 0x%lx (size 0x%lx) already available",
449 (unsigned long)address,
450 (unsigned long)length);
451 else {
452 /* free this chunk */
453 DTRACE(memory, ("release - address=0x%lx, length=0x%lx\n",
454 (unsigned long) address,
455 (unsigned long) length));
456 chunk->available = 1;
457 break;
458 }
459 }
460 else if (chunk->address >= address
461 && chunk->address + chunk->size <= address + length) {
462 /* a sub region */
463 if (!chunk->available) {
464 DTRACE(memory, ("release - address=0x%lx, size=0x%lx within region 0x%lx length 0x%lx\n",
465 (unsigned long) chunk->address,
466 (unsigned long) chunk->size,
467 (unsigned long) address,
468 (unsigned long) length));
469 chunk->available = 1;
470 }
471 }
472 chunk = chunk->next;
473 }
474 if (chunk == NULL) {
475 printf_filtered("warning: released chunks within region 0x%lx..0x%lx\n",
476 (unsigned long)address,
477 (unsigned long)(address + length - 1));
478 }
479
480 /* check for the chance to merge two adjacent available memory chunks */
481 chunk = hw_memory->heap;
482 while (chunk != NULL) {
483 if (chunk->available
484 && chunk->next != NULL && chunk->next->available) {
485 /* adjacent */
486 hw_memory_chunk *delete = chunk->next;
487 ASSERT(chunk->address + chunk->size == delete->address);
488 chunk->size += delete->size;
489 chunk->next = delete->next;
490 free(delete);
491 }
492 else {
493 chunk = chunk->next;
494 }
495 }
496
497 /* update the corresponding property */
498 hw_memory_set_available(device_instance_device(instance), hw_memory);
499
500 return 0;
501 }
502
503
504 static device_instance_methods hw_memory_instance_methods[] = {
505 { "claim", hw_memory_instance_claim },
506 { "release", hw_memory_instance_release },
507 { NULL, },
508 };
509
510 static device_instance_callbacks const hw_memory_instance_callbacks = {
511 hw_memory_instance_delete,
512 NULL /*read*/, NULL /*write*/, NULL /*seek*/,
513 hw_memory_instance_methods
514 };
515
516 static device_instance *
517 hw_memory_create_instance(device *me,
518 const char *path,
519 const char *args)
520 {
521 return device_create_instance_from(me, NULL,
522 device_data(me), /* nothing better */
523 path, args,
524 &hw_memory_instance_callbacks);
525 }
526
527 static device_callbacks const hw_memory_callbacks = {
528 { hw_memory_init_address, },
529 { NULL, }, /* address */
530 { NULL, }, /* IO */
531 { NULL, }, /* DMA */
532 { NULL, }, /* interrupt */
533 { NULL, }, /* unit */
534 hw_memory_create_instance,
535 };
536
537 const device_descriptor hw_memory_device_descriptor[] = {
538 { "memory", hw_memory_create, &hw_memory_callbacks },
539 { NULL },
540 };
541
542 #endif /* _HW_MEMORY_C_ */