machdep.c revision 1.52
1/* $NetBSD: machdep.c,v 1.52 2004/08/28 12:32:48 tsutsui Exp $ */ 2 3/* 4 * Copyright (c) 2000 Soren S. Jorvang. 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 AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.52 2004/08/28 12:32:48 tsutsui Exp $"); 30 31#include "opt_ddb.h" 32#include "opt_kgdb.h" 33#include "opt_execfmt.h" 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/kernel.h> 38#include <sys/proc.h> 39#include <sys/buf.h> 40#include <sys/reboot.h> 41#include <sys/conf.h> 42#include <sys/file.h> 43#include <sys/malloc.h> 44#include <sys/mbuf.h> 45#include <sys/msgbuf.h> 46#include <sys/device.h> 47#include <sys/user.h> 48#include <sys/exec.h> 49#include <uvm/uvm_extern.h> 50#include <sys/sysctl.h> 51#include <sys/mount.h> 52#include <sys/sa.h> 53#include <sys/syscallargs.h> 54#include <sys/kcore.h> 55#include <sys/boot_flag.h> 56#include <sys/ksyms.h> 57 58#include <machine/cpu.h> 59#include <machine/reg.h> 60#include <machine/psl.h> 61#include <machine/pte.h> 62#include <machine/autoconf.h> 63#include <machine/bootinfo.h> 64#include <machine/intr.h> 65#include <mips/locore.h> 66 67#include <machine/nvram.h> 68#include <machine/leds.h> 69 70#include <dev/cons.h> 71 72#ifdef KGDB 73#include <sys/kgdb.h> 74#endif 75 76#include "ksyms.h" 77 78#if NKSYMS || defined(DDB) || defined(LKM) 79#include <machine/db_machdep.h> 80#include <ddb/db_extern.h> 81#define ELFSIZE DB_ELFSIZE 82#include <sys/exec_elf.h> 83#endif 84 85/* For sysctl. */ 86extern char cpu_model[]; 87 88/* Our exported CPU info; we can have only one. */ 89struct cpu_info cpu_info_store; 90 91/* Maps for VM objects. */ 92struct vm_map *exec_map = NULL; 93struct vm_map *mb_map = NULL; 94struct vm_map *phys_map = NULL; 95 96int physmem; /* Total physical memory */ 97char *bootinfo = NULL; /* pointer to bootinfo structure */ 98 99char bootstring[512]; /* Boot command */ 100int netboot; /* Are we netbooting? */ 101 102char * nfsroot_bstr = NULL; 103char * root_bstr = NULL; 104int bootunit = -1; 105int bootpart = -1; 106 107 108phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 109int mem_cluster_cnt; 110 111void mach_init(unsigned int, u_int, char*); 112void decode_bootstring(void); 113static char * strtok_light(char *, const char); 114 115/* 116 * safepri is a safe priority for sleep to set for a spin-wait during 117 * autoconfiguration or after a panic. Used as an argument to splx(). 118 */ 119int safepri = MIPS1_PSL_LOWIPL; 120 121extern caddr_t esym; 122extern struct user *proc0paddr; 123 124 125 126/* 127 * Do all the stuff that locore normally does before calling main(). 128 */ 129void 130mach_init(memsize, bim, bip) 131 unsigned int memsize; 132 u_int bim; 133 char *bip; 134{ 135 caddr_t kernend, v; 136 u_long first, last; 137 extern char edata[], end[]; 138 char *bi_msg; 139#if NKSYMS || defined(DDB) || defined(LKM) 140 int nsym = 0; 141 caddr_t ssym = 0; 142 caddr_t esym = 0; 143 struct btinfo_symtab *bi_syms; 144#endif 145 146 /* 147 * Clear the BSS segment. 148 */ 149#if NKSYMS || defined(DDB) || defined(LKM) 150 if (memcmp(((Elf_Ehdr *)end)->e_ident, ELFMAG, SELFMAG) == 0 && 151 ((Elf_Ehdr *)end)->e_ident[EI_CLASS] == ELFCLASS) { 152 esym = end; 153 esym += ((Elf_Ehdr *)end)->e_entry; 154 kernend = (caddr_t)mips_round_page(esym); 155 memset(edata, 0, end - edata); 156 } else 157#endif 158 { 159 kernend = (caddr_t)mips_round_page(end); 160 memset(edata, 0, kernend - edata); 161 } 162 163 /* Check for valid bootinfo passed from bootstrap */ 164 if (bim == BOOTINFO_MAGIC) { 165 struct btinfo_magic *bi_magic; 166 167 bootinfo = bip; 168 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 169 if (bi_magic == NULL || bi_magic->magic != BOOTINFO_MAGIC) 170 bi_msg = "invalid bootinfo structure.\n"; 171 else 172 bi_msg = NULL; 173 } else 174 bi_msg = "invalid bootinfo (standalone boot?)\n"; 175 176#if NKSYMS || defined(DDB) || defined(LKM) 177 bi_syms = lookup_bootinfo(BTINFO_SYMTAB); 178 179 /* Load symbol table if present */ 180 if (bi_syms != NULL) { 181 nsym = bi_syms->nsym; 182 ssym = (caddr_t)bi_syms->ssym; 183 esym = (caddr_t)bi_syms->esym; 184 kernend = (caddr_t)mips_round_page(esym); 185 } 186#endif 187 188 physmem = btoc(memsize - MIPS_KSEG0_START); 189 190 consinit(); 191 192 if (bi_msg != NULL) 193 printf(bi_msg); 194 195 uvm_setpagesize(); 196 197 /* 198 * Copy exception-dispatch code down to exception vector. 199 * Initialize locore-function vector. 200 * Clear out the I and D caches. 201 */ 202 mips_vector_init(); 203 204 /* 205 * The boot command is passed in the top 512 bytes, 206 * so don't clobber that. 207 */ 208 mem_clusters[0].start = 0; 209 mem_clusters[0].size = ctob(physmem) - 512; 210 mem_cluster_cnt = 1; 211 212 memcpy(bootstring, (char *)(memsize - 512), 512); 213 memset((char *)(memsize - 512), 0, 512); 214 bootstring[511] = '\0'; 215 216 decode_bootstring(); 217 218#if NKSYMS || defined(DDB) || defined(LKM) 219 /* init symbols if present */ 220 if ((bi_syms != NULL) && (esym != NULL)) 221 ksyms_init(esym - ssym, ssym, esym); 222 else 223 ksyms_init(0, NULL, NULL); 224#endif 225#ifdef DDB 226 if (boothowto & RB_KDB) 227 Debugger(); 228#endif 229#ifdef KGDB 230 if (boothowto & RB_KDB) 231 kgdb_connect(0); 232#endif 233 234 strcpy(cpu_model, "Cobalt Microserver"); 235 236 /* 237 * Load the rest of the available pages into the VM system. 238 */ 239 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 240 last = mem_clusters[0].start + mem_clusters[0].size; 241 uvm_page_physload(atop(first), atop(last), atop(first), atop(last), 242 VM_FREELIST_DEFAULT); 243 244 /* 245 * Initialize error message buffer (at end of core). 246 */ 247 mips_init_msgbuf(); 248 249 pmap_bootstrap(); 250 251 /* 252 * Allocate space for proc0's USPACE. 253 */ 254 v = (caddr_t)uvm_pageboot_alloc(USPACE); 255 lwp0.l_addr = proc0paddr = (struct user *)v; 256 lwp0.l_md.md_regs = (struct frame *)(v + USPACE) - 1; 257 curpcb = &lwp0.l_addr->u_pcb; 258 curpcb->pcb_context[11] = MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */ 259} 260 261/* 262 * Allocate memory for variable-sized tables, 263 */ 264void 265cpu_startup() 266{ 267 vaddr_t minaddr, maxaddr; 268 char pbuf[9]; 269 270 /* 271 * Good {morning,afternoon,evening,night}. 272 */ 273 printf(version); 274 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 275 printf("total memory = %s\n", pbuf); 276 277 minaddr = 0; 278 /* 279 * Allocate a submap for exec arguments. This map effectively 280 * limits the number of processes exec'ing at any time. 281 */ 282 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 283 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 284 /* 285 * Allocate a submap for physio. 286 */ 287 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 288 VM_PHYS_SIZE, 0, FALSE, NULL); 289 290 /* 291 * (No need to allocate an mbuf cluster submap. Mbuf clusters 292 * are allocated via the pool allocator, and we use KSEG to 293 * map those pages.) 294 */ 295 296 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 297 printf("avail memory = %s\n", pbuf); 298} 299 300int waittime = -1; 301 302void 303cpu_reboot(howto, bootstr) 304 int howto; 305 char *bootstr; 306{ 307 /* Take a snapshot before clobbering any registers. */ 308 if (curlwp) 309 savectx((struct user *)curpcb); 310 311 if (cold) { 312 howto |= RB_HALT; 313 goto haltsys; 314 } 315 316 /* If "always halt" was specified as a boot flag, obey. */ 317 if (boothowto & RB_HALT) 318 howto |= RB_HALT; 319 320 boothowto = howto; 321 if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) { 322 waittime = 0; 323 vfs_shutdown(); 324 325 /* 326 * If we've been adjusting the clock, the todr 327 * will be out of synch; adjust it now. 328 */ 329 resettodr(); 330 } 331 332 splhigh(); 333 334 if (howto & RB_DUMP) 335 dumpsys(); 336 337haltsys: 338 doshutdownhooks(); 339 340 if (howto & RB_HALT) { 341 printf("\n"); 342 printf("The operating system has halted.\n"); 343 printf("Please press any key to reboot.\n\n"); 344 cnpollc(1); /* For proper keyboard command handling */ 345 cngetc(); 346 cnpollc(0); 347 } 348 349 printf("rebooting...\n\n"); 350 delay(500000); 351 352 *(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 353 printf("WARNING: reboot failed!\n"); 354 355 for (;;); 356} 357 358unsigned long cpuspeed; 359 360__inline void 361delay(n) 362 unsigned long n; 363{ 364 volatile register long N = cpuspeed * n; 365 366 while (--N > 0); 367} 368 369#define NINTR 6 370 371static struct cobalt_intrhand intrtab[NINTR]; 372 373const u_int32_t mips_ipl_si_to_sr[_IPL_NSOFT] = { 374 MIPS_SOFT_INT_MASK_0, /* IPL_SOFT */ 375 MIPS_SOFT_INT_MASK_0, /* IPL_SOFTCLOCK */ 376 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTNET */ 377 MIPS_SOFT_INT_MASK_1, /* IPL_SOFTSERIAL */ 378}; 379 380void * 381cpu_intr_establish(level, ipl, func, arg) 382 int level; 383 int ipl; 384 int (*func)(void *); 385 void *arg; 386{ 387 if (level < 0 || level >= NINTR) 388 panic("invalid interrupt level"); 389 390 if (intrtab[level].ih_func != NULL) 391 panic("cannot share CPU interrupts"); 392 393 intrtab[level].cookie_type = COBALT_COOKIE_TYPE_CPU; 394 intrtab[level].ih_func = func; 395 intrtab[level].ih_arg = arg; 396 397 return &intrtab[level]; 398} 399 400void 401cpu_intr_disestablish(cookie) 402 void *cookie; 403{ 404 struct cobalt_intrhand *ih = cookie; 405 406 if (ih->cookie_type == COBALT_COOKIE_TYPE_CPU) { 407 ih->ih_func = NULL; 408 ih->ih_arg = NULL; 409 } 410} 411 412void 413cpu_intr(status, cause, pc, ipending) 414 u_int32_t status; 415 u_int32_t cause; 416 u_int32_t pc; 417 u_int32_t ipending; 418{ 419 struct clockframe cf; 420 static u_int32_t cycles; 421 int i; 422 423 uvmexp.intrs++; 424 425 if (ipending & MIPS_INT_MASK_0) { 426 volatile u_int32_t *irq_src = 427 (u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000c18); 428 429 if (*irq_src & 0x00000100) { 430 *irq_src = 0; 431 432 cf.pc = pc; 433 cf.sr = status; 434 435 hardclock(&cf); 436 } 437 cause &= ~MIPS_INT_MASK_0; 438 } 439 440 for (i = 0; i < 5; i++) { 441 if (ipending & (MIPS_INT_MASK_0 << i)) 442 if (intrtab[i].ih_func != NULL) 443 if ((*intrtab[i].ih_func)(intrtab[i].ih_arg)) 444 cause &= ~(MIPS_INT_MASK_0 << i); 445 } 446 447 if (ipending & MIPS_INT_MASK_5) { 448 cycles = mips3_cp0_count_read(); 449 mips3_cp0_compare_write(cycles + 1250000); /* XXX */ 450 451#if 0 452 cf.pc = pc; 453 cf.sr = status; 454 455 statclock(&cf); 456#endif 457 cause &= ~MIPS_INT_MASK_5; 458 } 459 460 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 461 462 /* software interrupt */ 463 ipending &= (MIPS_SOFT_INT_MASK_1|MIPS_SOFT_INT_MASK_0); 464 if (ipending == 0) 465 return; 466 467 _clrsoftintr(ipending); 468 469 softintr_dispatch(ipending); 470} 471 472 473void 474decode_bootstring(void) 475{ 476 char * work; 477 char * equ; 478 int i; 479 480 /* break apart bootstring on ' ' boundries and itterate*/ 481 work = strtok_light(bootstring, ' '); 482 while (work != '\0') { 483 /* if starts with '-', we got options, walk its decode */ 484 if (work[0] == '-') { 485 i = 1; 486 while (work[i] != ' ' && work[i] != '\0') { 487 BOOT_FLAG(work[i], boothowto); 488 i++; 489 } 490 } else 491 492 /* if it has a '=' its an assignment, switch and set */ 493 if ((equ = strchr(work,'=')) != '\0') { 494 if(0 == memcmp("nfsroot=", work, 8)) { 495 nfsroot_bstr = (equ +1); 496 } else 497 if(0 == memcmp("root=", work, 5)) { 498 root_bstr = (equ +1); 499 } 500 } else 501 502 /* else it a single value, switch and process */ 503 if (memcmp("single", work, 5) == 0) { 504 boothowto |= RB_SINGLE; 505 } else 506 if (memcmp("ro", work, 2) == 0) { 507 /* this is also inserted by the firmware */ 508 } 509 510 /* grab next token */ 511 work = strtok_light(NULL, ' '); 512 } 513 514 if (root_bstr != NULL) { 515 /* this should be of the form "/dev/hda1" */ 516 /* [abcd][1234] drive partition linux probe order */ 517 if ((memcmp("/dev/hd",root_bstr,7) == 0) && 518 (strlen(root_bstr) == 9) ){ 519 bootunit = root_bstr[7] - 'a'; 520 bootpart = root_bstr[8] - '1'; 521 } 522 } 523} 524 525 526static char * 527strtok_light(str, sep) 528 char * str; 529 const char sep; 530{ 531 static char * proc; 532 char * head; 533 char * work; 534 535 if (str != NULL) 536 proc = str; 537 if (proc == NULL) /* end of string return NULL */ 538 return proc; 539 540 head = proc; 541 542 work = strchr (proc, sep); 543 if (work == NULL) { /* we hit the end */ 544 proc = work; 545 } else { 546 proc = (work +1 ); 547 *work = '\0'; 548 } 549 550 return head; 551} 552 553/* 554 * Look up information in bootinfo of boot loader. 555 */ 556void * 557lookup_bootinfo(type) 558 int type; 559{ 560 struct btinfo_common *bt; 561 char *help = bootinfo; 562 563 /* Check for a bootinfo record first. */ 564 if (help == NULL) { 565 printf("##### help == NULL\n"); 566 return (NULL); 567 } 568 569 do { 570 bt = (struct btinfo_common *)help; 571 printf("Type %d @0x%x\n", bt->type, (u_int)bt); 572 if (bt->type == type) 573 return ((void *)help); 574 help += bt->next; 575 } while (bt->next != 0 && 576 (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); 577 578 return (NULL); 579} 580