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 
ofprint(const char * blah,...)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
ofwbootcons_cngetc(dev_t dev)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
ofwbootcons_cnputc(dev_t dev,int c)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
ofw_bootstrap_console(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
ofw_bootstrap_get_memory(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
ofw_bootstrap_get_translations(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
ofw_option_truefalse(const char * prop,int proplen)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
ofw_bootstrap(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
mem_regions(struct mem_region ** memp,struct mem_region ** availp)518 mem_regions(struct mem_region **memp, struct mem_region **availp)
519 {
520           *memp = OFmem;
521           *availp = OFavail;
522 }
523 
524 void
ppc_exit(void)525 ppc_exit(void)
526 {
527           OF_exit();
528 }
529 
530 void
ppc_boot(char * str)531 ppc_boot(char *str)
532 {
533           OF_boot(str);
534 }
535