Home | History | Annotate | Line # | Download | only in powerpc
      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, &regs[i * (acells + scells)],
    234 			    sizeof(int32_t) * acells);
    235 		else
    236 			addr = regs[i * (acells + scells)];
    237 
    238 		if (scells > 1)
    239 			memcpy(&size, &regs[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, &regs[i * (acells + scells)],
    298 			    sizeof(int32_t) * acells);
    299 		else
    300 			addr = regs[i * (acells + scells)];
    301 
    302 		if (scells > 1)
    303 			memcpy(&size, &regs[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 < &regs[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 > &regs[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