1 1.2 thorpej /* $NetBSD: loadfile_machdep.c,v 1.2 2022/07/10 14:18:27 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.1 thorpej * Copyright (c) 2021 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe. 9 1.1 thorpej * 10 1.1 thorpej * Redistribution and use in source and binary forms, with or without 11 1.1 thorpej * modification, are permitted provided that the following conditions 12 1.1 thorpej * are met: 13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 14 1.1 thorpej * notice, this list of conditions and the following disclaimer. 15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 17 1.1 thorpej * documentation and/or other materials provided with the distribution. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 30 1.1 thorpej */ 31 1.1 thorpej 32 1.1 thorpej #include "boot.h" 33 1.1 thorpej 34 1.1 thorpej #include <sys/param.h> 35 1.1 thorpej #include <sys/boot_flag.h> 36 1.1 thorpej #include <sys/disklabel.h> 37 1.1 thorpej 38 1.1 thorpej #include <lib/libsa/stand.h> 39 1.1 thorpej #include <lib/libsa/loadfile.h> 40 1.1 thorpej #include <lib/libkern/libkern.h> 41 1.1 thorpej 42 1.1 thorpej #include "openfirm.h" 43 1.1 thorpej 44 1.1 thorpej #ifdef KMAPPING_DEBUG 45 1.1 thorpej #define DPRINTF printf 46 1.1 thorpej #else 47 1.1 thorpej #define DPRINTF while (0) printf 48 1.1 thorpej #endif 49 1.1 thorpej 50 1.1 thorpej static int 51 1.1 thorpej ofw_claimphys(paddr_t pa, vsize_t size) 52 1.1 thorpej { 53 1.1 thorpej /* (2) phys, (2) size, (1) align -> 2 (phys) */ 54 1.1 thorpej uint32_t cells[2+2+1+2]; 55 1.1 thorpej uint32_t *p = cells; 56 1.1 thorpej paddr_t result; 57 1.1 thorpej 58 1.1 thorpej if (ofw_address_cells == 2) { 59 1.2 thorpej *p++ = ((uint64_t)pa) >> 32; 60 1.1 thorpej *p++ = (uint32_t)pa; 61 1.1 thorpej } else { 62 1.1 thorpej *p++ = (uint32_t)pa; 63 1.1 thorpej } 64 1.1 thorpej 65 1.2 thorpej #if 0 /* No known Mac systems with 2. */ 66 1.1 thorpej if (ofw_size_cells == 2) { 67 1.1 thorpej *p++ = ((uint64_t)size) >> 32; 68 1.1 thorpej *p++ = (uint32_t)size; 69 1.1 thorpej } else 70 1.1 thorpej #endif 71 1.1 thorpej *p++ = (uint32_t)size; 72 1.1 thorpej 73 1.1 thorpej *p++ = 0; /* align */ 74 1.1 thorpej 75 1.1 thorpej if (OF_call_method("claim", ofw_memory_ihandle, 76 1.1 thorpej ofw_address_cells + ofw_size_cells + 1, 77 1.1 thorpej ofw_address_cells, (int *)cells) == -1) { 78 1.1 thorpej return -1; 79 1.1 thorpej } 80 1.1 thorpej 81 1.1 thorpej if (ofw_address_cells == 2) { 82 1.1 thorpej uint64_t v; 83 1.2 thorpej v = (uint64_t)(*p++) << 32; 84 1.2 thorpej v |= *p++; 85 1.1 thorpej result = (paddr_t)v; 86 1.1 thorpej } else { 87 1.1 thorpej result = *p++; 88 1.1 thorpej } 89 1.1 thorpej 90 1.1 thorpej if (result != pa) { 91 1.1 thorpej printf("!!! CLAIM PHYS 0x%lx RETURNED 0x%lx\n", 92 1.1 thorpej pa, result); 93 1.1 thorpej return -1; 94 1.1 thorpej } 95 1.1 thorpej 96 1.1 thorpej return 0; 97 1.1 thorpej } 98 1.1 thorpej 99 1.1 thorpej static int 100 1.1 thorpej ofw_releasephys(paddr_t pa, vsize_t size) 101 1.1 thorpej { 102 1.1 thorpej /* (2) phys, (2) size, -> nil */ 103 1.1 thorpej uint32_t cells[2+2]; 104 1.1 thorpej uint32_t *p = cells; 105 1.1 thorpej 106 1.1 thorpej if (ofw_address_cells == 2) { 107 1.2 thorpej *p++ = ((uint64_t)pa) >> 32; 108 1.1 thorpej *p++ = (uint32_t)pa; 109 1.1 thorpej } else { 110 1.1 thorpej *p++ = (uint32_t)pa; 111 1.1 thorpej } 112 1.1 thorpej 113 1.2 thorpej #if 0 /* No known Mac systems with 2. */ 114 1.1 thorpej if (ofw_size_cells == 2) { 115 1.1 thorpej *p++ = ((uint64_t)size) >> 32; 116 1.1 thorpej *p++ = (uint32_t)size; 117 1.1 thorpej } else 118 1.1 thorpej #endif 119 1.1 thorpej *p++ = (uint32_t)size; 120 1.1 thorpej 121 1.1 thorpej if (OF_call_method("release", ofw_memory_ihandle, 122 1.1 thorpej ofw_address_cells + ofw_size_cells, 123 1.1 thorpej 0, (int *)cells) == -1) { 124 1.1 thorpej return -1; 125 1.1 thorpej } 126 1.1 thorpej 127 1.1 thorpej return 0; 128 1.1 thorpej } 129 1.1 thorpej 130 1.1 thorpej static int 131 1.1 thorpej ofw_claimvirt(vaddr_t va, vsize_t size) 132 1.1 thorpej { 133 1.1 thorpej /* (1) virt, (1) size, (1) align -> (1) virt */ 134 1.1 thorpej uint32_t cells[1+1+1+1]; 135 1.1 thorpej uint32_t *p = cells; 136 1.1 thorpej vaddr_t result; 137 1.1 thorpej 138 1.1 thorpej *p++ = va; 139 1.1 thorpej *p++ = size; 140 1.1 thorpej *p++ = 0; /* align */ 141 1.1 thorpej 142 1.1 thorpej if (OF_call_method("claim", ofw_mmu_ihandle, 143 1.1 thorpej 3, 1, (int *)cells) == -1) { 144 1.1 thorpej return -1; 145 1.1 thorpej } 146 1.1 thorpej 147 1.1 thorpej result = *p++; 148 1.1 thorpej 149 1.1 thorpej if (result != va) { 150 1.1 thorpej printf("!!! CLAIM VIRT 0x%lx RETURNED 0x%lx\n", 151 1.1 thorpej va, result); 152 1.1 thorpej return -1; 153 1.1 thorpej } 154 1.1 thorpej 155 1.1 thorpej return 0; 156 1.1 thorpej } 157 1.1 thorpej 158 1.1 thorpej static int 159 1.1 thorpej ofw_releasevirt(vaddr_t va, vsize_t size) 160 1.1 thorpej { 161 1.1 thorpej /* (1) virt, (1) size -> nil */ 162 1.1 thorpej uint32_t cells[1+1]; 163 1.1 thorpej uint32_t *p = cells; 164 1.1 thorpej 165 1.1 thorpej *p++ = va; 166 1.1 thorpej *p++ = size; 167 1.1 thorpej 168 1.1 thorpej if (OF_call_method("release", ofw_mmu_ihandle, 169 1.1 thorpej 2, 0, (int *)cells) == -1) { 170 1.1 thorpej return -1; 171 1.1 thorpej } 172 1.1 thorpej 173 1.1 thorpej return 0; 174 1.1 thorpej } 175 1.1 thorpej 176 1.1 thorpej static int 177 1.1 thorpej ofw_map(vaddr_t va, paddr_t pa, vsize_t size) 178 1.1 thorpej { 179 1.1 thorpej /* (2) phys, (1) virt, (1) size, (1) mode -> nil */ 180 1.1 thorpej uint32_t cells[2+1+1+1]; 181 1.1 thorpej uint32_t *p = cells; 182 1.1 thorpej 183 1.1 thorpej if (ofw_address_cells == 2) { 184 1.2 thorpej *p++ = ((uint64_t)pa) >> 32; 185 1.1 thorpej *p++ = (uint32_t)pa; 186 1.1 thorpej } else { 187 1.1 thorpej *p++ = (uint32_t)pa; 188 1.1 thorpej } 189 1.1 thorpej 190 1.1 thorpej *p++ = va; 191 1.1 thorpej *p++ = size; 192 1.1 thorpej *p++ = 0x00000010 /* PTE_SO | PTE_M */; /* XXX magic numbers */ 193 1.1 thorpej 194 1.1 thorpej if (OF_call_method("map", ofw_mmu_ihandle, 195 1.1 thorpej ofw_address_cells + 3, 0, (int *)cells) == -1) { 196 1.1 thorpej return -1; 197 1.1 thorpej } 198 1.1 thorpej 199 1.1 thorpej return 0; 200 1.1 thorpej } 201 1.1 thorpej 202 1.1 thorpej static int 203 1.1 thorpej ofw_create_mapping(vaddr_t va, paddr_t pa, vsize_t size) 204 1.1 thorpej { 205 1.1 thorpej if (ofw_claimphys(pa, size) == -1) { 206 1.1 thorpej printf("!!! FAILED TO CLAIM PHYS 0x%lx size 0x%lx\n", 207 1.1 thorpej pa, size); 208 1.1 thorpej return -1; 209 1.1 thorpej } 210 1.1 thorpej 211 1.1 thorpej /* 212 1.1 thorpej * If we're running in real-mode, the claimphys is enough. 213 1.1 thorpej */ 214 1.1 thorpej if (ofw_real_mode) { 215 1.1 thorpej return 0; 216 1.1 thorpej } 217 1.1 thorpej 218 1.1 thorpej if (ofw_claimvirt(va, size) == -1) { 219 1.1 thorpej printf("!!! FAILED TO CLAIM VIRT 0x%lx size 0x%lx\n", 220 1.1 thorpej va, size); 221 1.1 thorpej ofw_releasephys(pa, size); 222 1.1 thorpej return -1; 223 1.1 thorpej } 224 1.1 thorpej if (ofw_map(va, pa, size) == -1) { 225 1.1 thorpej printf("!!! FAILED TO MAP PHYS 0x%lx @ 0x%lx size 0x%lx\n", 226 1.1 thorpej pa, va, size); 227 1.1 thorpej ofw_releasevirt(va, size); 228 1.1 thorpej ofw_releasephys(pa, size); 229 1.1 thorpej return -1; 230 1.1 thorpej } 231 1.1 thorpej 232 1.1 thorpej return 0; 233 1.1 thorpej } 234 1.1 thorpej 235 1.1 thorpej /* 236 1.1 thorpej * This structure describes a physically contiguous mapping 237 1.1 thorpej * for the loaded kernel. We assume VA==PA, which would be 238 1.1 thorpej * equivalent to running in real-mode. 239 1.1 thorpej */ 240 1.1 thorpej #define MAX_KMAPPINGS 64 241 1.1 thorpej struct kmapping { 242 1.1 thorpej vaddr_t vstart; 243 1.1 thorpej vaddr_t vend; 244 1.1 thorpej } kmappings[MAX_KMAPPINGS]; 245 1.1 thorpej 246 1.1 thorpej #define TRUNC_PAGE(x) ((x) & ~((unsigned long)NBPG - 1)) 247 1.1 thorpej #define ROUND_PAGE(x) TRUNC_PAGE((x) + (NBPG - 1)) 248 1.1 thorpej 249 1.1 thorpej /* 250 1.1 thorpej * Enter a mapping for the loaded kernel. If the start is within an 251 1.1 thorpej * already mapped region, or if it starts immediately following a 252 1.1 thorpej * previous region, we extend it. 253 1.1 thorpej */ 254 1.1 thorpej static int 255 1.1 thorpej kmapping_enter(vaddr_t va, vsize_t size) 256 1.1 thorpej { 257 1.1 thorpej struct kmapping *km, *km_prev, *km_next, *km_last; 258 1.1 thorpej vaddr_t va_end; 259 1.1 thorpej int i; 260 1.1 thorpej 261 1.1 thorpej km_last = &kmappings[MAX_KMAPPINGS - 1]; 262 1.1 thorpej 263 1.1 thorpej /* Round the region to a page. */ 264 1.1 thorpej va_end = ROUND_PAGE(va + size); 265 1.1 thorpej 266 1.1 thorpej /* Truncate the region to the nearest page boundary. */ 267 1.1 thorpej va = TRUNC_PAGE(va); 268 1.1 thorpej 269 1.1 thorpej /* Get the rounded size. */ 270 1.1 thorpej size = va_end - va; 271 1.1 thorpej 272 1.1 thorpej DPRINTF("kmapping_enter: va=0x%lx size=0x%lx\n", 273 1.1 thorpej va, size); 274 1.1 thorpej 275 1.1 thorpej /* Check to see if there's an overlapping entry in the table. */ 276 1.1 thorpej for (i = 0, km_prev = NULL; i < MAX_KMAPPINGS; i++, km_prev = km) { 277 1.1 thorpej km = &kmappings[i]; 278 1.1 thorpej km_next = (km == km_last) ? NULL : (km + 1); 279 1.1 thorpej 280 1.1 thorpej if (km->vstart == km->vend) { 281 1.1 thorpej /* 282 1.1 thorpej * Found an empty slot. We are guaranteed there 283 1.1 thorpej * is not slot after this to merge with. 284 1.1 thorpej */ 285 1.1 thorpej DPRINTF("!!! entering into empty slot (%d)\n", i); 286 1.1 thorpej goto enter_new; 287 1.1 thorpej } 288 1.1 thorpej 289 1.1 thorpej if (va >= km->vstart) { 290 1.1 thorpej if (va_end <= km->vend) { 291 1.1 thorpej /* This region is already fully mapped. */ 292 1.1 thorpej DPRINTF("!!! matches existing region " 293 1.1 thorpej "va=0x%lx-0x%lx\n", 294 1.1 thorpej km->vstart, km->vend); 295 1.1 thorpej return 0; 296 1.1 thorpej } 297 1.1 thorpej if (va > km->vend) { 298 1.1 thorpej /* Requested region falls after this one. */ 299 1.1 thorpej continue; 300 1.1 thorpej } 301 1.1 thorpej 302 1.1 thorpej /* 303 1.1 thorpej * We will extend this region. Adjust the 304 1.1 thorpej * start and size. 305 1.1 thorpej */ 306 1.1 thorpej va = km->vend; 307 1.1 thorpej size = va_end - va; 308 1.1 thorpej 309 1.1 thorpej /* 310 1.1 thorpej * If there is a slot after this one and it's 311 1.1 thorpej * not empty, see if these two can be merged. 312 1.1 thorpej */ 313 1.1 thorpej if (km_next != NULL && 314 1.1 thorpej km_next->vstart != km_next->vend && 315 1.1 thorpej va_end >= km_next->vstart) { 316 1.1 thorpej if (va_end > km_next->vend) { 317 1.1 thorpej /* Crazy! */ 318 1.1 thorpej printf("!!! GOBBLED UP KM_NEXT!\n"); 319 1.1 thorpej return 1; 320 1.1 thorpej } 321 1.1 thorpej va_end = km_next->vstart; 322 1.1 thorpej size = va_end - va; 323 1.1 thorpej 324 1.1 thorpej DPRINTF("!!! merging va=0x%lx-0x%lx and " 325 1.1 thorpej "va=0x%lx-0x%lx\n", 326 1.1 thorpej km->vstart, km->vend, 327 1.1 thorpej km_next->vstart, km_next->vend); 328 1.1 thorpej goto merge_two; 329 1.1 thorpej } 330 1.1 thorpej 331 1.1 thorpej DPRINTF("!!! extending existing region " 332 1.1 thorpej "va=0x%lx-0x%lx to " 333 1.1 thorpej "va=0x%lx-0x%lx\n", 334 1.1 thorpej km->vstart, km->vend, 335 1.1 thorpej km->vstart, va_end); 336 1.1 thorpej goto extend_existing; 337 1.1 thorpej } 338 1.1 thorpej 339 1.1 thorpej /* 340 1.1 thorpej * We know that the new region starts before the current 341 1.1 thorpej * one. Check to see of the end overlaps. 342 1.1 thorpej */ 343 1.1 thorpej if (va_end >= km->vstart) { 344 1.1 thorpej va_end = km->vstart; 345 1.1 thorpej size = va_end - va; 346 1.1 thorpej 347 1.1 thorpej /* 348 1.1 thorpej * No need to check for a merge here; we would 349 1.1 thorpej * have caught it above. 350 1.1 thorpej */ 351 1.1 thorpej goto prepend_existing; 352 1.1 thorpej } 353 1.1 thorpej 354 1.1 thorpej /* 355 1.1 thorpej * Need to the new region in front of the current one. 356 1.1 thorpej * Make sure there's room. 357 1.1 thorpej */ 358 1.1 thorpej if (km_next == NULL || km_last->vstart != km_last->vend) { 359 1.1 thorpej printf("!!! NO ROOM TO INSERT MAPPING\n"); 360 1.1 thorpej return 1; 361 1.1 thorpej } 362 1.1 thorpej 363 1.1 thorpej if (km_prev == NULL) { 364 1.1 thorpej DPRINTF("!!! entering before 0x%lx-0x%lx\n", 365 1.1 thorpej km->vstart, km->vend); 366 1.1 thorpej } else { 367 1.1 thorpej DPRINTF("!!! entering between 0x%lx-0x%lx and " 368 1.1 thorpej "0x%lx-0x%lx\n", 369 1.1 thorpej km_prev->vstart, km_prev->vend, 370 1.1 thorpej km->vstart, km->vend); 371 1.1 thorpej } 372 1.1 thorpej 373 1.1 thorpej if (ofw_create_mapping(va, va, size) == -1) { 374 1.1 thorpej return 1; 375 1.1 thorpej } 376 1.1 thorpej size = (uintptr_t)(&kmappings[MAX_KMAPPINGS]) - 377 1.1 thorpej (uintptr_t)(km_next + 1); 378 1.1 thorpej memmove(km_next, km, size); 379 1.1 thorpej km->vstart = va; 380 1.1 thorpej km->vend = va_end; 381 1.1 thorpej return 0; 382 1.1 thorpej } 383 1.1 thorpej 384 1.1 thorpej extend_existing: 385 1.1 thorpej if (ofw_create_mapping(va, va, size) == -1) { 386 1.1 thorpej return 1; 387 1.1 thorpej } 388 1.1 thorpej km->vend = va_end; 389 1.1 thorpej return 0; 390 1.1 thorpej 391 1.1 thorpej prepend_existing: 392 1.1 thorpej if (ofw_create_mapping(va, va, size) == -1) { 393 1.1 thorpej return 1; 394 1.1 thorpej } 395 1.1 thorpej km->vstart = va; 396 1.1 thorpej return 0; 397 1.1 thorpej 398 1.1 thorpej enter_new: 399 1.1 thorpej if (ofw_create_mapping(va, va, size) == -1) { 400 1.1 thorpej return 1; 401 1.1 thorpej } 402 1.1 thorpej km->vstart = va; 403 1.1 thorpej km->vend = va_end; 404 1.1 thorpej return 0; 405 1.1 thorpej 406 1.1 thorpej merge_two: 407 1.1 thorpej if (ofw_create_mapping(va, va, size) == -1) { 408 1.1 thorpej return 1; 409 1.1 thorpej } 410 1.1 thorpej km->vend = km_next->vend; 411 1.1 thorpej size = 412 1.1 thorpej (uintptr_t)(&kmappings[MAX_KMAPPINGS]) - (uintptr_t)(km_next + 1); 413 1.1 thorpej if (size != 0) { 414 1.1 thorpej memmove(km_next, km_next + 1, size); 415 1.1 thorpej } 416 1.1 thorpej km_last->vstart = km_last->vend = 0; 417 1.1 thorpej return 0; 418 1.1 thorpej } 419 1.1 thorpej 420 1.1 thorpej /* 421 1.1 thorpej * loadfile() hooks. 422 1.1 thorpej */ 423 1.1 thorpej ssize_t 424 1.1 thorpej macppc_read(int f, void *addr, size_t size) 425 1.1 thorpej { 426 1.1 thorpej if (kmapping_enter((vaddr_t)addr, size)) { 427 1.1 thorpej return -1; 428 1.1 thorpej } 429 1.1 thorpej return read(f, addr, size); 430 1.1 thorpej } 431 1.1 thorpej 432 1.1 thorpej void * 433 1.1 thorpej macppc_memcpy(void *dst, const void *src, size_t size) 434 1.1 thorpej { 435 1.1 thorpej if (kmapping_enter((vaddr_t)dst, size)) { 436 1.1 thorpej panic("macppc_memcpy: kmapping_enter failed"); 437 1.1 thorpej } 438 1.1 thorpej return memcpy(dst, src, size); 439 1.1 thorpej } 440 1.1 thorpej 441 1.1 thorpej void * 442 1.1 thorpej macppc_memset(void *dst, int c, size_t size) 443 1.1 thorpej { 444 1.1 thorpej if (kmapping_enter((vaddr_t)dst, size)) { 445 1.1 thorpej panic("macppc_memset: kmapping_enter failed"); 446 1.1 thorpej } 447 1.1 thorpej return memset(dst, c, size); 448 1.1 thorpej } 449