Commit | Line | Data |
---|---|---|
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 ============================================ | |
42 | id: @(#)memlist.fth 2.9 05/04/08 | |
43 | purpose: | |
44 | copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved | |
45 | copyright: Use is subject to license terms. | |
46 | ||
47 | \ Common routines for memory list manipulation | |
48 | ||
49 | listnode | |
50 | /n field >adr | |
51 | /n field >size | |
52 | nodetype: memrange | |
53 | ||
54 | \ local variable for use by memory list code | |
55 | headerless | |
56 | ||
57 | 0 value prev-node \ The node preceding (above) the insertion point | |
58 | 0 value next-node \ The node following (below) the insertion point | |
59 | 0 value memlist \ The memory list we're working on | |
60 | ||
61 | defer ?splice ( adr node -- ) \ Routine to free spanning resources | |
62 | ||
63 | headers | |
64 | : node-range ( node -- adr size ) dup >adr @ swap >size @ ; | |
65 | ||
66 | headerless | |
67 | \ Convenience functions | |
68 | ||
69 | : prev-start ( -- adr ) prev-node >adr @ ; | |
70 | : next-end ( -- adr ) next-node node-range + ; | |
71 | ||
72 | defer 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 | ||
136 | headers | |
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. | |
154 | headers | |
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 | ||
252 | headers |