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