Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / obp / obp / os / bootprom / memlist.fth
CommitLineData
920dae64
AT
1\ ========== Copyright Header Begin ==========================================
2\
3\ Hypervisor Software File: memlist.fth
4\
5\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6\
7\ - Do no alter or remove copyright notices
8\
9\ - Redistribution and use of this software in source and binary forms, with
10\ or without modification, are permitted provided that the following
11\ conditions are met:
12\
13\ - Redistribution of source code must retain the above copyright notice,
14\ this list of conditions and the following disclaimer.
15\
16\ - Redistribution in binary form must reproduce the above copyright notice,
17\ this list of conditions and the following disclaimer in the
18\ documentation and/or other materials provided with the distribution.
19\
20\ Neither the name of Sun Microsystems, Inc. or the names of contributors
21\ may be used to endorse or promote products derived from this software
22\ without specific prior written permission.
23\
24\ This software is provided "AS IS," without a warranty of any kind.
25\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
26\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
27\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
28\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
29\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
30\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
31\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
32\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
33\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
34\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
35\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
36\
37\ You acknowledge that this software is not designed, licensed or
38\ intended for use in the design, construction, operation or maintenance of
39\ any nuclear facility.
40\
41\ ========== Copyright Header End ============================================
42id: @(#)memlist.fth 2.9 05/04/08
43purpose:
44copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved
45copyright: Use is subject to license terms.
46
47\ Common routines for memory list manipulation
48
49listnode
50 /n field >adr
51 /n field >size
52nodetype: memrange
53
54\ local variable for use by memory list code
55headerless
56
570 value prev-node \ The node preceding (above) the insertion point
580 value next-node \ The node following (below) the insertion point
590 value memlist \ The memory list we're working on
60
61defer ?splice ( adr node -- ) \ Routine to free spanning resources
62
63headers
64: node-range ( node -- adr size ) dup >adr @ swap >size @ ;
65
66headerless
67\ Convenience functions
68
69: prev-start ( -- adr ) prev-node >adr @ ;
70: next-end ( -- adr ) next-node node-range + ;
71
72defer memrange-hook
73
74\ alloc 20 more nodes before dropping below 4 free nodes.
75\ clear defer before allocating more nodes to prevent reentry
76\ in case more-nodes needs to modify memlist to allocate more heap
77: (memrange-hook ( -- ) recursive
78 0 memrange
79 begin ( #free node )
80 @ dup if ( #free node )
81 swap 1+ swap ( #free node )
82 then ( #free node )
83 over d# 4 >= ( #free node flag )
84 over 0= or ( #free node flag )
85 until ( #free node )
86 drop d# 4 < if ( )
87 ['] noop is memrange-hook
88 d# 20 memrange more-nodes
89 ['] (memrange-hook is memrange-hook
90 then
91;
92
93' (memrange-hook is memrange-hook
94
95\ Used with "find-node" to locate the pair of nodes around "adr"
96
97: lower? ( adr node -- adr flag ) >adr @ over u<= ;
98
99\ Used with "find-node" to locate a memory node at least as big as "size"
100
101: big-enough? ( size node-adr -- size flag ) >size @ over u>= ;
102
103\ Handle possible singularity at 0
104: handle-0 ( end-adr start-adr -- end-adr' start-adr' )
105 2dup = if exit then \ Don't do it for 0-length ranges
106 over 0= if nip -1 swap then
107;
108
109\ Used with "find-node" to locate a memory node containing the range adr,len
110
111: contained? ( adr len node-adr -- adr len flag )
112 node-range bounds handle-0 ( adr len node-end node-start )
113 2over bounds handle-0 ( adr len node-end,start end,start )
114 rot u>= -rot u>= and ( adr len flag )
115;
116
117: collapse-nodes ( next prev -- )
118 over >size @ over >size +! ( next prev )
119 swap >adr @ swap >adr ! ( )
120;
121
122: suitable? ( alignment size node-adr -- alignment size flag )
123 >r r@ >adr @ 2 pick round-up ( alignment size aligned-adr )
124 r> node-range -rot - ( alignment size node-size waste )
125 2dup u<= if 2drop false exit then ( alignment size node-size waste )
126 - ( alignment size aln-node-size )
127 over u>= ( alignment size flag )
128;
129
130: mem-node! ( adr size node -- )
131 tuck >size ! >adr ! ( )
132;
133
134\ Allocates and initializes a new memory node
135
136headers
137: set-node ( adr size -- node )
138 memrange allocate-node ( adr sz node )
139 dup >r mem-node! r> memrange-hook ( node )
140;
141
142: end-piece-aligned? ( aln size -- flag )
143 next-end ( aln size end-adr )
144 swap - dup rot ( adr adr aln )
145 round-up = ( flag )
146;
147
148\ Frees the range of memory "adr size", adding it to the free list "list".
149\ Every attempt is made to add the memory range to an existing node, and
150\ to join adjacent nodes into one larger node. When memory is added to an
151\ existing node, or when nodes are joined, the defer word "?splice" is
152\ called with the join address as an argument, allowing for spanning
153\ resources (e.g. PMEGS) to be freed if possible.
154headers
155: free-memrange ( adr size list -- )
156 is memlist ( adr size )
157
158 swap memlist ['] lower? find-node ( size adr prev-node this-node|0 )
159 is next-node is prev-node ( size adr )
160
161 \ Error check to catch attempts to free already-free memory.
162
163 next-node if ( size adr )
164 dup next-node >adr @ next-end within
165 abort" Freeing memory that is already free"
166 then ( size adr )
167
168 \ Try to add this node to the end of the lower piece in the available list
169
170 next-node if ( size adr )
171 dup next-end = if ( size adr )
172
173 \ This piece can be added to the end of the lower piece
174
175 swap next-node >size +! ( adr )
176 next-node ?splice ( ) \ Perhaps free PMEG
177
178 \ Now try to collapse 2 adjacent nodes
179 prev-node memlist <> if ( )
180 next-end prev-start = if ( )
181 next-end ( splice-adr )
182 next-node prev-node collapse-nodes ( splice-adr )
183 prev-node delete-after memrange free-node ( splice-adr )
184 prev-node ?splice ( ) \ Perhaps free PMEG
185 then
186 then
187
188 exit
189 then
190 then
191
192 \ Try to add this node to the start of the upper piece in the available list
193 prev-node memlist <> if ( size adr )
194 2dup + prev-start = if ( size adr )
195 2dup prev-node >adr ! ( size adr size )
196 prev-node >size +! ( size adr )
197 + prev-node ?splice ( ) \ Perhaps free PMEG
198 exit
199 then
200 then ( size adr )
201
202 \ Oh bother! We have to create another node
203 \ leave the current prev-node on stack in case it changes while
204 \ allocating more nodes in set-node
205 swap prev-node -rot set-node swap insert-after
206;
207
208: allocate-memrange ( alignment size list -- phys-adr false | true )
209 ['] suitable? find-node is next-node is prev-node ( aln+ size+ )
210
211 next-node 0= if 2drop true exit then ( aln+ size+ )
212
213 2dup end-piece-aligned? if ( aln+ size+ )
214 dup next-node >size @ = if ( aln+ size+ )
215 \ Node is exactly the right size; return the
216 \ address and remove the node from the list
217 next-node >adr @ ( aln+ size+ adr )
218 prev-node delete-after memrange free-node ( aln+ size+ adr )
219 else ( aln+ size+ )
220 \ Node is bigger than requested size. Decrease the size of the
221 \ node's region and return the last part of its address range.
222 dup negate next-node >size +! ( aln+ size+ )
223 next-end ( aln+ size+ adr )
224 then
225 else \ The piece was not already aligned ( aln+ size+ )
226
227 \ Change the size of the current node to reflect only the
228 \ fragment after the allocated piece.
229
230 next-end over - 2 pick round-down ( aln+ size+ adr )
231 2dup + dup next-end swap - ( aln+ size+ adr frag-adr frag-len )
232 next-node >adr @ >r \ Save for later
233 next-node mem-node!
234
235 r> 2dup - ( aln+ size+ adr frag-adr frag-len )
236 dup if ( aln+ size+ adr frag-adr frag-len )
237 \ Create a new node for the fragment before the allocated range.
238 \ We don't have to worry about splicing it to adjacent nodes,
239 \ because we know that it came from the beginning of an existing
240 \ separate node.
241 \ leave the current next-node on stack in case it changes while
242 \ allocating more nodes in set-node
243 next-node -rot set-node swap insert-after ( aln+ size+ adr )
244 else ( aln+ size+ adr frag-adr frag-len )
245 \ There is no fragment before the allocated range.
246 2drop ( aln+ size+ adr )
247 then ( aln+ size+ adr )
248 then ( aln+ size+ adr )
249 nip nip false ( adr false )
250;
251
252headers