1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains platform-dependent MMU support routines, 28 * suitable for mmu methods with 2-cell physical addresses. 29 * Use of these routines makes the caller platform-dependent, 30 * since the caller assumes knowledge of the physical layout of 31 * the machines address space. Generic programs should use the 32 * standard client interface memory allocators. 33 */ 34 35 #include <sys/promif.h> 36 #include <sys/promimpl.h> 37 38 ihandle_t 39 prom_mmu_ihandle(void) 40 { 41 static ihandle_t immu; 42 43 if (immu != (ihandle_t)0) 44 return (immu); 45 46 if (prom_getproplen(prom_chosennode(), "mmu") != sizeof (ihandle_t)) 47 return (immu = (ihandle_t)-1); 48 49 (void) prom_getprop(prom_chosennode(), "mmu", (caddr_t)(&immu)); 50 return (immu); 51 } 52 53 /* 54 * prom_map_phys: 55 * 56 * Create an MMU mapping for a given physical address to a given virtual 57 * address. The given resources are assumed to be owned by the caller, 58 * and are *not* removed from any free lists. 59 * 60 * This routine is suitable for mapping a 2-cell physical address. 61 */ 62 63 int 64 prom_map_phys(int mode, size_t size, caddr_t virt, unsigned long long physaddr) 65 { 66 cell_t ci[11]; 67 int rv; 68 ihandle_t immu = prom_mmu_ihandle(); 69 70 if ((immu == (ihandle_t)-1)) 71 return (-1); 72 73 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 74 ci[1] = (cell_t)7; /* #argument cells */ 75 ci[2] = (cell_t)1; /* #result cells */ 76 ci[3] = p1275_ptr2cell("map"); /* Arg1: method name */ 77 ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ 78 ci[5] = p1275_int2cell(mode); /* Arg3: SA1: mode */ 79 ci[6] = p1275_size2cell(size); /* Arg4: SA2: size */ 80 ci[7] = p1275_ptr2cell(virt); /* Arg5: SA3: virt */ 81 ci[8] = p1275_ull2cell_high(physaddr); /* Arg6: SA4: phys.hi */ 82 ci[9] = p1275_ull2cell_low(physaddr); /* Arg7: SA5: phys.low */ 83 84 promif_preprom(); 85 rv = p1275_cif_handler(&ci); 86 promif_postprom(); 87 88 if (rv != 0) 89 return (-1); 90 if (ci[10] != 0) /* Res1: Catch result */ 91 return (-1); 92 return (0); 93 } 94 95 void 96 prom_unmap_phys(size_t size, caddr_t virt) 97 { 98 (void) prom_unmap_virt(size, virt); 99 } 100 101 /* 102 * Allocate aligned or unaligned virtual address space, unmapped. 103 */ 104 caddr_t 105 prom_allocate_virt(uint_t align, size_t size) 106 { 107 cell_t ci[9]; 108 int rv; 109 ihandle_t immu = prom_mmu_ihandle(); 110 111 if ((immu == (ihandle_t)-1)) 112 return ((caddr_t)-1); 113 114 if (align == 0) 115 align = 1; 116 117 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 118 ci[1] = (cell_t)4; /* #argument cells */ 119 ci[2] = (cell_t)2; /* #result cells */ 120 ci[3] = p1275_ptr2cell("claim"); /* Arg1: Method name */ 121 ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ 122 ci[5] = p1275_uint2cell(align); /* Arg3: SA1: align */ 123 ci[6] = p1275_size2cell(size); /* Arg4: SA2: size */ 124 125 promif_preprom(); 126 rv = p1275_cif_handler(&ci); 127 promif_postprom(); 128 129 if (rv != 0) 130 return ((caddr_t)-1); 131 if (ci[7] != 0) /* Res1: Catch result */ 132 return ((caddr_t)-1); 133 return (p1275_cell2ptr(ci[8])); /* Res2: SR1: base */ 134 } 135 136 /* 137 * Claim a region of virtual address space, unmapped. 138 */ 139 caddr_t 140 prom_claim_virt(size_t size, caddr_t virt) 141 { 142 cell_t ci[10]; 143 int rv; 144 ihandle_t immu = prom_mmu_ihandle(); 145 146 if ((immu == (ihandle_t)-1)) 147 return ((caddr_t)-1); 148 149 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 150 ci[1] = (cell_t)5; /* #argument cells */ 151 ci[2] = (cell_t)2; /* #result cells */ 152 ci[3] = p1275_ptr2cell("claim"); /* Arg1: Method name */ 153 ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ 154 ci[5] = (cell_t)0; /* Arg3: align */ 155 ci[6] = p1275_size2cell(size); /* Arg4: length */ 156 ci[7] = p1275_ptr2cell(virt); /* Arg5: virt */ 157 158 promif_preprom(); 159 rv = p1275_cif_handler(&ci); 160 promif_postprom(); 161 162 if (rv != 0) 163 return ((caddr_t)-1); 164 if (ci[8] != 0) /* Res1: Catch result */ 165 return ((caddr_t)-1); 166 return (p1275_cell2ptr(ci[9])); /* Res2: base */ 167 } 168 169 /* 170 * Free virtual address resource (no unmapping is done). 171 */ 172 void 173 prom_free_virt(size_t size, caddr_t virt) 174 { 175 cell_t ci[7]; 176 ihandle_t immu = prom_mmu_ihandle(); 177 178 if ((immu == (ihandle_t)-1)) 179 return; 180 181 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 182 ci[1] = (cell_t)4; /* #argument cells */ 183 ci[2] = (cell_t)0; /* #return cells */ 184 ci[3] = p1275_ptr2cell("release"); /* Arg1: Method name */ 185 ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ 186 ci[5] = p1275_size2cell(size); /* Arg3: length */ 187 ci[6] = p1275_ptr2cell(virt); /* Arg4: virt */ 188 189 promif_preprom(); 190 (void) p1275_cif_handler(&ci); 191 promif_postprom(); 192 } 193 194 /* 195 * Un-map virtual address. Does not free underlying resources. 196 */ 197 void 198 prom_unmap_virt(size_t size, caddr_t virt) 199 { 200 cell_t ci[7]; 201 ihandle_t immu = prom_mmu_ihandle(); 202 203 if ((immu == (ihandle_t)-1)) 204 return; 205 206 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 207 ci[1] = (cell_t)4; /* #argument cells */ 208 ci[2] = (cell_t)0; /* #result cells */ 209 ci[3] = p1275_ptr2cell("unmap"); /* Arg1: Method name */ 210 ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ 211 ci[5] = p1275_size2cell(size); /* Arg3: SA1: size */ 212 ci[6] = p1275_ptr2cell(virt); /* Arg4: SA2: virt */ 213 214 promif_preprom(); 215 (void) p1275_cif_handler(&ci); 216 promif_postprom(); 217 } 218 219 static pnode_t 220 prom_mmu_phandle(void) 221 { 222 static pnode_t pmmu = 0; 223 224 if (pmmu == (pnode_t)0) { 225 ihandle_t ih; 226 227 if ((ih = prom_mmu_ihandle()) == (ihandle_t)-1) 228 prom_panic("Can't get mmu ihandle"); 229 pmmu = prom_getphandle(ih); 230 } 231 return (pmmu); 232 } 233 234 235 int 236 prom_virt_avail_len(void) 237 { 238 return (prom_getproplen(prom_mmu_phandle(), "available")); 239 } 240 241 int 242 prom_virt_avail(caddr_t prop) 243 { 244 return (prom_getprop(prom_mmu_phandle(), "available", prop)); 245 } 246 247 /* 248 * Translate virtual address to physical address. 249 * Returns 0: Success; Non-zero: failure. 250 * Returns *phys_hi, *phys_lo and *mode only if successful. 251 */ 252 int 253 prom_translate_virt(caddr_t virt, int *valid, 254 unsigned long long *physaddr, int *mode) 255 { 256 cell_t ci[11]; 257 int rv; 258 ihandle_t immu = prom_mmu_ihandle(); 259 260 *valid = 0; 261 262 if ((immu == (ihandle_t)-1)) 263 return (-1); 264 265 ci[0] = p1275_ptr2cell("call-method"); /* Service name */ 266 ci[1] = (cell_t)3; /* #argument cells */ 267 ci[2] = (cell_t)5; /* #result cells */ 268 ci[3] = p1275_ptr2cell("translate"); /* Arg1: Method name */ 269 ci[4] = p1275_ihandle2cell(immu); /* Arg2: mmu ihandle */ 270 ci[5] = p1275_ptr2cell(virt); /* Arg3: virt */ 271 ci[6] = 0; /* Res1: catch-resule */ 272 ci[7] = 0; /* Res2: sr1: valid */ 273 274 promif_preprom(); 275 rv = p1275_cif_handler(&ci); 276 promif_postprom(); 277 278 if (rv == -1) /* Did the call fail ? */ 279 return (-1); 280 if (ci[6] != 0) /* Catch result */ 281 return (-1); 282 283 if (p1275_cell2int(ci[7]) != -1) /* Valid results ? */ 284 return (0); 285 286 *mode = p1275_cell2int(ci[8]); /* Res3: sr2: mode, if valid */ 287 *physaddr = p1275_cells2ull(ci[9], ci[10]); 288 /* Res4: sr3: phys-hi ... Res5: sr4: phys-lo */ 289 *valid = -1; /* Indicate valid result */ 290 return (0); 291 } 292