Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: prom_mmu.c | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * Copyright (c) 2000-2003 Sun Microsystems, Inc. | |
46 | * All rights reserved. | |
47 | * Use is subject to license terms. | |
48 | */ | |
49 | ||
50 | #pragma ident "@(#)prom_mmu.c 1.1 00/08/07 SMI" | |
51 | ||
52 | /* | |
53 | * This file contains platform-dependent MMU support routines, | |
54 | * suitable for mmu methods with 2-cell physical addresses. | |
55 | * Use of these routines makes the caller platform-dependent, | |
56 | * since the caller assumes knowledge of the physical layout of | |
57 | * the machines address space. Generic programs should use the | |
58 | * standard client interface memory allocators. | |
59 | */ | |
60 | ||
61 | #include <sys/promif.h> | |
62 | #include <sys/promimpl.h> | |
63 | ||
64 | ihandle_t | |
65 | prom_mmu_ihandle(void) | |
66 | { | |
67 | static ihandle_t immu; | |
68 | ||
69 | if (immu != (ihandle_t)0) | |
70 | return (immu); | |
71 | ||
72 | if (prom_getproplen(prom_chosennode(), "mmu") != sizeof (ihandle_t)) | |
73 | return (immu = (ihandle_t)-1); | |
74 | ||
75 | (void) prom_getprop(prom_chosennode(), "mmu", (caddr_t)(&immu)); | |
76 | immu = (ihandle_t)prom_decode_int(immu); | |
77 | return (immu); | |
78 | } | |
79 | ||
80 | /* | |
81 | * prom_map_phys: | |
82 | * | |
83 | * Create an MMU mapping for a given physical address to a given virtual | |
84 | * address. The given resources are assumed to be owned by the caller, | |
85 | * and are *not* removed from any free lists. | |
86 | * | |
87 | * This routine is suitable for mapping a 2-cell physical address. | |
88 | */ | |
89 | ||
90 | int | |
91 | prom_map_phys(int32_t mode, size_t size, caddr_t virt, u_longlong_t physaddr) | |
92 | { | |
93 | cell_t ci[11]; | |
94 | int32_t rv; | |
95 | ihandle_t immu = prom_mmu_ihandle(); | |
96 | ||
97 | if ((immu == (ihandle_t)-1)) | |
98 | return (-1); | |
99 | ||
100 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
101 | ci[1] = (cell_t)7; /* #argument cells */ | |
102 | ci[2] = (cell_t)1; /* #result cells */ | |
103 | ci[3] = p1275_ptr2cell("map"); /* Arg1: method name */ | |
104 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
105 | ci[5] = p1275_int2cell(mode); /* Arg3: SA1: mode */ | |
106 | ci[6] = p1275_size2cell(size); /* Arg4: SA2: size */ | |
107 | ci[7] = p1275_ptr2cell(virt); /* Arg5: SA3: virt */ | |
108 | ci[8] = p1275_ull2cell_high(physaddr); /* Arg6: SA4: phys.hi */ | |
109 | ci[9] = p1275_ull2cell_low(physaddr); /* Arg7: SA5: phys.low */ | |
110 | ||
111 | rv = p1275_cif_handler(&ci); | |
112 | ||
113 | if (rv != 0) | |
114 | return (-1); | |
115 | if (ci[10] != 0) /* Res1: Catch result */ | |
116 | return (-1); | |
117 | return (0); | |
118 | } | |
119 | ||
120 | void | |
121 | prom_unmap_phys(size_t size, caddr_t virt) | |
122 | { | |
123 | (void) prom_unmap_virt(size, virt); | |
124 | } | |
125 | ||
126 | /* | |
127 | * Allocate aligned or unaligned virtual address space, unmapped. | |
128 | */ | |
129 | caddr_t | |
130 | prom_allocate_virt(uint32_t align, size_t size) | |
131 | { | |
132 | cell_t ci[9]; | |
133 | int32_t rv; | |
134 | ihandle_t immu = prom_mmu_ihandle(); | |
135 | ||
136 | if ((immu == (ihandle_t)-1)) | |
137 | return ((caddr_t)-1); | |
138 | ||
139 | if (align == 0) | |
140 | align = 1; | |
141 | ||
142 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
143 | ci[1] = (cell_t)4; /* #argument cells */ | |
144 | ci[2] = (cell_t)2; /* #result cells */ | |
145 | ci[3] = p1275_ptr2cell("claim"); /* Arg1: Method name */ | |
146 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
147 | ci[5] = p1275_uint2cell(align); /* Arg3: SA1: align */ | |
148 | ci[6] = p1275_size2cell(size); /* Arg4: SA2: size */ | |
149 | ||
150 | rv = p1275_cif_handler(&ci); | |
151 | ||
152 | if (rv != 0) | |
153 | return ((caddr_t)-1); | |
154 | if (ci[7] != 0) /* Res1: Catch result */ | |
155 | return ((caddr_t)-1); | |
156 | return (p1275_cell2ptr(ci[8])); /* Res2: SR1: base */ | |
157 | } | |
158 | ||
159 | /* | |
160 | * Claim a region of virtual address space, unmapped. | |
161 | */ | |
162 | caddr_t | |
163 | prom_claim_virt(size_t size, caddr_t virt) | |
164 | { | |
165 | cell_t ci[10]; | |
166 | int32_t rv; | |
167 | ihandle_t immu = prom_mmu_ihandle(); | |
168 | ||
169 | if ((immu == (ihandle_t)-1)) | |
170 | return ((caddr_t)-1); | |
171 | ||
172 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
173 | ci[1] = (cell_t)5; /* #argument cells */ | |
174 | ci[2] = (cell_t)2; /* #result cells */ | |
175 | ci[3] = p1275_ptr2cell("claim"); /* Arg1: Method name */ | |
176 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
177 | ci[5] = (cell_t)0; /* Arg3: align */ | |
178 | ci[6] = p1275_size2cell(size); /* Arg4: length */ | |
179 | ci[7] = p1275_ptr2cell(virt); /* Arg5: virt */ | |
180 | ||
181 | rv = p1275_cif_handler(&ci); | |
182 | ||
183 | if (rv != 0) | |
184 | return ((caddr_t)-1); | |
185 | if (ci[8] != 0) /* Res1: Catch result */ | |
186 | return ((caddr_t)-1); | |
187 | return (p1275_cell2ptr(ci[9])); /* Res2: base */ | |
188 | } | |
189 | ||
190 | /* | |
191 | * Free virtual address resource (no unmapping is done). | |
192 | */ | |
193 | void | |
194 | prom_free_virt(size_t size, caddr_t virt) | |
195 | { | |
196 | cell_t ci[7]; | |
197 | ihandle_t immu = prom_mmu_ihandle(); | |
198 | ||
199 | if ((immu == (ihandle_t)-1)) | |
200 | return; | |
201 | ||
202 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
203 | ci[1] = (cell_t)4; /* #argument cells */ | |
204 | ci[2] = (cell_t)0; /* #return cells */ | |
205 | ci[3] = p1275_ptr2cell("release"); /* Arg1: Method name */ | |
206 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
207 | ci[5] = p1275_size2cell(size); /* Arg3: length */ | |
208 | ci[6] = p1275_ptr2cell(virt); /* Arg4: virt */ | |
209 | ||
210 | (void) p1275_cif_handler(&ci); | |
211 | } | |
212 | ||
213 | /* | |
214 | * Un-map virtual address. Does not free underlying resources. | |
215 | */ | |
216 | void | |
217 | prom_unmap_virt(size_t size, caddr_t virt) | |
218 | { | |
219 | cell_t ci[7]; | |
220 | ihandle_t immu = prom_mmu_ihandle(); | |
221 | ||
222 | if ((immu == (ihandle_t)-1)) | |
223 | return; | |
224 | ||
225 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
226 | ci[1] = (cell_t)4; /* #argument cells */ | |
227 | ci[2] = (cell_t)0; /* #result cells */ | |
228 | ci[3] = p1275_ptr2cell("unmap"); /* Arg1: Method name */ | |
229 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
230 | ci[5] = p1275_size2cell(size); /* Arg3: SA1: size */ | |
231 | ci[6] = p1275_ptr2cell(virt); /* Arg4: SA2: virt */ | |
232 | ||
233 | (void) p1275_cif_handler(&ci); | |
234 | } | |
235 | ||
236 | /* | |
237 | * Translate virtual address to physical address. | |
238 | * Returns 0: Success; Non-zero: failure. | |
239 | * Returns *phys_hi, *phys_lo and *mode only if successful. | |
240 | */ | |
241 | int | |
242 | prom_translate_virt(caddr_t virt, int32_t *valid, | |
243 | u_longlong_t *physaddr, int32_t *mode) | |
244 | { | |
245 | cell_t ci[11]; | |
246 | int32_t rv; | |
247 | ihandle_t immu = prom_mmu_ihandle(); | |
248 | ||
249 | *valid = 0; | |
250 | ||
251 | if ((immu == (ihandle_t)-1)) | |
252 | return (-1); | |
253 | ||
254 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
255 | ci[1] = (cell_t)3; /* #argument cells */ | |
256 | ci[2] = (cell_t)5; /* #result cells */ | |
257 | ci[3] = p1275_ptr2cell("translate"); /* Arg1: Method name */ | |
258 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
259 | ci[5] = p1275_ptr2cell(virt); /* Arg3: virt */ | |
260 | ci[6] = 0; /* Res1: catch-result */ | |
261 | ci[7] = 0; /* Res2: sr1: valid */ | |
262 | ||
263 | rv = p1275_cif_handler(&ci); | |
264 | ||
265 | if (rv == -1) /* Did the call fail ? */ | |
266 | return (-1); | |
267 | if (ci[6] != 0) /* Catch result */ | |
268 | return (-1); | |
269 | ||
270 | if (p1275_cell2int(ci[7]) != -1) /* Valid results ? */ | |
271 | return (0); | |
272 | ||
273 | *mode = p1275_cell2int(ci[8]); /* Res3: sr2: mode, if valid */ | |
274 | *physaddr = p1275_cells2ull(ci[9], ci[10]); | |
275 | /* Res4: sr3: phys-hi ... Res5: sr4: phys-lo */ | |
276 | *valid = -1; /* Indicate valid result */ | |
277 | return (0); | |
278 | } | |
279 | ||
280 | int | |
281 | prom_modify_mapping(caddr_t virt, size_t size, int32_t mode) | |
282 | { | |
283 | cell_t ci[8]; | |
284 | int32_t rv; | |
285 | ihandle_t immu = prom_mmu_ihandle(); | |
286 | ||
287 | if ((immu == (ihandle_t)-1)) | |
288 | return (-1); | |
289 | ||
290 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
291 | ci[1] = (cell_t)3; /* #argument cells */ | |
292 | ci[2] = (cell_t)0; /* #result cells */ | |
293 | ci[3] = p1275_ptr2cell("modify"); /* Arg1: Method name */ | |
294 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: immu handle */ | |
295 | ci[5] = p1275_int2cell(mode); /* Arg3: mode */ | |
296 | ci[6] = p1275_size2cell(size); /* Arg4: size */ | |
297 | ci[7] = p1275_ptr2cell(virt); /* Arg5: virt */ | |
298 | ||
299 | rv = p1275_cif_handler(&ci); | |
300 | ||
301 | if (rv != 0) | |
302 | return (-1); | |
303 | if (ci[8] != 0) /* Res1: Catch result */ | |
304 | return (-1); | |
305 | return (0); | |
306 | } | |
307 | ||
308 | /* | |
309 | * prom_itlb_load, prom_dtlb_load: | |
310 | * | |
311 | * Manage the TLB. Returns 0 if successful, -1 otherwise. | |
312 | * Flush the address in context zero mapped by tte_data and virt, | |
313 | * and load the {i,d} tlb entry index with tte_data and virt. | |
314 | */ | |
315 | ||
316 | int | |
317 | prom_itlb_load(int32_t index, u_longlong_t tte_data, caddr_t virt) | |
318 | { | |
319 | cell_t ci[9]; | |
320 | int32_t rv; | |
321 | ihandle_t immu = prom_mmu_ihandle(); | |
322 | ||
323 | if ((immu == (ihandle_t)-1)) | |
324 | return (-1); | |
325 | ||
326 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
327 | ci[1] = (cell_t)5; /* #argument cells */ | |
328 | ci[2] = (cell_t)1; /* #result cells */ | |
329 | ci[3] = p1275_ptr2cell("SUNW,itlb-load"); /* Arg1: method name */ | |
330 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
331 | ci[5] = p1275_ptr2cell(virt); /* Arg3: SA1: virt */ | |
332 | ci[6] = (cell_t)tte_data; /* Arg4: SA2: tte_data */ | |
333 | ci[7] = p1275_int2cell(index); /* Arg5: SA3: index */ | |
334 | ||
335 | rv = p1275_cif_handler(&ci); | |
336 | ||
337 | if (rv != 0) | |
338 | return (-1); | |
339 | if (ci[8] != 0) /* Res1: Catch result */ | |
340 | return (-1); | |
341 | return (0); | |
342 | } | |
343 | ||
344 | int | |
345 | prom_dtlb_load(int32_t index, u_longlong_t tte_data, caddr_t virt) | |
346 | { | |
347 | cell_t ci[9]; | |
348 | int32_t rv; | |
349 | ihandle_t immu = prom_mmu_ihandle(); | |
350 | ||
351 | if ((immu == (ihandle_t)-1)) | |
352 | return (-1); | |
353 | ||
354 | ci[0] = p1275_ptr2cell("call-method"); /* Service name */ | |
355 | ci[1] = (cell_t)5; /* #argument cells */ | |
356 | ci[2] = (cell_t)1; /* #result cells */ | |
357 | ci[3] = p1275_ptr2cell("SUNW,dtlb-load"); /* Arg1: method name */ | |
358 | ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ | |
359 | ci[5] = p1275_ptr2cell(virt); /* Arg3: SA1: virt */ | |
360 | ci[6] = (cell_t)tte_data; /* Arg4: SA2: tte_data */ | |
361 | ci[7] = p1275_int2cell(index); /* Arg5: SA3: index */ | |
362 | ||
363 | rv = p1275_cif_handler(&ci); | |
364 | ||
365 | if (rv != 0) | |
366 | return (-1); | |
367 | if (ci[8] != 0) /* Res1: Catch result */ | |
368 | return (-1); | |
369 | return (0); | |
370 | } |