1 /* $NetBSD: machdep.c,v 1.4 2026/08/02 15:44:21 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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) 1988 University of Utah. 34 * Copyright (c) 1982, 1986, 1990, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * the Systems Programming Group of the University of Utah Computer 39 * Science Department. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * from: Utah $Hdr: machdep.c 1.74 92/12/20$ 66 * 67 * @(#)machdep.c 8.10 (Berkeley) 4/20/94 68 */ 69 70 #include <sys/cdefs.h> 71 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.4 2026/08/02 15:44:21 thorpej Exp $"); 72 73 #include "opt_ddb.h" 74 #include "opt_modular.h" 75 #include "opt_m68k_arch.h" 76 #include "opt_hb68k_config.h" 77 78 #include "ksyms.h" 79 80 #define _M68K_BUS_SPACE_PRIVATE 81 #define _M68K_BUS_DMA_PRIVATE 82 83 #include <sys/param.h> 84 #include <sys/systm.h> 85 #include <sys/kernel.h> 86 #include <sys/reboot.h> 87 #include <sys/conf.h> 88 #include <sys/ksyms.h> 89 #include <sys/module.h> 90 #include <sys/device.h> 91 #include <sys/cpu.h> 92 #include <sys/boot_flag.h> 93 #include <sys/bus.h> 94 95 #include <dev/fdt/fdtvar.h> 96 #include <dev/fdt/fdt_boot.h> 97 #include <dev/fdt/fdt_console.h> 98 #include <dev/fdt/fdt_platform.h> 99 100 #include <dev/ofw/openfirm.h> 101 102 #include <uvm/uvm_extern.h> 103 104 #include <sys/sysctl.h> 105 106 #include <dev/cons.h> 107 108 #if defined(CONFIG_LINUX_BOOTINFO) 109 #include <m68k/linux_bootinfo.h> 110 #endif 111 112 #ifdef DDB 113 #include <machine/db_machdep.h> 114 #include <ddb/db_extern.h> 115 #include <ddb/db_output.h> 116 #endif 117 118 /* Default to the fastest CPU we could have in this configuration. */ 119 #if defined(M68060) 120 #define DELAY_DIVISOR_DEFAULT delay_divisor_est60(80) 121 #elif defined(M68040) 122 #define DELAY_DIVISOR_DEFAULT delay_divisor_est40(33) 123 #elif defined(M68030) 124 #define DELAY_DIVISOR_DEFAULT delay_divisor_est(50) 125 #elif defined(M68020) 126 #define DELAY_DIVISOR_DEFAULT delay_divisor_est(25) 127 #else 128 #define DELAY_DIVISOR_DEFAULT delay_divisor_est(12) 129 #endif 130 131 int delay_divisor = DELAY_DIVISOR_DEFAULT; 132 133 /* Machine-dependent initialization routines. */ 134 void machine_init(paddr_t); 135 136 #if defined(M68K_MMU_MOTOROLA) 137 struct pmap_bootmap machine_bootmap[MACHINE_BOOTMAP_ENTRY_COUNT+1] = { 138 /* 139 * pmap_bootstrap1() will skip any entry with pmbm_size == 0. 140 * The machine-specific bootstrap() function simply needs to 141 * fill in machine_bootmap[] entries it wishes to use. 142 */ 143 [MACHINE_BOOTMAP_ENTRY_COUNT] = { .pmbm_vaddr = -1 } 144 }; 145 #endif /* M68K_MMU_MOTOROLA */ 146 147 bool 148 machine_fdt_init(void *addr) 149 { 150 static bool fdt_initialized; 151 152 if (fdt_initialized) { 153 return true; 154 } 155 156 if (fdtbus_init(addr)) { 157 fdt_initialized = true; 158 } 159 return fdt_initialized; 160 } 161 162 const struct fdt_platform * 163 machine_platform(void) 164 { 165 static const struct fdt_platform *this_plat; 166 167 if (__predict_false(this_plat == NULL)) { 168 this_plat = fdt_platform_find(); 169 } 170 return this_plat; 171 } 172 173 static struct m68k_bus_dma_tag hb68k_simple_dma_tag = { 174 NULL, 175 0, 176 _bus_dmamap_create, 177 _bus_dmamap_destroy, 178 _bus_dmamap_load_direct, 179 _bus_dmamap_load_mbuf_direct, 180 _bus_dmamap_load_uio_direct, 181 _bus_dmamap_load_raw_direct, 182 _bus_dmamap_unload, 183 _bus_dmamap_sync, 184 _bus_dmamem_alloc, 185 _bus_dmamem_free, 186 _bus_dmamem_map, 187 _bus_dmamem_unmap, 188 _bus_dmamem_mmap 189 }; 190 191 bus_dma_tag_t 192 fdtbus_dma_tag_create(int phandle, const struct fdt_dma_range *ranges, 193 u_int nranges) 194 { 195 KASSERT(nranges == 0); 196 return &hb68k_simple_dma_tag; 197 } 198 199 bus_space_tag_t 200 fdtbus_bus_tag_create(int phandle, uint32_t flags) 201 { 202 return &m68k_simple_bus_space; 203 } 204 205 void 206 machine_init_attach_args(struct fdt_attach_args *faa) 207 { 208 memset(faa, 0, sizeof(*faa)); 209 210 faa->faa_bst = &m68k_simple_bus_space; 211 faa->faa_dmat = &hb68k_simple_dma_tag; 212 } 213 214 #if NKSYMS || defined(DDB) || defined(MODULAR) 215 vaddr_t ksym_start, ksym_end; 216 217 static bool 218 machine_find_ksyms(void) 219 { 220 /* 221 * If they've already been found, then no more work to do! 222 */ 223 if (ksym_end - ksym_start != 0) { 224 return true; 225 } 226 227 #if defined(CONFIG_LINUX_BOOTINFO) 228 struct bootinfo_data *bid = bootinfo_data(); 229 if (bid->bootinfo_ksym_size != 0) { 230 ksym_start = bid->bootinfo_ksym_start; 231 ksym_end = ksym_start + bid->bootinfo_ksym_size; 232 return true; 233 } 234 #endif 235 236 return false; 237 } 238 #endif /* NKSYMS || DDB || MODULAR */ 239 240 static const char * 241 machine_parse_bootflags(const char *cp) 242 { 243 while (*cp != '\0') { 244 if (*cp == ' ' || *cp == '\t') { 245 break; 246 } 247 BOOT_FLAG(*cp, boothowto); 248 cp++; 249 } 250 return cp; 251 } 252 253 static void 254 machine_parse_cmdline(void) 255 { 256 /* 257 * We are pretty flexible with what we accept. Here, we're 258 * just interested in boot flags, so we can do: 259 * 260 * flags=... 261 * -or- 262 * -... 263 * 264 * Or any combination of that, really. 265 * 266 * We also notice root= and pass that to machine_set_bootspec(). 267 */ 268 const char *cp = NULL; 269 270 #if defined(CONFIG_LINUX_BOOTINFO) 271 if (cp == NULL) { 272 struct bi_record *bi = bootinfo_find(BI_COMMAND_LINE); 273 if (bi != NULL) { 274 cp = bootinfo_dataptr(bi); 275 } 276 } 277 #endif 278 if (cp == NULL) { 279 cp = fdt_get_bootargs(); 280 } 281 282 if (cp == NULL) { 283 return; 284 } 285 286 while (*cp != '\0') { 287 if (*cp == '-') { 288 cp = machine_parse_bootflags(cp + 1); 289 continue; 290 } 291 if (strncmp(cp, "flags=", 6) == 0) { 292 cp = machine_parse_bootflags(cp + 6); 293 continue; 294 } 295 if (strncmp(cp, "root=", 5) == 0) { 296 cp = machine_set_bootspec(cp + 5); 297 continue; 298 } 299 cp++; 300 } 301 } 302 303 /* 304 * Early initialization, right before main is called. 305 */ 306 void 307 machine_init(paddr_t nextpa) 308 { 309 int phandle; 310 uint32_t val; 311 312 #if defined(CONFIG_LINUX_BOOTINFO) 313 /* 314 * For the FDT machtype, the device tree is passed as a 315 * blob directly in the bootinfo. 316 */ 317 struct bi_record *bi = 318 bootinfo_find_machdep(BI_MACH_FDT, BI_FDT_BLOB); 319 if (bi != NULL) { 320 struct bi_data *d = bootinfo_dataptr(bi); 321 machine_fdt_init(&d->data_bytes[0]); 322 } 323 #endif 324 325 const struct fdt_platform *plat = machine_platform(); 326 if (plat->fp_machine_init != NULL) { 327 nextpa = plat->fp_machine_init(nextpa); 328 } 329 330 phandle = OF_finddevice("/cpus/cpu@0"); 331 if (phandle >= 0 && 332 of_getprop_uint32(phandle, "clock-frequency", &val) != -1) { 333 cpuspeed_khz = val / 1000; 334 335 /* 336 * Set initial delay divisor; this may get properly 337 * calibrated later. 338 */ 339 switch (cputype) { 340 #ifdef M68060 341 case CPU_68060: 342 delay_divisor = 343 delay_divisor_est60(cpuspeed_khz / 1000); 344 break; 345 #endif 346 #ifdef M68040 347 case CPU_68040: 348 delay_divisor = 349 delay_divisor_est40(cpuspeed_khz / 1000); 350 break; 351 #endif 352 default: 353 delay_divisor = 354 delay_divisor_est(cpuspeed_khz / 1000); 355 break; 356 } 357 } 358 359 #if defined(CONFIG_LINUX_BOOTINFO) 360 /* 361 * Pass 2 at parsing bootinfo now that the MMU is enabled. 362 */ 363 bootinfo_startup2(nextpa); 364 #endif 365 366 /* 367 * Just use the default pager_map_size for now. We may decide 368 * to make it larger for large memory configs. 369 */ 370 371 machine_init_common(nextpa); 372 373 machine_parse_cmdline(); 374 } 375 376 /* 377 * Console initialization: called early on from main, 378 * before vm init or startup. Do enough configuration 379 * to choose and initialize a console. 380 */ 381 void 382 consinit(void) 383 { 384 static bool initialized = false; 385 const struct fdt_platform *plat = machine_platform(); 386 const struct fdt_console *cons = fdtbus_get_console(); 387 const int phandle = fdtbus_get_stdout_phandle(); 388 struct fdt_attach_args faa; 389 u_int uart_freq = 0; 390 391 if (initialized || cons == NULL) { 392 return; 393 } 394 395 machine_init_attach_args(&faa); 396 397 if (of_getprop_uint32(phandle, "clock-frequency", &uart_freq)) { 398 if (plat->fp_uart_freq != NULL) { 399 uart_freq = plat->fp_uart_freq(); 400 } 401 } 402 403 faa.faa_phandle = phandle; 404 cons->consinit(&faa, uart_freq); 405 406 initialized = true; 407 408 #if NKSYMS || defined(DDB) || defined(MODULAR) 409 /* 410 * Add kernel symbols now because traditionally consinit() 411 * is the boot-into-debugger hook. 412 */ 413 if (machine_find_ksyms()) { 414 ksyms_addsyms_elf(ksym_end - ksym_start, 415 (void *)ksym_start, (void *)ksym_end); 416 } 417 #endif 418 #ifdef DDB 419 if (boothowto & RB_KDB) 420 Debugger(); 421 #endif 422 } 423 424 /* 425 * cpu_startup: allocate memory for variable-sized tables, 426 * initialize CPU, and do autoconfiguration. 427 */ 428 void 429 cpu_startup(void) 430 { 431 432 cpu_startup_common(); 433 434 #if defined(CONFIG_LINUX_BOOTINFO) 435 struct bootinfo_data *bid = bootinfo_data(); 436 if (bid->bootinfo_mem_segments_ignored) { 437 printf("WARNING: ignored %zd bytes of memory in %d segments.\n", 438 bid->bootinfo_mem_segments_ignored_bytes, 439 bid->bootinfo_mem_segments_ignored); 440 } 441 #endif 442 } 443 444 void 445 machine_set_model(void) 446 { 447 int phandle; 448 char buf[40]; 449 450 phandle = OF_finddevice("/"); 451 if (phandle < 0 || 452 OF_getprop(phandle, "model", buf, sizeof(buf)) < 0) { 453 cpu_setmodel("Unknown Homebrew"); 454 } else { 455 cpu_setmodel("%s", buf); 456 } 457 } 458 459 /* 460 * machine dependent system variables. 461 */ 462 SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup") 463 { 464 sysctl_createv(clog, 0, NULL, NULL, 465 CTLFLAG_PERMANENT, 466 CTLTYPE_NODE, "machdep", NULL, 467 NULL, 0, NULL, 0, 468 CTL_MACHDEP, CTL_EOL); 469 470 sysctl_createv(clog, 0, NULL, NULL, 471 CTLFLAG_PERMANENT, 472 CTLTYPE_STRUCT, "console_device", NULL, 473 sysctl_consdev, 0, NULL, sizeof(dev_t), 474 CTL_MACHDEP, CPU_CONSDEV, CTL_EOL); 475 } 476 477 void 478 machine_powerdown(void) 479 { 480 const struct fdt_platform *plat = machine_platform(); 481 482 if (plat->fp_powerdown != NULL) { 483 (*plat->fp_powerdown)(); 484 } else { 485 machine_powerdown_default(); 486 } 487 } 488 489 void 490 machine_halt(void) 491 { 492 const struct fdt_platform *plat = machine_platform(); 493 494 if (plat->fp_halt != NULL) { 495 (*plat->fp_halt)(); 496 } else { 497 machine_halt_default(); 498 } 499 } 500 501 void 502 machine_reboot(int howto, char *bootstr) 503 { 504 const struct fdt_platform *plat = machine_platform(); 505 506 if (plat->fp_reboot != NULL) { 507 (*plat->fp_reboot)(howto, bootstr); 508 } 509 } 510 511 /* 512 * Level 7 interrupts are caused by e.g. the ABORT switch. 513 * 514 * If we have DDB, then break into DDB on ABORT. In a production 515 * environment, bumping the ABORT switch would be bad, so we enable 516 * panic'ing on ABORT with the kernel option "PANICBUTTON". 517 */ 518 int 519 nmihand(void *arg) 520 { 521 522 printf("NMI ignored.\n"); 523 524 return 1; 525 } 526