1/* $NetBSD: machdep.c,v 1.124 2024/03/05 14:15:29 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 2006 Izumi Tsutsui. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27/* 28 * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions, and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 42 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 49 * SUCH DAMAGE. 50 */ 51 52#include <sys/cdefs.h> 53__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.124 2024/03/05 14:15:29 thorpej Exp $"); 54 55#include "opt_ddb.h" 56#include "opt_kgdb.h" 57#include "opt_modular.h" 58#include "opt_execfmt.h" 59 60#include <sys/param.h> 61#include <sys/systm.h> 62#include <sys/boot_flag.h> 63#include <sys/bus.h> 64#include <sys/cpu.h> 65#include <sys/device.h> 66#include <sys/kernel.h> 67#include <sys/kcore.h> 68#include <sys/ksyms.h> 69#include <sys/mount.h> 70#include <sys/proc.h> 71#include <sys/reboot.h> 72 73#include <uvm/uvm_extern.h> 74 75#include <machine/bootinfo.h> 76 77#include <mips/locore.h> 78#include <mips/psl.h> 79 80#include <dev/cons.h> 81 82#include <cobalt/dev/gtreg.h> 83 84#ifdef KGDB 85#include <sys/kgdb.h> 86#endif 87 88#include "ksyms.h" 89 90#if NKSYMS || defined(DDB) || defined(MODULAR) 91#include <mips/db_machdep.h> 92#include <ddb/db_extern.h> 93#include <sys/exec_elf.h> 94#endif 95 96/* Maps for VM objects. */ 97struct vm_map *phys_map = NULL; 98 99void *bootinfo = NULL; /* pointer to bootinfo structure */ 100 101char bootstring[512]; /* Boot command */ 102int netboot; /* Are we netbooting? */ 103 104char *nfsroot_bstr = NULL; 105char *root_bstr = NULL; 106int bootunit = -1; 107int bootpart = -1; 108 109#if 0 110struct extent *cobalt_io_ex = NULL; 111struct extent *cobalt_mem_ex = NULL; 112struct mips_bus_space bonito_iot; 113struct mips_bus_space bonito_memt; 114struct mips_bus_dma_tag bonito_dmat; 115struct mips_pci_chipset bonito_pc; 116#endif 117 118 119int cpuspeed; 120 121u_int cobalt_id; 122static const char * const cobalt_model[] = 123{ 124 [COBALT_ID_QUBE2700] = "Cobalt Qube 2700", 125 [COBALT_ID_RAQ] = "Cobalt RaQ", 126 [COBALT_ID_QUBE2] = "Cobalt Qube 2", 127 [COBALT_ID_RAQ2] = "Cobalt RaQ 2" 128}; 129#define COBALT_MODELS __arraycount(cobalt_model) 130 131phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 132int mem_cluster_cnt; 133 134void mach_init(int32_t, u_int, int32_t); 135void decode_bootstring(void); 136static char *strtok_light(char *, const char); 137static u_int read_board_id(void); 138 139extern char *esym; 140 141struct mips_bus_space cobalt_bs; 142void mainbus_bus_mem_init(bus_space_tag_t, void *); 143 144 145/* 146 * Do all the stuff that locore normally does before calling main(). 147 */ 148void 149mach_init(int32_t memsize32, u_int bim, int32_t bip32) 150{ 151 intptr_t memsize = (int32_t)memsize32; 152 char *kernend; 153 char *bip = (char *)(intptr_t)(int32_t)bip32; 154 u_long first, last; 155 extern char edata[], end[]; 156 const char *bi_msg; 157#if NKSYMS || defined(DDB) || defined(MODULAR) 158 char *ssym = 0; 159 struct btinfo_symtab *bi_syms; 160#endif 161 struct btinfo_howto *bi_howto; 162 163 /* 164 * Clear the BSS segment (if needed). 165 */ 166 if (memcmp(((Elf_Ehdr *)end)->e_ident, ELFMAG, SELFMAG) == 0 && 167 ((Elf_Ehdr *)end)->e_ident[EI_CLASS] == ELFCLASS) { 168 esym = end; 169#if NKSYMS || defined(DDB) || defined(MODULAR) 170 esym += ((Elf_Ehdr *)end)->e_entry; 171#endif 172 kernend = (char *)mips_round_page(esym); 173 /* 174 * We don't have to clear BSS here 175 * since our bootloader already does it. 176 */ 177#if 0 178 memset(edata, 0, end - edata); 179#endif 180 } else { 181 kernend = (void *)mips_round_page(end); 182 /* 183 * No symbol table, so assume we are loaded by 184 * the firmware directly with "bfd" command. 185 * The firmware loader doesn't clear BSS of 186 * a loaded kernel, so do it here. 187 */ 188 memset(edata, 0, kernend - edata); 189 190 } 191 192 /* 193 * Copy exception-dispatch code down to exception vector. 194 * Initialize locore-function vector. 195 * Clear out the I and D caches. 196 */ 197 mips_vector_init(NULL, false); 198 199 mainbus_bus_mem_init(&cobalt_bs, NULL); 200 201 /* Check for valid bootinfo passed from bootstrap */ 202 if (bim == BOOTINFO_MAGIC) { 203 struct btinfo_magic *bi_magic; 204 205 bootinfo = bip; 206 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 207 if (bi_magic == NULL) { 208 bi_msg = "missing bootinfo structure"; 209 bim = (uintptr_t)bip; 210 } else if (bi_magic->magic != BOOTINFO_MAGIC) { 211 bi_msg = "invalid bootinfo structure"; 212 bim = bi_magic->magic; 213 } else 214 bi_msg = NULL; 215 } else { 216 bi_msg = "invalid bootinfo (standalone boot?)"; 217 } 218 219#if NKSYMS || defined(DDB) || defined(MODULAR) 220 bi_syms = lookup_bootinfo(BTINFO_SYMTAB); 221 222 /* Load symbol table if present */ 223 if (bi_syms != NULL) { 224 ssym = (void *)(intptr_t)bi_syms->ssym; 225 esym = (void *)(intptr_t)bi_syms->esym; 226 kernend = (void *)mips_round_page(esym); 227 } 228#endif 229 230 bi_howto = lookup_bootinfo(BTINFO_HOWTO); 231 if (bi_howto != NULL) 232 boothowto = bi_howto->bi_howto; 233 234 cobalt_id = read_board_id(); 235 if (cobalt_id >= COBALT_MODELS || cobalt_model[cobalt_id] == NULL) 236 cpu_setmodel("Cobalt unknown model (board ID %u)", 237 cobalt_id); 238 else 239 cpu_setmodel("%s", cobalt_model[cobalt_id]); 240 241 switch (cobalt_id) { 242 case COBALT_ID_QUBE2700: 243 case COBALT_ID_RAQ: 244 cpuspeed = 150; /* MHz */ 245 break; 246 case COBALT_ID_QUBE2: 247 case COBALT_ID_RAQ2: 248 cpuspeed = 250; /* MHz */ 249 break; 250 default: 251 /* assume the fastest, so that delay(9) works */ 252 cpuspeed = 250; 253 break; 254 } 255 curcpu()->ci_cpu_freq = cpuspeed * 1000 * 1000; 256 curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz; 257 curcpu()->ci_divisor_delay = 258 ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000); 259 /* all models have Rm5200, which is CPU_MIPS_DOUBLE_COUNT */ 260 curcpu()->ci_cycles_per_hz /= 2; 261 curcpu()->ci_divisor_delay /= 2; 262 263 physmem = btoc(memsize - MIPS_KSEG0_START); 264 265 consinit(); 266 267 KASSERT(&lwp0 == curlwp); 268 if (bi_msg != NULL) 269 printf("%s: magic=%#x bip=%p\n", bi_msg, bim, bip); 270 271 uvm_md_init(); 272 273 /* 274 * The boot command is passed in the top 512 bytes, 275 * so don't clobber that. 276 */ 277 mem_clusters[0].start = 0; 278 mem_clusters[0].size = ctob(physmem) - 512; 279 mem_cluster_cnt = 1; 280 281 memcpy(bootstring, (char *)(memsize - 512), 512); 282 memset((char *)(memsize - 512), 0, 512); 283 bootstring[511] = '\0'; 284 285 decode_bootstring(); 286 287#if NKSYMS || defined(DDB) || defined(MODULAR) 288 /* init symbols if present */ 289 if ((bi_syms != NULL) && (esym != NULL)) 290 ksyms_addsyms_elf(esym - ssym, ssym, esym); 291#endif 292 KASSERT(&lwp0 == curlwp); 293 /* 294 * Load the rest of the available pages into the VM system. 295 */ 296 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 297 last = mem_clusters[0].start + mem_clusters[0].size; 298 uvm_page_physload(atop(first), atop(last), atop(first), atop(last), 299 VM_FREELIST_DEFAULT); 300 301 /* 302 * Initialize error message buffer (at end of core). 303 */ 304 mips_init_msgbuf(); 305 306 pmap_bootstrap(); 307 308 /* 309 * Allocate space for proc0's USPACE. 310 */ 311 mips_init_lwp0_uarea(); 312 313#ifdef DDB 314 if (boothowto & RB_KDB) 315 Debugger(); 316#endif 317#ifdef KGDB 318 if (boothowto & RB_KDB) 319 kgdb_connect(0); 320#endif 321 322} 323 324/* 325 * Allocate memory for variable-sized tables, 326 */ 327void 328cpu_startup(void) 329{ 330 cpu_startup_common(); 331} 332 333static int waittime = -1; 334 335void 336cpu_reboot(int howto, char *bootstr) 337{ 338 339 /* Take a snapshot before clobbering any registers. */ 340 savectx(curpcb); 341 342 if (cold) { 343 howto |= RB_HALT; 344 goto haltsys; 345 } 346 347 /* If "always halt" was specified as a boot flag, obey. */ 348 if (boothowto & RB_HALT) 349 howto |= RB_HALT; 350 351 boothowto = howto; 352 if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) { 353 waittime = 0; 354 vfs_shutdown(); 355 } 356 357 splhigh(); 358 359 if (howto & RB_DUMP) 360 dumpsys(); 361 362 haltsys: 363 doshutdownhooks(); 364 365 pmf_system_shutdown(boothowto); 366 367 if (howto & RB_HALT) { 368 printf("\n"); 369 printf("The operating system has halted.\n"); 370 printf("Please press any key to reboot.\n\n"); 371 cnpollc(1); /* For proper keyboard command handling */ 372 cngetc(); 373 cnpollc(0); 374 } 375 376 printf("rebooting...\n\n"); 377 delay(500000); 378 379 *(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 380 printf("WARNING: reboot failed!\n"); 381 382 for (;;) 383 ; 384} 385 386 387void 388decode_bootstring(void) 389{ 390 char *work; 391 char *equ; 392 int i; 393 394 /* break apart bootstring on ' ' boundaries and iterate */ 395 work = strtok_light(bootstring, ' '); 396 while (work != NULL) { 397 /* if starts with '-', we got options, walk its decode */ 398 if (work[0] == '-') { 399 i = 1; 400 while (work[i] != ' ' && work[i] != '\0') { 401 BOOT_FLAG(work[i], boothowto); 402 i++; 403 } 404 } else 405 406 /* if it has a '=' its an assignment, switch and set */ 407 if ((equ = strchr(work, '=')) != NULL) { 408 if (memcmp("nfsroot=", work, 8) == 0) { 409 nfsroot_bstr = (equ + 1); 410 } else 411 if (memcmp("root=", work, 5) == 0) { 412 root_bstr = (equ + 1); 413 } 414 } else 415 416 /* else it a single value, switch and process */ 417 if (memcmp("single", work, 5) == 0) { 418 boothowto |= RB_SINGLE; 419 } else 420 if (memcmp("ro", work, 2) == 0) { 421 /* this is also inserted by the firmware */ 422 } 423 424 /* grab next token */ 425 work = strtok_light(NULL, ' '); 426 } 427 428 if (root_bstr != NULL) { 429 /* this should be of the form "/dev/hda1" */ 430 /* [abcd][1234] drive partition linux probe order */ 431 if ((memcmp("/dev/hd", root_bstr, 7) == 0) && 432 (strlen(root_bstr) == 9) ){ 433 bootunit = root_bstr[7] - 'a'; 434 bootpart = root_bstr[8] - '1'; 435 } 436 } 437 438 if (nfsroot_bstr != NULL) 439 netboot = 1; 440} 441 442 443static char * 444strtok_light(char *str, const char sep) 445{ 446 static char *proc; 447 char *head; 448 char *work; 449 450 if (str != NULL) 451 proc = str; 452 if (proc == NULL) /* end of string return NULL */ 453 return proc; 454 455 head = proc; 456 457 work = strchr(proc, sep); 458 if (work == NULL) { /* we hit the end */ 459 proc = work; 460 } else { 461 proc = (work + 1); 462 *work = '\0'; 463 } 464 465 return head; 466} 467 468/* 469 * Look up information in bootinfo of boot loader. 470 */ 471void * 472lookup_bootinfo(unsigned int type) 473{ 474 struct btinfo_common *bt; 475 char *help = bootinfo; 476 477 /* Check for a bootinfo record first. */ 478 if (help == NULL) { 479 printf("##### help == NULL\n"); 480 return NULL; 481 } 482 483 do { 484 bt = (struct btinfo_common *)help; 485 printf("Type %d @%p\n", bt->type, (void *)(intptr_t)bt); 486 if (bt->type == type) 487 return (void *)help; 488 help += bt->next; 489 } while (bt->next != 0 && 490 (uintptr_t)help < (uintptr_t)bootinfo + BOOTINFO_SIZE); 491 492 return NULL; 493} 494 495/* 496 * Get board ID of cobalt models. 497 * 498 * The board ID info is stored at the PCI config register 499 * on the PCI-ISA bridge part of the VIA VT82C586 chipset. 500 * We can't use pci_conf_read(9) yet here, so read it directly. 501 */ 502static u_int 503read_board_id(void) 504{ 505 volatile uint32_t *pcicfg_addr, *pcicfg_data; 506 uint32_t reg; 507 508#define PCIB_PCI_BUS 0 509#define PCIB_PCI_DEV 9 510#define PCIB_PCI_FUNC 0 511#define PCIB_BOARD_ID_REG 0x94 512#define COBALT_BOARD_ID(reg) ((reg & 0x000000f0) >> 4) 513 514 pcicfg_addr = (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_PCICFG_ADDR); 515 pcicfg_data = (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_PCICFG_DATA); 516 517 *pcicfg_addr = PCICFG_ENABLE | 518 (PCIB_PCI_BUS << 16) | (PCIB_PCI_DEV << 11) | (PCIB_PCI_FUNC << 8) | 519 PCIB_BOARD_ID_REG; 520 reg = *pcicfg_data; 521 *pcicfg_addr = 0; 522 523 return COBALT_BOARD_ID(reg); 524} 525