1 /* $NetBSD: machdep.c,v 1.256 2024/03/05 14:15:34 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department, The Mach Operating System project at 11 * Carnegie-Mellon University and Ralph Campbell. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 38 * from: Utah Hdr: machdep.c 1.63 91/04/24 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.256 2024/03/05 14:15:34 thorpej Exp $"); 43 44 #include "opt_ddb.h" 45 #include "opt_modular.h" 46 #define _PMAX_BUS_DMA_PRIVATE 47 48 49 #include <sys/param.h> 50 #include <sys/boot_flag.h> 51 #include <sys/buf.h> 52 #include <sys/bus.h> 53 #include <sys/device.h> 54 #include <sys/kcore.h> 55 #include <sys/kernel.h> 56 #include <sys/ksyms.h> 57 #include <sys/mount.h> 58 #include <sys/proc.h> 59 #include <sys/reboot.h> 60 #include <sys/systm.h> 61 #include <sys/cpu.h> 62 63 #include <uvm/uvm_extern.h> 64 65 #include <dev/cons.h> 66 67 #include <ufs/mfs/mfs_extern.h> /* mfs_initminiroot() */ 68 69 #include <mips/cache.h> 70 #include <mips/locore.h> 71 #include <mips/regnum.h> 72 #include <mips/psl.h> 73 74 #include <pmax/autoconf.h> 75 #include <pmax/dec_prom.h> 76 #include <pmax/sysconf.h> 77 #include <pmax/bootinfo.h> 78 79 #include <pmax/pmax/machdep.h> 80 81 #if NKSYMS || defined(DDB) || defined(MODULAR) 82 #include <mips/db_machdep.h> 83 #include <ddb/db_extern.h> 84 #endif 85 86 #include "opt_dec_3min.h" 87 #include "opt_dec_maxine.h" 88 #include "opt_dec_3maxplus.h" 89 #include "ksyms.h" 90 91 unsigned int ssir; /* simulated interrupt register */ 92 93 /* maps for VM objects */ 94 struct vm_map *phys_map = NULL; 95 96 int systype; /* mother board type */ 97 char *bootinfo = NULL; /* pointer to bootinfo structure */ 98 int cpuspeed = 30; /* approx # instr per usec. */ 99 intptr_t physmem_boardmax; /* {model,SIMM}-specific bound on physmem */ 100 int mem_cluster_cnt; 101 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 102 103 void mach_init(int, int32_t *, int, intptr_t, u_int, char *); /* XXX */ 104 105 /* Motherboard or system-specific initialization vector */ 106 static void unimpl_bus_reset(void); 107 static void unimpl_cons_init(void); 108 static void unimpl_iointr(uint32_t, vaddr_t, uint32_t); 109 static void unimpl_intr_establish(device_t, void *, int, 110 int (*)(void *), void *); 111 static int unimpl_memsize(void *); 112 static unsigned nullwork(void); 113 114 struct platform platform = { 115 "iobus not set", 116 unimpl_bus_reset, 117 unimpl_cons_init, 118 unimpl_iointr, 119 unimpl_intr_establish, 120 unimpl_memsize, 121 (void *)nullwork, 122 }; 123 124 extern void *esym; /* XXX */ 125 extern struct consdev promcd; /* XXX */ 126 127 #define ARGV(i) ((char *)(intptr_t)(argv32[i])) 128 129 /* 130 * Do all the stuff that locore normally does before calling main(). 131 * The first 4 arguments are passed by PROM monitor, and remaining two 132 * are built on temporary stack by our boot loader (or in reg if N32/N64). 133 */ 134 void 135 mach_init(int argc, int32_t *argv32, int code, intptr_t cv, u_int bim, char *bip) 136 { 137 char *cp; 138 const char *bootinfo_msg; 139 int i; 140 char *kernend; 141 #if NKSYMS || defined(DDB) || defined(MODULAR) 142 void *ssym = 0; 143 struct btinfo_symtab *bi_syms; 144 #endif 145 extern char edata[], end[]; /* XXX */ 146 147 /* Set up bootinfo structure looking at stack. */ 148 if (bim == BOOTINFO_MAGIC) { 149 struct btinfo_magic *bi_magic; 150 151 bootinfo = bip; 152 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 153 if (bi_magic == NULL || bi_magic->magic != BOOTINFO_MAGIC) 154 bootinfo_msg = 155 "invalid magic number in bootinfo structure.\n"; 156 else 157 bootinfo_msg = NULL; 158 } 159 else 160 bootinfo_msg = "invalid bootinfo pointer (old bootblocks?)\n"; 161 162 /* clear the BSS segment */ 163 #if NKSYMS || defined(DDB) || defined(MODULAR) 164 bi_syms = lookup_bootinfo(BTINFO_SYMTAB); 165 #ifdef EXEC_AOUT 166 struct exec *aout = (struct exec *)edata; 167 #endif 168 169 /* Was it a valid bootinfo symtab info? */ 170 if (bi_syms != NULL) { 171 ssym = (void *)(intptr_t)bi_syms->ssym; 172 esym = (void *)(intptr_t)bi_syms->esym; 173 174 if (esym < (void *)end) { 175 /* protect against bogus bootinfo data */ 176 kernend = end; 177 } else { 178 kernend = esym; 179 } 180 kernend = (void *)mips_round_page(kernend); 181 #if 0 /* our bootloader clears BSS properly */ 182 memset(edata, 0, end - edata); 183 #endif 184 } else 185 #ifdef EXEC_AOUT 186 /* XXX: Backwards compatibility with old bootblocks - this should 187 * go soon... 188 */ 189 /* Exec header and symbols? */ 190 if (aout->a_midmag == 0x07018b00 && (i = aout->a_syms) != 0) { 191 ssym = end; 192 i += (*(long *)(end + i + 4) + 3) & ~3; /* strings */ 193 esym = end + i + 4; 194 kernend = (void *)mips_round_page(esym); 195 memset(edata, 0, end - edata); 196 } else 197 #endif 198 #endif 199 { 200 kernend = (void *)mips_round_page(end); 201 memset(edata, 0, kernend - edata); 202 } 203 204 /* Initialize callv so we can do PROM output... */ 205 if (code == DEC_PROM_MAGIC) { 206 #ifdef _LP64 207 /* 208 * Convert the call vector from using 32bit function pointers 209 * to using 64bit function pointers. 210 */ 211 for (i = 0; i < sizeof(callvec) / sizeof(void *); i++) 212 ((intptr_t *)&callvec)[i] = ((int32_t *)cv)[i]; 213 callv = &callvec; 214 #else 215 callv = (void *)cv; 216 #endif 217 } else { 218 callv = &callvec; 219 } 220 221 #ifdef DDB 222 /* Make DDB "machine reset" call emulate pushing the HALT button. */ 223 cpu_reset_address = prom_haltbutton; 224 #endif 225 226 /* Use PROM console output until we initialize a console driver. */ 227 cn_tab = &promcd; 228 229 #if 0 230 if (bootinfo_msg != NULL) 231 printf(bootinfo_msg); 232 #else 233 __USE(bootinfo_msg); 234 #endif 235 uvm_md_init(); 236 237 /* 238 * Copy exception-dispatch code down to exception vector. 239 * Initialize locore-function vector. 240 * Clear out the I and D caches. 241 */ 242 mips_vector_init(NULL, false); 243 244 /* 245 * We know the CPU type now. Initialize our DMA tags (might 246 * need this early, for certain types of console devices!!). 247 */ 248 pmax_bus_dma_init(); 249 250 /* Check for direct boot from DS5000 REX monitor */ 251 if (argc > 0 && strcmp(ARGV(0), "boot") == 0) { 252 argc--; 253 argv32++; 254 } 255 256 /* Look at argv[0] and compute bootdev */ 257 makebootdev(ARGV(0)); 258 259 /* 260 * Look at arguments passed to us and compute boothowto. 261 */ 262 boothowto = RB_SINGLE; 263 #ifdef KADB 264 boothowto |= RB_KDB; 265 #endif 266 for (i = 1; i < argc; i++) { 267 for (cp = ARGV(i); *cp; cp++) { 268 switch (*cp) { 269 case 'a': /* autoboot */ 270 boothowto &= ~RB_SINGLE; 271 break; 272 273 case 'n': /* ask for names */ 274 boothowto |= RB_ASKNAME; 275 break; 276 277 case 'N': /* don't ask for names */ 278 boothowto &= ~RB_ASKNAME; 279 break; 280 281 default: 282 BOOT_FLAG(*cp, boothowto); 283 break; 284 } 285 } 286 } 287 288 /* 289 * Check to see if a mini-root was loaded into memory. It resides 290 * at the start of the next page just after the end of BSS. 291 */ 292 if (boothowto & RB_MINIROOT) 293 kernend += round_page(mfs_initminiroot(kernend)); 294 295 #if NKSYMS || defined(DDB) || defined(MODULAR) 296 /* init symbols if present */ 297 if (esym) 298 ksyms_addsyms_elf((char *)esym - (char *)ssym, ssym, esym); 299 #endif 300 #ifdef DDB 301 if (boothowto & RB_KDB) 302 Debugger(); 303 #endif 304 305 /* 306 * We need to do this early for badaddr(). 307 */ 308 lwp0.l_addr = (struct user *)kernend; 309 kernend += USPACE; 310 mips_init_lwp0_uarea(); 311 312 /* 313 * Initialize physmem_boardmax; assume no SIMM-bank limits. 314 * Adjust later in model-specific code if necessary. 315 */ 316 physmem_boardmax = MIPS_MAX_MEM_ADDR; 317 318 /* 319 * Determine what model of computer we are running on. 320 */ 321 systype = ((prom_systype() >> 16) & 0xff); 322 if (systype >= nsysinit) { 323 platform_not_supported(); 324 /* NOTREACHED */ 325 } 326 327 /* Machine specific initialization. */ 328 (*sysinit[systype].init)(); 329 330 /* Find out how much memory is available. */ 331 physmem = (*platform.memsize)(kernend); 332 333 /* 334 * Load the rest of the available pages into the VM system. 335 * Put the first 8M of RAM onto a lower-priority free list, since 336 * some TC boards (e.g. PixelStamp boards) are only able to DMA 337 * into this region, and we want them to have a fighting chance of 338 * allocating their DMA memory during autoconfiguration. 339 */ 340 for (i = 0, physmem = 0; i < mem_cluster_cnt; ++i) { 341 physmem += atop(mem_clusters[i].size); 342 } 343 344 static const struct mips_vmfreelist first8 = { 345 .fl_start = 0, 346 .fl_end = 8 * 1024 * 1024, 347 .fl_freelist = VM_FREELIST_FIRST8 348 }; 349 mips_page_physload(MIPS_KSEG0_START, (vaddr_t)kernend, 350 mem_clusters, mem_cluster_cnt, &first8, 1); 351 352 353 /* 354 * Initialize error message buffer (at end of core). 355 */ 356 mips_init_msgbuf(); 357 358 /* 359 * Initialize the virtual memory system. 360 */ 361 pmap_bootstrap(); 362 } 363 364 void 365 mips_machdep_cache_config(void) 366 { 367 /* All r4k pmaxen have a 1MB L2 cache. */ 368 if (CPUISMIPS3) 369 mips_cache_info.mci_sdcache_size = 1024 * 1024; 370 } 371 372 void 373 consinit(void) 374 { 375 376 (*platform.cons_init)(); 377 } 378 379 /* 380 * Machine-dependent startup code: allocate memory for variable-sized 381 * tables. 382 */ 383 void 384 cpu_startup(void) 385 { 386 cpu_startup_common(); 387 } 388 389 /* 390 * Look up information in bootinfo of boot loader. 391 */ 392 void * 393 lookup_bootinfo(int type) 394 { 395 struct btinfo_common *bt; 396 char *help = bootinfo; 397 398 /* Check for a bootinfo record first. */ 399 if (help == NULL) 400 return (NULL); 401 402 do { 403 bt = (struct btinfo_common *)help; 404 if (bt->type == type) 405 return ((void *)help); 406 help += bt->next; 407 } while (bt->next != 0 && 408 (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); 409 410 return (NULL); 411 } 412 413 void 414 cpu_reboot(int howto, char *bootstr) 415 { 416 417 /* take a snap shot before clobbering any registers */ 418 savectx(curpcb); 419 420 #ifdef DEBUG 421 if (panicstr) 422 stacktrace(); 423 #endif 424 425 /* If system is cold, just halt. */ 426 if (cold) { 427 howto |= RB_HALT; 428 goto haltsys; 429 } 430 431 /* If "always halt" was specified as a boot flag, obey. */ 432 if ((boothowto & RB_HALT) != 0) 433 howto |= RB_HALT; 434 435 boothowto = howto; 436 if ((howto & RB_NOSYNC) == 0) { 437 /* 438 * Synchronize the disks.... 439 */ 440 vfs_shutdown(); 441 } 442 443 /* Disable interrupts. */ 444 splhigh(); 445 446 /* If rebooting and a dump is requested do it. */ 447 #if 0 448 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 449 #else 450 if ((howto & RB_DUMP) != 0) 451 #endif 452 dumpsys(); 453 454 haltsys: 455 456 /* run any shutdown hooks */ 457 doshutdownhooks(); 458 459 pmf_system_shutdown(boothowto); 460 461 /* Finally, halt/reboot the system. */ 462 printf("%s\n\n", ((howto & RB_HALT) != 0) ? "halted." : "rebooting..."); 463 prom_halt(howto & RB_HALT, bootstr); 464 /*NOTREACHED*/ 465 } 466 467 /* 468 * Find out how much memory is available by testing memory. 469 * Be careful to save and restore the original contents for msgbuf. 470 */ 471 int 472 memsize_scan(void *first) 473 { 474 int i, mem; 475 char *cp; 476 477 mem = btoc((paddr_t)first - MIPS_KSEG0_START); 478 cp = (char *)MIPS_PHYS_TO_KSEG1(mem << PGSHIFT); 479 while (cp < (char *)physmem_boardmax) { 480 int j; 481 if (badaddr(cp, 4)) 482 break; 483 i = *(int *)cp; 484 j = ((int *)cp)[4]; 485 *(int *)cp = 0xa5a5a5a5; 486 /* 487 * Data will persist on the bus if we read it right away. 488 * Have to be tricky here. 489 */ 490 ((int *)cp)[4] = 0x5a5a5a5a; 491 wbflush(); 492 if (*(int *)cp != 0xa5a5a5a5) 493 break; 494 *(int *)cp = i; 495 ((int *)cp)[4] = j; 496 cp += PAGE_SIZE; 497 mem++; 498 } 499 500 /* 501 * Now that we know how much memory we have, initialize the 502 * mem cluster array. 503 */ 504 mem_clusters[0].start = 0; /* XXX is this correct? */ 505 mem_clusters[0].size = ctob(mem); 506 mem_cluster_cnt = 1; 507 508 /* clear any memory error conditions possibly caused by probe */ 509 (*platform.bus_reset)(); 510 return (mem); 511 } 512 513 /* 514 * Find out how much memory is available by using the PROM bitmap. 515 */ 516 int 517 memsize_bitmap(void *first) 518 { 519 memmap *prom_memmap = (memmap *)first; 520 int i, mapbytes; 521 int segstart, curaddr, xsize, segnum; 522 523 mapbytes = prom_getbitmap(prom_memmap); 524 if (mapbytes == 0) 525 return (memsize_scan(first)); 526 527 segstart = curaddr = i = segnum = 0; 528 xsize = prom_memmap->pagesize * 8; 529 while (i < mapbytes) { 530 while (i < mapbytes && prom_memmap->bitmap[i] == 0xff) { 531 ++i; 532 curaddr += xsize; 533 } 534 if (curaddr > segstart) { 535 mem_clusters[segnum].start = segstart; 536 mem_clusters[segnum].size = curaddr - segstart; 537 ++segnum; 538 } 539 while (i < mapbytes && prom_memmap->bitmap[i] != 0xff) { 540 ++i; 541 curaddr += xsize; 542 } 543 segstart = curaddr; 544 } 545 mem_cluster_cnt = segnum; 546 for (i = 0; i < segnum; ++i) { 547 printf("segment %2d start %08lx size %08lx\n", i, 548 (long)mem_clusters[i].start, (long)mem_clusters[i].size); 549 } 550 return (mapbytes * 8); 551 } 552 553 /* 554 * Ensure all platform vectors are always initialized. 555 */ 556 static void 557 unimpl_bus_reset(void) 558 { 559 560 panic("sysconf.init didn't set bus_reset"); 561 } 562 563 static void 564 unimpl_cons_init(void) 565 { 566 567 panic("sysconf.init didn't set cons_init"); 568 } 569 570 static void 571 unimpl_iointr(uint32_t status, vaddr_t pc, uint32_t ipending) 572 { 573 574 panic("sysconf.init didn't set intr"); 575 } 576 577 static void 578 unimpl_intr_establish(device_t dev, void *cookie, int level, 579 int (*handler)(void *), void *arg) 580 { 581 panic("sysconf.init didn't set intr_establish"); 582 } 583 584 static int 585 unimpl_memsize(void *first) 586 { 587 588 panic("sysconf.init didn't set memsize"); 589 } 590 591 static unsigned 592 nullwork(void) 593 { 594 595 return (0); 596 } 597 598 /* 599 * Wait "n" microseconds. (scsi code needs this). 600 */ 601 void 602 delay(int n) 603 { 604 605 DELAY(n); 606 } 607