Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | \ ========== Copyright Header Begin ========================================== |
2 | \ | |
3 | \ Hypervisor Software File: mmu.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: @(#)mmu.fth 1.32 05/02/16 | |
43 | purpose: | |
44 | copyright: Copyright 2005 Sun Microsystems, Inc. All Rights Reserved | |
45 | copyright: Use is subject to license terms. | |
46 | ||
47 | \ We define this now, until mixed-page support is ready | |
48 | [define] MMU-8K-ONLY? | |
49 | ||
50 | \ Public Interfaces: | |
51 | \ pgmap@ ( va -- tte|0 ) | |
52 | \ pgmap! ( tte virt -- ) | |
53 | \ set-tte-soft ( tte virt -- tte' ) | |
54 | \ vpt-walker ( acf -- ) | |
55 | \ map-page ( pa.lo pa.hi va -- ) | |
56 | \ unmap-page ( virt -- ) | |
57 | \ map-pages ( pa.lo pa.hi virtual size -- ) | |
58 | \ unmap-pages ( va len -- ) | |
59 | \ >mmu-boundaries ( va len size -- va' len' ) | |
60 | \ >page-boundaries ( va len -- va' len' ) | |
61 | ||
62 | headerless | |
63 | ||
64 | #vabits d# 64 = if -1 else 1 #vabits lshift 1- then constant va-mask | |
65 | ||
66 | pageshift tteshift - constant vptshift | |
67 | 0 1 #vabits pageshift - tteshift + lshift - constant vpt-base | |
68 | 0 vpt-base - constant vpt-size | |
69 | ||
70 | \ For example, in a 44 bit va space, the vpt-base is at ffff.fffc.0000.0000 | |
71 | \ The vpt address of a tte mapping any va is found by: | |
72 | \ apply va-mask to the va | |
73 | \ shift page bits off va (all adrs in same page correspond to same tte) | |
74 | \ shift tte bits back on va (each tte is 8 bytes in vpt) | |
75 | \ add result to vpt-base | |
76 | \ | |
77 | \ The above method is used to get the tte for both non-vpt and vpt addresses. | |
78 | \ The lower pages of the vpt itself are mapped by tte's higher in the vpt. | |
79 | \ The next level of pages in the vpt holding tte's for the first level are | |
80 | \ themselves mapped by tte's in the vpt-root page at ffff.ffff.ffff.c000. | |
81 | \ The vpt-root page is not mapped by a vpt entry, it is locked in the dtlb. | |
82 | ||
83 | \ These two defers are executed during the performance-critical path | |
84 | \ of mapping, but are not re-vectored at run-time. They appear to | |
85 | \ be being defined here as DEFERs either to workaround the lack of | |
86 | \ forward-definitions, or because their resolutions differ by platform. | |
87 | \ Arguably, they should be PATCHed-over where they're resolved... | |
88 | ||
89 | defer allocate-page ( -- pa.lo pa.hi ) | |
90 | defer set-tte-soft ( tte virt -- tte' ) ' drop is set-tte-soft | |
91 | ||
92 | \ This is a code saving measure, it does not obey any of the standard | |
93 | \ ABI conventions as it trashes the locals!! Do not call this routine | |
94 | \ from outside this file. | |
95 | \ On entry: | |
96 | \ tos is holding the VA | |
97 | \ On exit: | |
98 | \ scr = pgmap | |
99 | \ sc1 = segment | |
100 | \ sc2 = region | |
101 | \ sc5 = region-tte | |
102 | label pgmap-common | |
103 | va-mask sc1 sc2 setx | |
104 | tos sc2 scr and \ VA & va-mask | |
105 | ||
106 | scr pageshift scr srlx \ VA -> vpt offset | |
107 | vpt-base sc1 sc3 setx | |
108 | scr tteshift scr sllx | |
109 | scr sc3 scr add \ pgmap | |
110 | ||
111 | scr sc2 sc1 and | |
112 | sc1 pageshift sc1 srlx | |
113 | sc1 tteshift sc1 sllx | |
114 | sc1 sc3 sc1 add \ vpt-segment | |
115 | ||
116 | sc1 sc2 sc5 and | |
117 | sc5 pageshift sc2 srlx | |
118 | sc2 tteshift sc2 sllx | |
119 | sc2 sc3 sc2 add \ vpt-region | |
120 | ||
121 | retl | |
122 | sc2 %g0 sc5 ldx | |
123 | end-code | |
124 | ||
125 | headers | |
126 | ||
127 | \ this routine returns 0 for an invalid VA. | |
128 | \ the VPT is scanned from region->segment->pgmap before the | |
129 | \ access is done. | |
130 | code pgmap@ ( va -- tte|0 ) | |
131 | pgmap-common call | |
132 | nop \ (delay) | |
133 | \ Validate the region | |
134 | sc5 %g0 %g0 subcc | |
135 | 0< if \ region valid? | |
136 | %g0 %g0 tos add \ (delay) Invalid | |
137 | ||
138 | \ Validate the segment | |
139 | sc1 %g0 sc5 ldx | |
140 | sc5 %g0 %g0 subcc | |
141 | 0< if \ segment valid? | |
142 | %g0 %g0 tos add \ (delay) Invalid | |
143 | scr %g0 tos ldx \ get tte | |
144 | then | |
145 | then | |
146 | c; | |
147 | ||
148 | headerless | |
149 | ||
150 | \ get vpt address of tte for va | |
151 | code >vpt ( va -- adr ) | |
152 | va-mask sc1 scr setx | |
153 | tos scr tos and | |
154 | tos pageshift tos srlx | |
155 | vpt-base sc1 scr setx | |
156 | tos tteshift tos sllx | |
157 | tos scr tos add | |
158 | c; | |
159 | ||
160 | \ this routine is the primitive pagemap stuffer. | |
161 | \ If it returns 0 then this segment and region are fine. | |
162 | \ if the region needs creation then the tte,va,3 and true are returned. | |
163 | \ if the segment needs updating then tte,va,2,true are returned | |
164 | \ returning non-zero means it required high level assistance. | |
165 | code ((pgmap!)) ( tte va -- 0|tte,va,2,-1|tte,va,3,-1 ) | |
166 | pgmap-common call | |
167 | nop \ (delay) | |
168 | ||
169 | \ Validate the region | |
170 | sc5 %g0 %g0 subcc | |
171 | 0>= if \ region valid? | |
172 | %g0 3 sc4 add \ (delay) map-region required. | |
173 | tos sp push | |
174 | sc4 sp push | |
175 | else | |
176 | %g0 1 tos sub \ (delay) map needs assistance | |
177 | ||
178 | \ Validate the segment | |
179 | sc1 %g0 sc5 ldx | |
180 | sc5 %g0 %g0 subcc | |
181 | 0>= if \ segment valid? | |
182 | %g0 2 sc4 add \ (delay) map-segment required. | |
183 | tos sp push | |
184 | sc4 sp push | |
185 | else | |
186 | %g0 1 tos sub \ (delay) map needs assistance | |
187 | ||
188 | \ Pop the tte and stuff the entry | |
189 | sp sc4 pop | |
190 | %g0 %g0 tos add \ All done. | |
191 | sc4 scr %g0 stx \ store the tte. | |
192 | then | |
193 | then | |
194 | c; | |
195 | ||
196 | : (pgmap!) ( tte va -- ) | |
197 | recursive ( tte va ) | |
198 | ((pgmap!)) if ( tte va index ) | |
199 | over swap ( tte va va index ) | |
200 | 0 ?do >vpt loop ( tte va va' ) | |
201 | allocate-page ( tte va va' pa.lo pa.hi ) | |
202 | >tte >tte-soft ( tte va va' tte' ) | |
203 | swap x! ( tte va ) | |
204 | (pgmap!) ( ) | |
205 | then | |
206 | ; | |
207 | ||
208 | \ From this point onwards we are presenting the higher level MMU routines. | |
209 | \ No-one should be calling routines defined before this point - except | |
210 | \ pgmap@, and >vpt | |
211 | ||
212 | headers | |
213 | ||
214 | : .vpt ( vpt -- ) | |
215 | <# | |
216 | u# u# u# u# ascii . hold | |
217 | u# u# u# u# ascii . hold | |
218 | u# u# u# u# ascii . hold | |
219 | u# u# u# u# | |
220 | u#> type | |
221 | ; | |
222 | ||
223 | \ root vpt page which is locked in tlb never misses | |
224 | 0 >vpt >vpt >vpt constant vpt-root | |
225 | ||
226 | : .vpts ( va -- ) | |
227 | pagesize round-down | |
228 | >vpt dup .vpt cr | |
229 | >vpt dup .vpt cr | |
230 | >vpt .vpt cr | |
231 | ; | |
232 | ||
233 | headerless | |
234 | ||
235 | \ NOTE: | |
236 | \ The final 2drop is patched at RUNTIME by enable-map-flushing | |
237 | \ this code is in a performance path which is why it is not | |
238 | \ using a variable/value/defer to switch this feature on/off. | |
239 | : (common-mapper) ( va tte len -- ) | |
240 | >r swap ( tte va ) | |
241 | r@ 0 ?do 2dup i + (pgmap!) pagesize +loop ( tte va ) | |
242 | nip r> ( va len ) | |
243 | \ patched to flush-tlb-range | |
244 | 2drop | |
245 | ; | |
246 | ||
247 | headers | |
248 | ||
249 | \ The virtual memory node calls into this routine to 'modify' entries.. | |
250 | : pgmap! ( tte virt -- ) | |
251 | tuck ( va tte va ) | |
252 | set-tte-soft ( va tte' ) | |
253 | pagesize (common-mapper) ( ) | |
254 | ; | |
255 | ||
256 | headerless | |
257 | ||
258 | \ round pa.lo and va down | |
259 | code >tte-boundaries ( pa.lo pa.hi va round -- va pa.lo pa.hi ) | |
260 | tos 1 scr sub | |
261 | sp tos pop \ VA | |
262 | tos scr tos andn \ VA' | |
263 | sp sc1 pop | |
264 | sp sc2 pop | |
265 | sc2 scr sc2 andn \ pa.lo' | |
266 | tos sp push | |
267 | sc2 sp push | |
268 | sc1 tos move | |
269 | c; | |
270 | ||
271 | \ round the region to enclose the appropriate page restrictions. | |
272 | code >mmu-boundaries ( va len size -- va' len' ) | |
273 | sp scr pop \ len | |
274 | sp sc1 pop \ va | |
275 | tos 1 tos sub \ mask | |
276 | sc1 tos sc2 andn \ round-down | |
277 | sc2 sp push | |
278 | scr sc1 scr add \ top VA | |
279 | scr tos scr add \ add size-1 | |
280 | scr tos scr andn \ round-down | |
281 | scr sc2 tos sub | |
282 | c; | |
283 | ||
284 | : >page-boundaries ( va len -- va' len' ) pagesize >mmu-boundaries ; | |
285 | ||
286 | headers | |
287 | ||
288 | : map-page ( pa.lo pa.hi va -- ) | |
289 | pagesize >tte-boundaries ( va' pa.lo' pa.hi ) | |
290 | >tte swap pgmap! ( ) | |
291 | ; | |
292 | ||
293 | headerless | |
294 | ||
295 | \ this assumes you have correctly aligned all the args!! | |
296 | : (map-pages) ( pa.lo pa.hi va len -- ) | |
297 | >r pagesize >tte-boundaries ( va pa.lo pa.hi ) | |
298 | rot r> ( pa.lo pa.hi va len ) | |
299 | bounds ?do ( pa.lo pa.hi ) | |
300 | 2dup i -rot ( pa.lo pa.hi va pa.lo pa.hi ) | |
301 | >tte ( pa.lo pa.hi va tte ) | |
302 | over set-tte-soft ( pa.lo pa.hi va tte' ) | |
303 | swap (pgmap!) ( pa.lo pa.hi ) | |
304 | swap pagesize + swap ( pa.lo' pa.hi ) | |
305 | pagesize +loop ( pa.lo' pa.hi ) | |
306 | 2drop ( ) | |
307 | ; | |
308 | ||
309 | headers | |
310 | ||
311 | : unmap-page ( virt -- ) | |
312 | dup pgmap@ 0 >tte-valid invert and over pgmap! ( virt ) | |
313 | flush-cache-page ( ) | |
314 | ; | |
315 | ||
316 | headerless | |
317 | ||
318 | depend-load MMU-8K-ONLY? ${BP}/cpu/sparc/ultra/mmu-policy/8k-pages.fth | |
319 | ||
320 | headerless | |
321 | ||
322 | \ Call this once OBPs internal mappings are complete, this will then | |
323 | \ enable the tlb flushing code for mapping. | |
324 | \ We use patch because this code is all in the performance path. | |
325 | : enable-map-flushing ( -- ) | |
326 | ['] flush-tlb-range ['] 2drop ( acf1 acf2 ) | |
327 | 2dup ( acf1 acf2 acf1 acf2 ) | |
328 | ['] (common-mapper) (patch ( acf1 acf2 ) | |
329 | ['] map-pages (patch ( ) | |
330 | ; | |
331 | ||
332 | transient | |
333 | alias deallocate-segment drop ( vadr -- ) | |
334 | alias ?allocate-segment drop ( vadr -- ) | |
335 | resident | |
336 | ||
337 | headerless | |
338 | : (.map) ( vadr tte -- ) | |
339 | dup tte>size ( vadr tte size ) | |
340 | rot dup ." VA:" .x cr ( tte size vadr ) | |
341 | swap 1- and ( tte offset ) | |
342 | over .tlb cr ( tte offset ) | |
343 | over tte> drop or ( tte padr ) | |
344 | swap valid-tte? if ( padr ) | |
345 | ." PA:" .x ( ) | |
346 | else ( padr ) | |
347 | ." Invalid" drop ( ) | |
348 | then ( ) | |
349 | ; | |
350 | ||
351 | \ We set this to change the default translation behaviour so we can | |
352 | \ reuse the same vpt-walker for .trans and the translation property. | |
353 | \ This defer is set by any map activity; it is critical to performance. | |
354 | \ Speeding up the application of IS to a kernel native defer shows up | |
355 | \ here as a significant performance win. | |
356 | defer vpt-data-fn ( ?? va len tte -- ?? ) ' 3drop is vpt-data-fn | |
357 | ||
358 | struct | |
359 | /x field >vpt-va | |
360 | /x field >vpt-size | |
361 | /x field >vpt-tte | |
362 | constant /prev-vpt-data | |
363 | ||
364 | /prev-vpt-data ualloc user prev-vpt-data | |
365 | ||
366 | : vpt-data@ ( -- a b c ) | |
367 | prev-vpt-data >r | |
368 | r@ >vpt-va x@ | |
369 | r@ >vpt-size x@ | |
370 | r> >vpt-tte x@ | |
371 | ; | |
372 | : vpt-data! ( a b c -- ) | |
373 | prev-vpt-data >r | |
374 | r@ >vpt-tte x! | |
375 | r@ >vpt-size x! | |
376 | r> >vpt-va x! | |
377 | ; | |
378 | ||
379 | : prev-tte-invalid ( -- ) 0 prev-vpt-data >vpt-tte x! ; | |
380 | : prev-tte-valid? ( -- flag ) prev-vpt-data >vpt-tte x@ valid-tte? ; | |
381 | ||
382 | : (vpt-pgmap) ( va -- ) | |
383 | pagesize bounds do ( ) | |
384 | i x@ valid-tte? if ( ) | |
385 | i vpt-base - ( offset ) | |
386 | vptshift lshift ( va ) | |
387 | i x@ dup tte>size swap ( va size tte ) | |
388 | 2 pick 2 pick 1- and if ( va size tte ) | |
389 | \ tte-size overlaps va so we merge | |
390 | 3drop ( ) | |
391 | else ( va size tte ) | |
392 | prev-tte-valid? if ( va size tte ) | |
393 | prev-vpt-data >r ( va size tte ) | |
394 | 2 pick r@ >vpt-va x@ - ( va size tte n ) | |
395 | over tte> drop ( va size tte n pa.lo ) | |
396 | r@ >vpt-tte x@ tte> drop - ( va size tte n n ) | |
397 | = if ( va size tte ) | |
398 | \ merge sizes, because va and pa are contiguous. | |
399 | drop nip ( size ) | |
400 | r> >vpt-size +! ( ) | |
401 | else ( va size tte ) | |
402 | 2>r >r ( ) | |
403 | vpt-data@ vpt-data-fn ( va size tte ) | |
404 | r> 2r> vpt-data! ( ) | |
405 | r> drop ( ) | |
406 | then ( ) | |
407 | else ( va size tte ) | |
408 | \ save this va,tte for merging | |
409 | vpt-data! ( ) | |
410 | then ( ) | |
411 | then ( ) | |
412 | else ( ) | |
413 | prev-tte-valid? if ( ) | |
414 | vpt-data@ vpt-data-fn ( ) | |
415 | then ( ) | |
416 | prev-tte-invalid ( ) | |
417 | then ( ) | |
418 | /x +loop ( ) | |
419 | ; | |
420 | ||
421 | : (vpt-segment) ( va -- ) | |
422 | pagesize bounds do ( ) | |
423 | i x@ valid-tte? if ( ) | |
424 | i vptshift lshift ( va ) | |
425 | (vpt-pgmap) ( ) | |
426 | then ( ) | |
427 | /x +loop ( ) | |
428 | ; | |
429 | ||
430 | \ walk the vpt and execute acf with va,len,tte on the stack | |
431 | \ beginning at the vpt-root, iterate over each tte in that page; | |
432 | \ for each valid tte, go to the page it maps and iterate over those tte's; | |
433 | \ for each valid tte in those pages, again descend to the mapped page | |
434 | \ and iterate over those tte's; these last map the remaining address space | |
435 | : vpt-walker ( acf -- ) | |
436 | is vpt-data-fn ( ) | |
437 | prev-tte-invalid ( ) | |
438 | vpt-root pagesize bounds do ( ) | |
439 | i x@ valid-tte? if | |
440 | i vptshift lshift ( va ) | |
441 | (vpt-segment) ( ) | |
442 | then | |
443 | /x +loop | |
444 | prev-tte-valid? if | |
445 | vpt-data@ vpt-data-fn | |
446 | then | |
447 | ; |