1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
|
\ *****************************************************************************
\ * Copyright (c) 2004, 2011 IBM Corporation
\ * All rights reserved.
\ * This program and the accompanying materials
\ * are made available under the terms of the BSD License
\ * which accompanies this distribution, and is available at
\ * http://www.opensource.org/licenses/bsd-license.php
\ *
\ * Contributors:
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
\ \\\\\\\\\\\\\\ Constants
500 CONSTANT AVAILABLE-SIZE
4000 CONSTANT MIN-RAM-RESERVE \ prevent from using first pages
: MIN-RAM-SIZE \ Initially available memory size
epapr-ima-size IF
epapr-ima-size
ELSE
20000000 \ assumed minimal memory size
THEN
;
MIN-RAM-SIZE CONSTANT MIN-RAM-SIZE
\ \\\\\\\\\\\\\\ Structures
\ +
\ The available element size depends strictly on the address/size
\ value formats and will be different for various device types
\ +
STRUCT
cell field available>address
cell field available>size
CONSTANT /available
\ \\\\\\\\\\\\\\ Global Data
CREATE available AVAILABLE-SIZE /available * allot available AVAILABLE-SIZE /available * erase
VARIABLE mem-pre-released 0 mem-pre-released !
\ \\\\\\\\\\\\\\ Structure/Implementation Dependent Methods
: available>size@ available>size @ ;
: available>address@ available>address @ ;
: available>size! available>size ! ;
: available>address! available>address ! ;
: available! ( addr size available-ptr -- )
dup -rot available>size! available>address!
;
: available@ ( available-ptr -- addr size )
dup available>address@ swap available>size@
;
\ \\\\\\\\\\\\\\ Implementation Independent Methods (Depend on Previous)
\ +
\ Warning: They are not yet really independent from available formatting
\ +
\ +
\ Find position in the "available" where given range exists or can be inserted,
\ return pointer and logical found/notfound value
\ If error, return NULL pointer in addition to notfound code
\ +
: (?available-segment<) ( start1 end1 start2 end2 -- true/false ) drop < nip ;
: (?available-segment>) ( start1 end1 start2 end2 -- true/false ) -rot 2drop > ;
\ start1 to end1 is the area that should be claimed
\ start2 to end2 is the available segment
\ return true if it can not be claimed, false if it can be claimed
: (?available-segment-#) ( start1 end1 start2 end2 -- true/false )
2dup 5 roll -rot ( e1 s2 e2 s1 s2 e2 )
between >r between r> and not
;
: (find-available) ( addr addr+size-1 a-ptr a-size -- a-ptr' found )
?dup 0= IF -rot 2drop false EXIT THEN \ Not Found
2dup 2/ dup >r /available * +
( addr addr+size-1 a-ptr a-size a-ptr' R: a-size' )
dup available>size@ 0= IF 2drop r> RECURSE EXIT THEN
( addr addr+size-1 a-ptr a-size a-ptr' R: a-size' )
dup >r available@
( addr addr+size-1 a-ptr a-size addr' size' R: a-size' a-ptr' )
over + 1- 2>r 2swap
( a-ptr a-size addr addr+size-1 )
( R: a-size' a-ptr' addr' addr'+size'-1 )
2dup 2r@ (?available-segment>) IF
2swap 2r> 2drop r>
/available + -rot r> - 1- nip RECURSE EXIT \ Look Right
THEN
2dup 2r@ (?available-segment<) IF
2swap 2r> 2drop r>
2drop r> RECURSE EXIT \ Look Left
THEN
2dup 2r@ (?available-segment-#) IF \ Conflict - segments overlap
2r> 2r> 3drop 3drop 2drop
1212 throw
THEN
2r> 3drop 3drop r> r> drop ( a-ptr' -- )
dup available>size@ 0<> ( a-ptr' found -- )
;
: (find-available) ( addr size -- seg-ptr found )
over + 1- available AVAILABLE-SIZE ['] (find-available) catch IF
2drop 2drop 0 false
THEN
;
: dump-available ( available-ptr -- )
cr
dup available - /available / AVAILABLE-SIZE swap - 0 ?DO
dup available@ ?dup 0= IF
2drop UNLOOP EXIT
THEN
swap . . cr
/available +
LOOP
dup
;
: .available available dump-available ;
\ +
\ release utils:
\ +
\ +
\ (drop-available) just blindly compresses space of available map
\ +
: (drop-available) ( available-ptr -- )
dup available - /available / \ current element index
AVAILABLE-SIZE swap - \ # of remaining elements
( first nelements ) 1- 0 ?DO
dup /available + dup available@
( current next next>address next>size ) ?dup 0= IF
2drop LEAVE \ NULL element - goto last copy
THEN
3 roll available! ( next )
LOOP
\ Last element : just zero it out
0 0 rot available!
;
\ +
\ (stick-to-previous-available) merge the segment on stack
\ with the previous one, if possible, and modified segment parameters if merged
\ Return success code
\ +
: (stick-to-previous-available) ( addr size available-ptr -- naddr nsize nptr success )
dup available = IF
false EXIT \ This was the first available segment
THEN
dup /available - dup available@
+ 4 pick = IF
nip \ Drop available-ptr since we are going to previous one
rot drop \ Drop start addr, we take the previous one
dup available@ 3 roll + rot true
( prev-addr prev-size+size prev-ptr true )
ELSE
drop false
( addr size available-ptr false )
THEN
;
\ +
\ (insert-available) just blindly makes space for another element on given
\ position
\ +
\ insert-available should also check adjacent elements and merge if new
\ region is contiguos w. others
\ +
: (insert-available) ( available-ptr -- available-ptr )
dup \ current element
dup available - /available / \ current element index
AVAILABLE-SIZE swap - \ # of remaining elements
dup 0<= 3 pick available>size@ 0= or IF
\ End of "available" or came to an empty element - Exit
drop drop EXIT
THEN
over available@ rot
( first first/=current/ first>address first>size nelements ) 1- 0 ?DO
2>r
( first current R: current>address current>size )
/available + dup available@
( first current+1/=next/ next>address next>size )
( R: current>address current>size )
2r> 4 pick available! dup 0= IF
\ NULL element - last copy
rot /available + available!
UNLOOP EXIT
THEN
LOOP
( first next/=last/ last[0]>address last[0]>size ) ?dup 0<> IF
cr ." release error: available map overflow"
cr ." Dumping available property"
.available
cr ." No space for one before last entry:" cr swap . .
cr ." Dying ..." cr 123 throw
THEN
2drop
;
: insert-available ( addr size available-ptr -- addr size available-ptr )
dup available>address@ 0<> IF
\ Not empty :
dup available>address@ rot dup -rot -
( addr available-ptr size available>address@-size )
3 pick = IF \ if (available>address@ - size == addr)
\ Merge w. next segment - no insert needed
over available>size@ + swap
( addr size+available>size@ available-ptr )
(stick-to-previous-available) IF
\ Merged w. prev & next one : discard extra seg
dup /available + (drop-available)
THEN
ELSE
\ shift the rest of "available" to make space
swap (stick-to-previous-available)
not IF (insert-available) THEN
THEN
ELSE
(stick-to-previous-available) drop
THEN
;
defer release
\ +
\ claim utils:
\ +
: drop-available ( addr size available-ptr -- addr )
dup >r available@
( req_addr req_size segment_addr segment_size R: available-ptr )
over 4 pick swap - ?dup 0<> IF
\ Segment starts before requested address : free the head space
dup 3 roll swap r> available! -
( req_addr req_size segment_size-segment_addr+req_addr )
over - ?dup 0= IF
\ That's it - remainder of segment is what we claim
drop
ELSE
\ Both head and tail of segment remain unclaimed :
\ need an extra available element
swap 2 pick + swap release
THEN
ELSE
nip ( req_addr req_size segment_size )
over - ?dup 0= IF
\ Exact match : drop the whole available segment
drop r> (drop-available)
ELSE
\ We claimed the head, need to leave the tail available
-rot over + rot r> available!
THEN
THEN
( base R: -- )
;
: pwr2roundup ( value -- pwr2value )
dup CASE
0 OF EXIT ENDOF
1 OF EXIT ENDOF
ENDCASE
dup 1 DO drop i dup +LOOP
dup +
;
: (claim-best-fit) ( len align -- len base )
pwr2roundup 1- -1 -1
( len align-1 best-fit-residue/=-1/ best-fit-base/=-1/ )
available AVAILABLE-SIZE /available * + available DO
i \ Must be saved now, before we use Return stack
-rot >r >r swap >r
( len i R: best-fit-base best-fit-residue align-1 )
available@ ?dup 0= IF drop r> r> r> LEAVE THEN \ EOL
2 pick - dup 0< IF
2drop \ Can't Fit: Too Small
ELSE
dup 2 pick r@ and - 0< IF
2drop \ Can't Fit When Aligned
ELSE
( len i>address i>size-len )
( R: best-fit-base best-fit-residue align-1 )
r> -rot dup r@ U< IF
\ Best Fit so far: drop the old one
2r> 2drop
( len align-1 nu-base nu-residue R: )
\ Now align new base and push to R:
swap 2 pick + 2 pick invert and >r >r >r
ELSE
2drop >r
THEN
THEN
THEN
r> r> r>
/available +LOOP
-rot 2drop ( len best-fit-base/or -1 if none found/ )
;
: (adjust-release0) ( 0 size -- addr' size' )
\ segment 0 already pre-relased in early phase: adjust
2dup MIN-RAM-SIZE dup 3 roll + -rot -
dup 0< IF 2drop ELSE
2swap 2drop 0 mem-pre-released !
THEN
;
\ \\\\\\\\\\\\\\ Exported Interface:
\ +
\ IEEE 1275 implementation:
\ claim
\ Claim the region with given start address and size (if align parameter is 0);
\ alternatively claim any region of given alignment
\ +
\ Throw an exception if failed
\ +
: claim ( [ addr ] len align -- base )
?dup 0<> IF
(claim-best-fit) dup -1 = IF
2drop cr ." claim error : aligned allocation failed" cr
." available:" cr .available
321 throw EXIT
THEN
swap
THEN
2dup (find-available) not IF
drop
\ cr ." claim error : requested " . ." bytes of memory at " .
\ ." not available" cr
\ ." available:" cr .available
2drop
321 throw EXIT
THEN
( req_addr req_size available-ptr ) drop-available
( req_addr )
;
\ +
\ IEEE 1275 implementation:
\ release
\ Free the region with given start address and size
\ +
: .release ( addr len -- )
over 0= mem-pre-released @ and IF (adjust-release0) THEN
2dup (find-available) IF
drop swap
cr ." release error: region " . ." , " . ." already released" cr
ELSE
?dup 0= IF
swap
cr ." release error: Bad/conflicting region " . ." , " .
." or available list full " cr
ELSE
( addr size available-ptr ) insert-available
\ NOTE: insert did not change the stack layout
\ but it may have changed any of the three values
\ in order to implement merge of free regions
\ We do not interpret these values any more
\ just blindly copy it in
( addr size available-ptr ) available!
THEN
THEN
;
' .release to release
\ pre-release minimal memory size
0 MIN-RAM-SIZE release 1 mem-pre-released !
\ claim first pages used for PPC exception vectors
0 MIN-RAM-RESERVE 0 ' claim CATCH IF ." claim failed!" cr 2drop THEN drop
\ claim region used by firmware (assume 31 MiB size right now)
paflof-start ffff not and 1f00000 0 ' claim CATCH IF
." claim failed!" cr 2drop
THEN drop
|