1/* $NetBSD: machdep.c,v 1.123 2024/03/05 14:15:33 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 */ 39 40#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 41 42__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.123 2024/03/05 14:15:33 thorpej Exp $"); 43 44/* from: Utah Hdr: machdep.c 1.63 91/04/24 */ 45 46#include "opt_ddb.h" 47#include "opt_execfmt.h" 48#include "opt_modular.h" 49 50#define __INTR_PRIVATE 51 52#include <sys/param.h> 53#include <sys/systm.h> 54#include <sys/signalvar.h> 55#include <sys/kernel.h> 56#include <sys/proc.h> 57#include <sys/buf.h> 58#include <sys/reboot.h> 59#include <sys/conf.h> 60#include <sys/file.h> 61#include <sys/mbuf.h> 62#include <sys/msgbuf.h> 63#include <sys/ioctl.h> 64#include <sys/device.h> 65#include <sys/exec.h> 66#include <sys/mount.h> 67#include <sys/syscallargs.h> 68#include <sys/kcore.h> 69#include <sys/ksyms.h> 70#include <sys/cpu.h> 71#include <sys/intr.h> 72 73#include <uvm/uvm_extern.h> 74 75#include <ufs/mfs/mfs_extern.h> /* mfs_initminiroot() */ 76 77#include <mips/cache.h> 78#include <mips/locore.h> 79 80#include <machine/reg.h> 81#include <machine/psl.h> 82#include <machine/pte.h> 83#include <machine/autoconf.h> 84#include <machine/bootinfo.h> 85#include <machine/apbus.h> 86#include <machine/apcall.h> 87 88 89#define _NEWSMIPS_BUS_DMA_PRIVATE 90#include <machine/bus.h> 91 92#ifdef DDB 93#include <machine/db_machdep.h> 94#include <ddb/db_access.h> 95#include <ddb/db_extern.h> 96#include <ddb/db_sym.h> 97#endif 98 99#include <machine/adrsmap.h> 100#include <machine/machConst.h> 101#include <newsmips/newsmips/machid.h> 102#include <dev/cons.h> 103 104#include "ksyms.h" 105 106/* maps for VM objects */ 107 108struct vm_map *phys_map = NULL; 109 110char *bootinfo = NULL; /* pointer to bootinfo structure */ 111int systype; /* what type of NEWS we are */ 112struct apbus_sysinfo *_sip = NULL; 113void *sccport0a; 114 115phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 116int mem_cluster_cnt; 117 118struct idrom idrom; 119void (*hardware_intr)(int, vaddr_t, uint32_t); 120void (*enable_intr)(void); 121void (*disable_intr)(void); 122void (*enable_timer)(void); 123 124/* 125 * Local functions. 126 */ 127 128/* initialize bss, etc. from kernel start, before main() is called. */ 129void mach_init(int, int, int, int); 130 131void prom_halt(int) __attribute__((__noreturn__)); 132void to_monitor(int) __attribute__((__noreturn__)); 133 134#ifdef DEBUG 135/* stacktrace code violates prototypes to get callee's registers */ 136extern void stacktrace(void); /*XXX*/ 137#endif 138 139extern u_long bootdev; 140extern char edata[], end[]; 141 142/* 143 * Do all the stuff that locore normally does before calling main(). 144 * Process arguments passed to us by the prom monitor. 145 * Return the first page address following the system. 146 */ 147void 148mach_init(int x_boothowto, int x_bootdev, int x_bootname, int x_maxmem) 149{ 150 u_long first, last; 151 char *kernend; 152 const char *model; 153 struct btinfo_magic *bi_magic; 154 struct btinfo_bootarg *bi_arg; 155 struct btinfo_systype *bi_systype; 156#if NKSYMS || defined(DDB) || defined(MODULAR) 157 struct btinfo_symtab *bi_sym; 158 int nsym = 0; 159 char *ssym, *esym; 160 161 ssym = esym = NULL; /* XXX: gcc */ 162#endif 163 bi_arg = NULL; 164 165 bootinfo = (void *)BOOTINFO_ADDR; /* XXX */ 166 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 167 if (bi_magic && bi_magic->magic == BOOTINFO_MAGIC) { 168 bi_arg = lookup_bootinfo(BTINFO_BOOTARG); 169 if (bi_arg) { 170 x_boothowto = bi_arg->howto; 171 x_bootdev = bi_arg->bootdev; 172 x_maxmem = bi_arg->maxmem; 173 } 174#if NKSYMS || defined(DDB) || defined(MODULAR) 175 bi_sym = lookup_bootinfo(BTINFO_SYMTAB); 176 if (bi_sym) { 177 nsym = bi_sym->nsym; 178 ssym = (void *)bi_sym->ssym; 179 esym = (void *)bi_sym->esym; 180 } 181#endif 182 183 bi_systype = lookup_bootinfo(BTINFO_SYSTYPE); 184 if (bi_systype) 185 systype = bi_systype->type; 186 } else { 187 /* 188 * Running kernel is loaded by non-native loader; 189 * clear the BSS segment here. 190 */ 191 memset(edata, 0, end - edata); 192 } 193 194 if (systype == 0) 195 systype = NEWS3400; /* XXX compatibility for old boot */ 196 197#ifdef news3400 198 if (systype == NEWS3400) { 199 sccport0a = (void *)SCCPORT0A; 200 } 201#endif 202 203#if defined(news5000) || defined(news4000) 204 if (systype == NEWS5000 || systype == NEWS4000) { 205 int i; 206 char *bspec = (char *)x_bootdev; 207 208 if (bi_arg == NULL) 209 panic("%s requires BTINFO_BOOTARG to boot", 210 systype == NEWS5000 ? "news5000" : "news4000"); 211 212 _sip = (void *)bi_arg->sip; 213 x_maxmem = _sip->apbsi_memsize; 214 x_maxmem -= 0x00100000; /* reserve 1MB for ROM monitor */ 215 if (strncmp(bspec, "scsi", 4) == 0) { 216 x_bootdev = (5 << 28) | 0; /* magic, sd */ 217 bspec += 4; 218 if (*bspec != '(' /*)*/) 219 goto bootspec_end; 220 i = strtoul(bspec + 1, &bspec, 10); 221 x_bootdev |= (i << 24); /* bus */ 222 if (*bspec != ',') 223 goto bootspec_end; 224 i = strtoul(bspec + 1, &bspec, 10); 225 x_bootdev |= (i / 10) << 20; /* controller */ 226 x_bootdev |= (i % 10) << 16; /* unit */ 227 if (*bspec != ',') 228 goto bootspec_end; 229 i = strtoul(bspec + 1, &bspec, 10); 230 x_bootdev |= (i << 8); /* partition */ 231 } 232 bootspec_end: 233 sccport0a = (systype == NEWS5000) ? 234 (void *)NEWS5000_SCCPORT0A : (void *)NEWS4000_SCCPORT0A; 235 consinit(); 236 } 237#endif /* news5000 || news4000 */ 238 239 /* 240 * Save parameters into kernel work area. 241 */ 242 *(int *)(MIPS_PHYS_TO_KSEG1(MACH_MAXMEMSIZE_ADDR)) = x_maxmem; 243 *(int *)(MIPS_PHYS_TO_KSEG1(MACH_BOOTDEV_ADDR)) = x_bootdev; 244 *(int *)(MIPS_PHYS_TO_KSEG1(MACH_BOOTSW_ADDR)) = x_boothowto; 245 246 kernend = (char *)mips_round_page(end); 247#if NKSYMS || defined(DDB) || defined(MODULAR) 248 if (nsym) 249 kernend = (char *)mips_round_page(esym); 250#endif 251 252 uvm_md_init(); 253 254 boothowto = x_boothowto; 255 bootdev = x_bootdev; 256 physmem = btoc(x_maxmem); 257 258 /* 259 * Now that we know how much memory we have, initialize the 260 * mem cluster array. 261 */ 262 mem_clusters[0].start = 0; /* XXX is this correct? */ 263 mem_clusters[0].size = ctob(physmem); 264 mem_cluster_cnt = 1; 265 266 /* 267 * Copy exception-dispatch code down to exception vector. 268 * Initialize locore-function vector. 269 * Clear out the I and D caches. 270 */ 271 mips_vector_init(NULL, false); 272 273 /* 274 * We know the CPU type now. Initialize our DMA tags (might 275 * need this early). 276 */ 277 newsmips_bus_dma_init(); 278 279#if NKSYMS || defined(DDB) || defined(MODULAR) 280 if (nsym) 281 ksyms_addsyms_elf(esym - ssym, ssym, esym); 282#endif 283 284#ifdef KADB 285 boothowto |= RB_KDB; 286#endif 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 /* 296 * Load the rest of the available pages into the VM system. 297 */ 298 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 299 last = mem_clusters[0].start + mem_clusters[0].size; 300 uvm_page_physload(atop(first), atop(last), atop(first), atop(last), 301 VM_FREELIST_DEFAULT); 302 303 /* 304 * Initialize error message buffer (at end of core). 305 */ 306 mips_init_msgbuf(); 307 308 /* 309 * Initialize the virtual memory system. 310 */ 311 pmap_bootstrap(); 312 313 /* 314 * Allocate uarea page for lwp0 and set it. 315 */ 316 mips_init_lwp0_uarea(); 317 318 /* 319 * Determine what model of computer we are running on. 320 */ 321 switch (systype) { 322#ifdef news3400 323 case NEWS3400: 324 news3400_init(); 325 cpu_setmodel("%s", idrom.id_machine); 326 model = cpu_getmodel(); 327 if (strcmp(model, "news3400") == 0 || 328 strcmp(model, "news3200") == 0 || 329 strcmp(model, "news3700") == 0) { 330 /* 331 * Set up interrupt handling and I/O addresses. 332 */ 333 hardware_intr = news3400_intr; 334 cpuspeed = 10; 335 } else { 336 printf("kernel not configured for machine %s\n", model); 337 } 338 break; 339#endif 340 341#ifdef news5000 342 case NEWS5000: 343 news5000_init(); 344 cpu_setmodel("%s", idrom.id_machine); 345 model = cpu_getmodel(); 346 if (strcmp(model, "news5000") == 0 || 347 strcmp(model, "news5900") == 0) { 348 /* 349 * Set up interrupt handling and I/O addresses. 350 */ 351 hardware_intr = news5000_intr; 352 cpuspeed = 50; /* ??? XXX */ 353 } else { 354 printf("kernel not configured for machine %s\n", model); 355 } 356 break; 357#endif 358 359#ifdef news4000 360 case NEWS4000: 361 news4000_init(); 362 cpu_setmodel("%s", idrom.id_machine); 363 model = cpu_getmodel(); 364 if (strcmp(model, "news4000") == 0) { 365 /* 366 * Set up interrupt handling and I/O addresses. 367 */ 368 hardware_intr = news4000_intr; 369 cpuspeed = 40; /* ??? XXX */ 370 } else { 371 printf("kernel not configured for machine %s\n", model); 372 } 373 break; 374#endif 375 376 default: 377 printf("kernel not configured for systype %d\n", systype); 378 break; 379 } 380} 381 382void 383mips_machdep_cache_config(void) 384{ 385 /* All r4k news boxen have a 1MB L2 cache. */ 386 if (CPUISMIPS3) 387 mips_cache_info.mci_sdcache_size = 1024 * 1024; 388} 389 390/* 391 * cpu_startup: allocate memory for variable-sized tables, 392 * initialize CPU, and do autoconfiguration. 393 */ 394void 395cpu_startup(void) 396{ 397 printf("SONY NET WORK STATION, Model %s, ", idrom.id_model); 398 printf("Machine ID #%d\n", idrom.id_serial); 399 400 cpu_startup_common(); 401} 402 403/* 404 * lookup_bootinfo: 405 * Look up information in bootinfo of boot loader. 406 */ 407void * 408lookup_bootinfo(int type) 409{ 410 struct btinfo_common *bt; 411 char *help = bootinfo; 412 413 /* Check for a bootinfo record first. */ 414 if (help == NULL) 415 return NULL; 416 417 do { 418 bt = (struct btinfo_common *)help; 419 if (bt->type == type) 420 return (void *)help; 421 help += bt->next; 422 } while (bt->next != 0 && 423 (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); 424 425 return NULL; 426} 427 428/* 429 * call PROM to halt or reboot. 430 */ 431void 432prom_halt(int howto) 433 434{ 435#if defined(news5000) || defined(news4000) 436 if (systype == NEWS5000 || systype == NEWS4000) 437 apcall_exit(howto); 438#endif 439#ifdef news3400 440 if (systype == NEWS3400) 441 to_monitor(howto); 442#endif 443 for (;;); 444} 445 446int waittime = -1; 447 448void 449cpu_reboot(volatile int howto, char *bootstr) 450{ 451 452 /* take a snap shot before clobbering any registers */ 453 savectx(curpcb); 454 455#ifdef DEBUG 456 if (panicstr) 457 stacktrace(); 458#endif 459 460 /* If system is cold, just halt. */ 461 if (cold) { 462 howto |= RB_HALT; 463 goto haltsys; 464 } 465 466 /* If "always halt" was specified as a boot flag, obey. */ 467 if ((boothowto & RB_HALT) != 0) 468 howto |= RB_HALT; 469 470 boothowto = howto; 471 if ((howto & RB_NOSYNC) == 0 && waittime < 0) { 472 /* 473 * Synchronize the disks.... 474 */ 475 waittime = 0; 476 vfs_shutdown(); 477 } 478 479 /* Disable interrupts. */ 480 disable_intr(); 481 482 splhigh(); 483 484 /* If rebooting and a dump is requested do it. */ 485#if 0 486 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 487#else 488 if (howto & RB_DUMP) 489#endif 490 dumpsys(); 491 492haltsys: 493 494 /* run any shutdown hooks */ 495 doshutdownhooks(); 496 497 pmf_system_shutdown(boothowto); 498 499 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) 500 prom_halt(0x80); /* rom monitor RB_PWOFF */ 501 502 /* Finally, halt/reboot the system. */ 503 printf("%s\n\n", howto & RB_HALT ? "halted." : "rebooting..."); 504 prom_halt(howto & RB_HALT); 505 /*NOTREACHED*/ 506} 507 508void 509delay(int n) 510{ 511 512 DELAY(n); 513} 514 515void 516cpu_intr(int ppl, vaddr_t pc, uint32_t status) 517{ 518 curcpu()->ci_data.cpu_nintr++; 519 520 /* device interrupts */ 521 (*hardware_intr)(ppl, pc, status); 522} 523