Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | \ ========== Copyright Header Begin ========================================== |
2 | \ | |
3 | \ Hypervisor Software File: allocvir.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: @(#)allocvir.fth 2.38 03/07/17 | |
43 | purpose: | |
44 | copyright: Copyright 1990-2003 Sun Microsystems, Inc. All Rights Reserved | |
45 | copyright: Use is subject to license terms. | |
46 | ||
47 | \ Virtual memory allocator for mapping in devices. | |
48 | ||
49 | \ allocate-virtual ( size -- phys space adr ) | |
50 | \ Allocates at least "size" bytes of virtual memory. The actual | |
51 | \ allocation size is "size" rounded up to a multiple of the page size. | |
52 | \ | |
53 | ||
54 | \ The firmware is allowed to allocate from 2 ranges of virtual memory, by | |
55 | \ (partially historical) agreement with the OS kernel. | |
56 | \ The first, and preferred, range is the 2 MByte range from 0xffd0.0000 | |
57 | \ to 0xffef.ffff. This range contains the mappings for the firmware itself, | |
58 | \ and the firmware's stacks, RAM space, and device mappings, leaving a little | |
59 | \ more than a megabyte for mapping plug-in devices. | |
60 | \ | |
61 | \ For larger framebuffers, 1 MByte is not enough, so the firmware is also | |
62 | \ allowed to allocate from the virtual region below 0xff00.0000. Unix | |
63 | \ calls this address "Sysbase". There is over 100 MBytes of otherwise | |
64 | \ unused virtual space between the end of the kernel text+data+bss+buffers | |
65 | \ at approximately 0xf820.0000 and Sysbase. | |
66 | \ | |
67 | \ One possible problem with this region below 0xff00.0000 is that it is | |
68 | \ inaccessable to DVMA from some devices, particularly the AMD Ethernet | |
69 | \ interface on the 4/60 and derived products. That interface has a 24-bit | |
70 | \ DMA interface, with bits A31:A24 hardwired to 0xff, so DVMA addresses | |
71 | \ for that device must be at or above 0xff00.0000. | |
72 | \ | |
73 | \ One solution is to use the "below 0xff00.0000" region for very large | |
74 | \ devices, say 1MByte or greater, thus leaving enough space for everything | |
75 | \ else in the high region above 0xffd0.0000. | |
76 | \ | |
77 | \ For now, we use a "first-fit" policy and hope. | |
78 | ||
79 | \ If the PMEG containing "splice-adr" is completely contained within the | |
80 | \ indicated node, free that PMEG. This code assumes that "splice-adr" itself | |
81 | \ is contained within the node. If "splice-adr" is a segment boundary, | |
82 | \ then we don't need to free the PMEG, because it will have already been | |
83 | \ taken care of at a higher level. | |
84 | ||
85 | defer check-range ' noop is check-range | |
86 | ||
87 | root-device | |
88 | new-device | |
89 | ||
90 | " virtual-memory" device-name | |
91 | ||
92 | headers | |
93 | list: fwvirt \ Virtual memory available list | |
94 | list: osvirt \ Virtual memory that the OS can use but the firmware can't | |
95 | ||
96 | headerless | |
97 | ||
98 | : ?free-segment ( splice-adr node -- ) | |
99 | >r ( splice-adr ) | |
100 | dup segmentsize round-down ( splice-adr seg-adr ) | |
101 | \ Exit if the splice is exactly on a segment boundary | |
102 | tuck = if drop r> drop exit then ( sdg-adr ) | |
103 | segmentsize ( seg-adr seg-size ) | |
104 | r> contained? if ( seg-adr seg-size ) | |
105 | drop deallocate-segment | |
106 | else ( seg-adr seg-size ) | |
107 | 2drop | |
108 | then ( ) | |
109 | ; | |
110 | ||
111 | \ Frees the virtual address range "adr len" | |
112 | ||
113 | : noreclaim-free-virtual ( adr len -- ) | |
114 | >page-boundaries | |
115 | over monvirtbase dup monvirtsize + within if ( adr len ) | |
116 | fwvirt | |
117 | else ( adr len ) | |
118 | over low-base dup low-size + within if ( adr len ) | |
119 | fwvirt | |
120 | else ( adr len ) | |
121 | osvirt | |
122 | then | |
123 | then ( adr len memorylist ) | |
124 | free-memrange | |
125 | ; | |
126 | \ Finds the starting address and size of any segments completely contained | |
127 | \ within the range adr,len | |
128 | ||
129 | : enclosed-segments ( adr len -- seg-start seg-len ) | |
130 | bounds >r ( end-adr ) ( r: start-adr ) | |
131 | segmentsize round-down ( seg-end ) ( r: start-adr ) | |
132 | dup r@ u< if ( seg-end ) ( r: start-adr ) | |
133 | drop r> 0 exit ( start-adr 0 ) ( r: start-adr ) | |
134 | then ( seg-end ) ( r: start-adr ) | |
135 | r> segmentsize round-up ( seg-end seg-start ) | |
136 | over umin ( seg-end seg-start' ) | |
137 | tuck - ( seg-start seg-len ) | |
138 | ; | |
139 | ||
140 | ||
141 | : reclaim-segments ( adr len -- ) | |
142 | >page-boundaries | |
143 | enclosed-segments ( seg-adr seg-len ) | |
144 | bounds ?do ( ) | |
145 | i deallocate-segment ( ) | |
146 | segmentsize +loop ( ) | |
147 | ; | |
148 | ||
149 | headers | |
150 | \ Frees virtual memory and PMEGs, but not the physical memory behind it | |
151 | : free-virtual-only ( adr len -- ) | |
152 | >page-boundaries | |
153 | 2dup reclaim-segments | |
154 | ['] ?free-segment is ?splice ( adr' len' ) | |
155 | noreclaim-free-virtual | |
156 | ; | |
157 | ||
158 | headerless | |
159 | : segment-boundaries ( adr len -- end-adr seg-end seg-start start-adr ) | |
160 | 2dup bounds 2swap ( end-adr start-adr adr len ) | |
161 | enclosed-segments ( end-adr start-adr seg-start seg-len ) | |
162 | bounds rot | |
163 | ; | |
164 | ||
165 | \ Allocates "segment-level" mapping resources for the indicated address range | |
166 | ||
167 | : ?allocate-segments ( adr size -- ) | |
168 | segment-boundaries ( end-adr seg-end seg-start start-adr ) | |
169 | ?allocate-segment ( end-adr seg-end seg-start ) | |
170 | over swap ?do ( end-adr seg-end ) | |
171 | i ?allocate-segment ( end-adr seg-end ) | |
172 | segmentsize +loop ( end-adr seg-end ) | |
173 | tuck - if ?allocate-segment else drop then ( ) | |
174 | ; | |
175 | ||
176 | \ Allocates at least "size" bytes of virtual memory | |
177 | headers | |
178 | : allocate-aligned-virtual ( alignment size -- virt-adr ) | |
179 | \ Minumum granularity of memory chunks is 1 page | |
180 | swap mmu-pagesize round-up | |
181 | swap mmu-pagesize round-up ( alignment+ size+ ) | |
182 | tuck fwvirt ( size alignment size list ) | |
183 | allocate-memrange ( size [ adr ] error? ) | |
184 | abort" Insufficient virtual memory" ( size adr ) | |
185 | tuck swap ?allocate-segments ( adr ) | |
186 | ; | |
187 | ||
188 | : allocate-virtual ( size -- virt ) | |
189 | 1 swap allocate-aligned-virtual | |
190 | ; | |
191 | headerless | |
192 | : claim-virtual ( adr size -- adr ) | |
193 | over >r >page-boundaries ( adr,len' ) | |
194 | \ Look first in the monitor's piece list | |
195 | fwvirt ['] contained? find-node ( adr,len' prev next|0 ) | |
196 | dup 0= if | |
197 | \ If not found in the monitor's virtual list, look in | |
198 | \ the OS's virtual list. | |
199 | 2drop | |
200 | osvirt ['] contained? find-node ( adr,len' prev next|0 ) | |
201 | then | |
202 | is next-node is prev-node ( adr,len' ) | |
203 | ||
204 | next-node 0= abort" Virtual address already used" ( adr,len' ) | |
205 | ||
206 | \ There are 4 cases to consider in removing the requested virtual | |
207 | \ address range from the list: | |
208 | \ (1) The requested range exactly matches the list node range | |
209 | \ (2) The requested range is at the beginning of the list node range | |
210 | \ (3) The requested range is at the end of the list node range | |
211 | \ (4) The requested range is in the middle of the list node range | |
212 | ||
213 | \ Remember the range of the node to be deleted | |
214 | next-node node-range ( adr,len' node-a,l ) | |
215 | ||
216 | \ Remove the node from the list | |
217 | prev-node delete-after memrange free-node ( adr,len' node-a,l ) | |
218 | ||
219 | \ Give back any left-over portion at the beginning | |
220 | over 4 pick over - ( adr,len' node-a,l begin-a,l ) | |
221 | dup if noreclaim-free-virtual else 2drop then ( adr,len' node-a,l ) | |
222 | ||
223 | \ Give back any left-over portion at the end | |
224 | 2over + -rot + over - ( adr,len' end-a,l ) | |
225 | dup if noreclaim-free-virtual else 2drop then ( adr,len' ) | |
226 | ||
227 | ?allocate-segments ( ) | |
228 | r> ( adr ) | |
229 | ; | |
230 | ||
231 | : add-os-piece ( start-adr end-adr -- ) | |
232 | over - set-node osvirt insert-after | |
233 | ; | |
234 | ||
235 | headers | |
236 | [ifdef] notdef | |
237 | \ The open method of /virtual-memory is highly system dependent. | |
238 | \ Below is an example open method which may not work for | |
239 | \ every system. The corret version of this method should | |
240 | \ be defined in the system dependent MMU driver which presumably | |
241 | \ knows about the limitations and futures of the MMU hardware. | |
242 | : open ( -- ok? ) | |
243 | 0 memrange ! \ Clear free list | |
244 | d# 20 memrange more-nodes \ Get enough nodes "forever" | |
245 | ||
246 | \ Create the available memory list from which the firmware is allowed | |
247 | \ to dynamically allocate virtual memory. | |
248 | ||
249 | low-base low-size set-node fwvirt insert-after | |
250 | monvirtbase monvirtsize set-node fwvirt insert-after | |
251 | ||
252 | ROMbase dictionary-top over - claim-virtual drop | |
253 | RAMbase RAMsize claim-virtual drop | |
254 | ||
255 | \ Create the available memory list from which the firmware is not allowed | |
256 | \ to dynamically allocate virtual memory. | |
257 | ||
258 | hole-end hole-start <> if | |
259 | 0 hole-start add-os-piece | |
260 | hole-end low-base add-os-piece | |
261 | else | |
262 | 0 low-base add-os-piece | |
263 | then | |
264 | low-base low-size + monvirtbase add-os-piece | |
265 | monvirtbase monvirtsize + 0 add-os-piece | |
266 | ||
267 | true | |
268 | ; | |
269 | [then] \ notdef | |
270 | ||
271 | : close ( -- ) ; | |
272 | ||
273 | : claim ( [ virt ] size align -- base ) | |
274 | ?dup if ( size align ) | |
275 | \ Alignment should be next power of two | |
276 | swap allocate-aligned-virtual ( base ) | |
277 | else ( virt size ) | |
278 | claim-virtual ( base ) | |
279 | then ( base ) | |
280 | ; | |
281 | : release ( virt size -- ) free-virtual-only ; | |
282 | ||
283 | : modify ( virt size mode -- ) | |
284 | -rot >page-boundaries bounds ?do ( mode ) | |
285 | dup i pgmap@ mode>tte i pgmap! ( mode ) | |
286 | mmu-pagesize +loop drop ( ) | |
287 | ; | |
288 | ||
289 | : map ( phys-lo phys-hi virt size mode -- ) | |
290 | >r 2dup 2>r map-pages ( ) ( r: mode virt size ) | |
291 | 2r> r> modify ( ) | |
292 | ; | |
293 | ||
294 | alias unmap unmap-pages ( virt size -- ) | |
295 | ||
296 | : translate ( virt -- false | phys-lo phys-hi mode true ) | |
297 | dup >physical 2dup -1 -1 d= if ( virt -1 -1 ) | |
298 | 3drop false | |
299 | else ( virt phys-lo phys-hi ) | |
300 | rot pgmap@ tte>mode true ( phys-lo phys-hi mode true ) | |
301 | then | |
302 | ; | |
303 | pagesize constant pagesize | |
304 | pagesize " page-size" integer-property | |
305 | ||
306 | finish-device | |
307 | device-end | |
308 | ||
309 | stand-init: Opening the virtual memory package | |
310 | " /virtual-memory" open-dev mmu-node ! | |
311 | ; |