1 /* $NetBSD: ofw_machdep.c,v 1.36 2022/12/12 13:26:46 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2007, 2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tim Rightnour 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (C) 1996 Wolfgang Solfrank. 34 * Copyright (C) 1996 TooLs GmbH. 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by TooLs GmbH. 48 * 4. The name of TooLs GmbH may not be used to endorse or promote products 49 * derived from this software without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 52 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 53 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 54 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 56 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 57 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 58 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 59 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 60 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: ofw_machdep.c,v 1.36 2022/12/12 13:26:46 martin Exp $"); 65 66 #include <sys/param.h> 67 #include <sys/buf.h> 68 #include <sys/conf.h> 69 #include <sys/device.h> 70 #include <sys/disk.h> 71 #include <sys/disklabel.h> 72 #include <sys/fcntl.h> 73 #include <sys/ioctl.h> 74 #include <sys/stat.h> 75 #include <sys/systm.h> 76 77 #include <dev/cons.h> 78 #include <dev/ofw/openfirm.h> 79 80 #include <machine/powerpc.h> 81 #include <machine/autoconf.h> 82 83 #include <powerpc/ofw_machdep.h> 84 85 #ifdef DEBUG 86 #define DPRINTF ofprint 87 #else 88 #define DPRINTF while(0) printf 89 #endif 90 91 #define ofpanic(FORMAT, ...) do { \ 92 ofprint(FORMAT __VA_OPT__(,) __VA_ARGS__); \ 93 panic(FORMAT __VA_OPT__(,) __VA_ARGS__); \ 94 } while (0) 95 96 int ofw_root; 97 int ofw_chosen; 98 99 bool ofw_real_mode; 100 101 /* 102 * Bootstrap console support functions. 103 */ 104 105 int console_node = -1, console_instance = -1; 106 int ofw_stdin, ofw_stdout; 107 bool ofwbootcons_suppress; 108 109 int ofw_address_cells; 110 int ofw_size_cells; 111 112 void ofprint(const char *blah, ...) 113 { 114 va_list va; 115 char buf[256]; 116 int len; 117 118 va_start(va, blah); 119 len = vsnprintf(buf, sizeof(buf), blah, va); 120 va_end(va); 121 OF_write(console_instance, buf, len); 122 /* Apple OF only does a newline on \n, so add an explicit CR */ 123 if ((len > 0) && (buf[len - 1] == '\n')) 124 OF_write(console_instance, "\r", 1); 125 } 126 127 static int 128 ofwbootcons_cngetc(dev_t dev) 129 { 130 unsigned char ch = '\0'; 131 int l; 132 133 if (ofwbootcons_suppress) { 134 return ch; 135 } 136 137 while ((l = OF_read(ofw_stdin, &ch, 1)) != 1) { 138 if (l != -2 && l != 0) { 139 return -1; 140 } 141 } 142 return ch; 143 } 144 145 static void 146 ofwbootcons_cnputc(dev_t dev, int c) 147 { 148 char ch = c; 149 150 if (ofwbootcons_suppress) { 151 return; 152 } 153 154 OF_write(ofw_stdout, &ch, 1); 155 } 156 157 static struct consdev consdev_ofwbootcons = { 158 .cn_getc = ofwbootcons_cngetc, 159 .cn_putc = ofwbootcons_cnputc, 160 .cn_pollc = nullcnpollc, 161 .cn_dev = NODEV, 162 .cn_pri = CN_INTERNAL, 163 }; 164 165 static void 166 ofw_bootstrap_console(void) 167 { 168 int node; 169 170 if (ofw_chosen == -1) { 171 goto nocons; 172 } 173 174 if (OF_getprop(ofw_chosen, "stdout", &ofw_stdout, 175 sizeof(ofw_stdout)) != sizeof(ofw_stdout)) 176 goto nocons; 177 178 if (OF_getprop(ofw_chosen, "stdin", &ofw_stdin, 179 sizeof(ofw_stdin)) != sizeof(ofw_stdin)) 180 goto nocons; 181 if (ofw_stdout == 0) { 182 /* screen should be console, but it is not open */ 183 ofw_stdout = OF_open("screen"); 184 } 185 node = OF_instance_to_package(ofw_stdout); 186 console_node = node; 187 console_instance = ofw_stdout; 188 189 cn_tab = &consdev_ofwbootcons; 190 191 return; 192 nocons: 193 ofpanic("No /chosen could be found!\n"); 194 console_node = -1; 195 } 196 197 #define OFMEM_REGIONS 32 198 static struct mem_region OFmem[OFMEM_REGIONS + 1], OFavail[OFMEM_REGIONS + 3]; 199 200 static void 201 ofw_bootstrap_get_memory(void) 202 { 203 const char *macrisc[] = {"MacRISC", "MacRISC2", "MacRISC4", NULL}; 204 int hmem, i, cnt, memcnt, regcnt; 205 int numregs; 206 uint32_t regs[OFMEM_REGIONS * 4]; /* 2 values + 2 for 64bit */ 207 208 int acells = ofw_address_cells; 209 int scells = ofw_size_cells; 210 211 DPRINTF("calling mem_regions\n"); 212 213 /* Get memory */ 214 memset(regs, 0, sizeof(regs)); 215 if ((hmem = OF_finddevice("/memory")) == -1) 216 goto error; 217 regcnt = OF_getprop(hmem, "reg", regs, 218 sizeof(regs[0]) * OFMEM_REGIONS * 4); 219 if (regcnt <= 0) 220 goto error; 221 222 /* how many mem regions did we get? */ 223 numregs = regcnt / (sizeof(uint32_t) * (acells + scells)); 224 DPRINTF("regcnt=%d num=%d acell=%d scell=%d\n", 225 regcnt, numregs, acells, scells); 226 227 /* move the data into OFmem */ 228 memset(OFmem, 0, sizeof(OFmem)); 229 for (i = 0, memcnt = 0; i < numregs; i++) { 230 uint64_t addr, size; 231 232 if (acells > 1) 233 memcpy(&addr, ®s[i * (acells + scells)], 234 sizeof(int32_t) * acells); 235 else 236 addr = regs[i * (acells + scells)]; 237 238 if (scells > 1) 239 memcpy(&size, ®s[i * (acells + scells) + acells], 240 sizeof(int32_t) * scells); 241 else 242 size = regs[i * (acells + scells) + acells]; 243 244 /* skip entry of 0 size */ 245 if (size == 0) 246 continue; 247 #ifndef _LP64 248 if (addr > 0xFFFFFFFF || size > 0xFFFFFFFF || 249 (addr + size) > 0xFFFFFFFF) { 250 ofprint("Base addr of %llx or size of %llx too" 251 " large for 32 bit OS. Skipping.", addr, size); 252 continue; 253 } 254 #endif 255 OFmem[memcnt].start = addr; 256 OFmem[memcnt].size = size; 257 DPRINTF("mem region %d start=%"PRIx64" size=%"PRIx64"\n", 258 memcnt, addr, size); 259 memcnt++; 260 } 261 262 DPRINTF("available\n"); 263 264 /* now do the same thing again, for the available counts */ 265 memset(regs, 0, sizeof(regs)); 266 regcnt = OF_getprop(hmem, "available", regs, 267 sizeof(regs[0]) * OFMEM_REGIONS * 4); 268 if (regcnt <= 0) 269 goto error; 270 271 DPRINTF("%08x %08x %08x %08x\n", regs[0], regs[1], regs[2], regs[3]); 272 273 /* 274 * according to comments in FreeBSD all Apple OF has 32bit values in 275 * "available", no matter what the cell sizes are 276 */ 277 if (of_compatible(ofw_root, macrisc)) { 278 DPRINTF("this appears to be a mac...\n"); 279 acells = 1; 280 scells = 1; 281 } 282 283 /* how many mem regions did we get? */ 284 numregs = regcnt / (sizeof(uint32_t) * (acells + scells)); 285 DPRINTF("regcnt=%d num=%d acell=%d scell=%d\n", 286 regcnt, numregs, acells, scells); 287 288 DPRINTF("to OF_avail\n"); 289 290 /* move the data into OFavail */ 291 memset(OFavail, 0, sizeof(OFavail)); 292 for (i = 0, cnt = 0; i < numregs; i++) { 293 uint64_t addr, size; 294 295 DPRINTF("%d\n", i); 296 if (acells > 1) 297 memcpy(&addr, ®s[i * (acells + scells)], 298 sizeof(int32_t) * acells); 299 else 300 addr = regs[i * (acells + scells)]; 301 302 if (scells > 1) 303 memcpy(&size, ®s[i * (acells + scells) + acells], 304 sizeof(int32_t) * scells); 305 else 306 size = regs[i * (acells + scells) + acells]; 307 /* skip entry of 0 size */ 308 if (size == 0) 309 continue; 310 #ifndef _LP64 311 if (addr > 0xFFFFFFFF || size > 0xFFFFFFFF || 312 (addr + size) > 0xFFFFFFFF) { 313 ofprint("Base addr of %llx or size of %llx too" 314 " large for 32 bit OS. Skipping.", addr, size); 315 continue; 316 } 317 #endif 318 OFavail[cnt].start = addr; 319 OFavail[cnt].size = size; 320 DPRINTF("avail region %d start=%#"PRIx64" size=%#"PRIx64"\n", 321 cnt, addr, size); 322 cnt++; 323 } 324 325 if (strncmp(model_name, "Pegasos", 7) == 0) { 326 /* 327 * Some versions of SmartFirmware, only recognize the first 328 * 256MB segment as available. Work around it and add an 329 * extra entry to OFavail[] to account for this. 330 */ 331 #define AVAIL_THRESH (0x10000000-1) 332 if (((OFavail[cnt-1].start + OFavail[cnt-1].size + 333 AVAIL_THRESH) & ~AVAIL_THRESH) < 334 (OFmem[memcnt-1].start + OFmem[memcnt-1].size)) { 335 336 OFavail[cnt].start = 337 (OFavail[cnt-1].start + OFavail[cnt-1].size + 338 AVAIL_THRESH) & ~AVAIL_THRESH; 339 OFavail[cnt].size = 340 OFmem[memcnt-1].size - OFavail[cnt].start; 341 ofprint("WARNING: add memory segment %lx - %" PRIxPADDR "," 342 "\nWARNING: which was not recognized by " 343 "the Firmware.\n", 344 (unsigned long)OFavail[cnt].start, 345 (unsigned long)OFavail[cnt].start + 346 OFavail[cnt].size); 347 cnt++; 348 } 349 } 350 351 return; 352 353 error: 354 #if defined (MAMBO) 355 ofprint("no memory, assuming 512MB\n"); 356 357 OFmem[0].start = 0x0; 358 OFmem[0].size = 0x20000000; 359 360 OFavail[0].start = 0x3000; 361 OFavail[0].size = 0x20000000 - 0x3000; 362 363 #else 364 ofpanic("no memory?"); 365 #endif 366 return; 367 } 368 369 static void 370 ofw_bootstrap_get_translations(void) 371 { 372 /* 5 cells per: virt(1), size(1), phys(2), mode(1) */ 373 uint32_t regs[OFW_MAX_TRANSLATIONS * 5]; 374 uint32_t virt, size, mode; 375 uint64_t phys; 376 uint32_t *rp; 377 int proplen; 378 int mmu_ihandle, mmu_phandle; 379 int idx; 380 381 if (OF_getprop(ofw_chosen, "mmu", &mmu_ihandle, 382 sizeof(mmu_ihandle)) <= 0) { 383 ofprint("No /chosen/mmu\n"); 384 return; 385 } 386 mmu_phandle = OF_instance_to_package(mmu_ihandle); 387 388 proplen = OF_getproplen(mmu_phandle, "translations"); 389 if (proplen <= 0) { 390 ofprint("No translations in /chosen/mmu\n"); 391 return; 392 } 393 394 if (proplen > sizeof(regs)) { 395 ofpanic("/chosen/mmu translations too large"); 396 } 397 398 proplen = OF_getprop(mmu_phandle, "translations", regs, sizeof(regs)); 399 int nregs = proplen / sizeof(regs[0]); 400 401 /* Decode into ofw_translations[]. */ 402 for (idx = 0, rp = regs; rp < ®s[nregs];) { 403 virt = *rp++; 404 size = *rp++; 405 switch (ofw_address_cells) { 406 case 1: 407 phys = *rp++; 408 break; 409 case 2: 410 phys = *rp++; 411 phys = (phys << 32) | *rp++; 412 break; 413 default: 414 ofpanic("unexpected #address-cells"); 415 } 416 mode = *rp++; 417 if (rp > ®s[nregs]) { 418 ofpanic("unexpected OFW translations format"); 419 } 420 421 /* Wouldn't expect this, but... */ 422 if (size == 0) { 423 continue; 424 } 425 426 DPRINTF("translation %d virt=%#"PRIx32 427 " phys=%#"PRIx64" size=%#"PRIx32" mode=%#"PRIx32"\n", 428 idx, virt, phys, size, mode); 429 430 if (sizeof(paddr_t) < 8 && phys >= 0x100000000ULL) { 431 ofpanic("translation phys out of range"); 432 } 433 434 if (idx == OFW_MAX_TRANSLATIONS) { 435 ofpanic("too many OFW translations"); 436 } 437 438 ofw_translations[idx].virt = virt; 439 ofw_translations[idx].size = size; 440 ofw_translations[idx].phys = (paddr_t)phys; 441 ofw_translations[idx].mode = mode; 442 idx++; 443 } 444 } 445 446 static bool 447 ofw_option_truefalse(const char *prop, int proplen) 448 { 449 /* These are all supposed to be strings. */ 450 switch (prop[0]) { 451 case 'y': 452 case 'Y': 453 case 't': 454 case 'T': 455 case '1': 456 return true; 457 } 458 return false; 459 } 460 461 /* 462 * Called from ofwinit() very early in bootstrap. We are still 463 * running on the stack provided by OpenFirmware and in the same 464 * OpenFirmware client environment as the boot loader. Our calls 465 * to OpenFirmware are direct, and not via the trampoline that 466 * saves / restores kernel state. 467 */ 468 void 469 ofw_bootstrap(void) 470 { 471 char prop[32]; 472 int handle, proplen; 473 474 /* Stash the handles for "/" and "/chosen" for convenience later. */ 475 ofw_root = OF_finddevice("/"); 476 ofw_chosen = OF_finddevice("/chosen"); 477 478 /* Initialize the early bootstrap console. */ 479 ofw_bootstrap_console(); 480 481 /* Check to see if we're running in real-mode. */ 482 handle = OF_finddevice("/options"); 483 if (handle != -1) { 484 proplen = OF_getprop(handle, "real-mode?", prop, sizeof(prop)); 485 if (proplen > 0) { 486 ofw_real_mode = ofw_option_truefalse(prop, proplen); 487 } else { 488 ofw_real_mode = false; 489 } 490 } 491 DPRINTF("OpenFirmware running in %s-mode\n", 492 ofw_real_mode ? "real" : "virtual"); 493 494 /* Get #address-cells and #size-cells to fetching memory info. */ 495 if (OF_getprop(ofw_root, "#address-cells", &ofw_address_cells, 496 sizeof(ofw_address_cells)) <= 0) 497 ofw_address_cells = 1; 498 499 if (OF_getprop(ofw_root, "#size-cells", &ofw_size_cells, 500 sizeof(ofw_size_cells)) <= 0) 501 ofw_size_cells = 1; 502 503 /* Get the system memory configuration. */ 504 ofw_bootstrap_get_memory(); 505 506 /* Get any translations used by OpenFirmware. */ 507 ofw_bootstrap_get_translations(); 508 } 509 510 /* 511 * This is called during initppc, before the system is really initialized. 512 * It shall provide the total and the available regions of RAM. 513 * Both lists must have a zero-size entry as terminator. 514 * The available regions need not take the kernel into account, but needs 515 * to provide space for two additional entry beyond the terminating one. 516 */ 517 void 518 mem_regions(struct mem_region **memp, struct mem_region **availp) 519 { 520 *memp = OFmem; 521 *availp = OFavail; 522 } 523 524 void 525 ppc_exit(void) 526 { 527 OF_exit(); 528 } 529 530 void 531 ppc_boot(char *str) 532 { 533 OF_boot(str); 534 } 535