machdep.c revision 1.27
1/* $NetBSD: machdep.c,v 1.27 2001/03/15 06:10:38 chs 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 "opt_ddb.h" 29#include "opt_execfmt.h" 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kernel.h> 34#include <sys/map.h> 35#include <sys/proc.h> 36#include <sys/buf.h> 37#include <sys/reboot.h> 38#include <sys/conf.h> 39#include <sys/file.h> 40#include <sys/malloc.h> 41#include <sys/mbuf.h> 42#include <sys/msgbuf.h> 43#include <sys/device.h> 44#include <sys/user.h> 45#include <sys/exec.h> 46#include <uvm/uvm_extern.h> 47#include <sys/sysctl.h> 48#include <sys/mount.h> 49#include <sys/syscallargs.h> 50#include <sys/kcore.h> 51#include <sys/boot_flag.h> 52 53#include <machine/cpu.h> 54#include <machine/reg.h> 55#include <machine/psl.h> 56#include <machine/pte.h> 57#include <machine/autoconf.h> 58#include <machine/intr.h> 59#include <mips/locore.h> 60 61#include <machine/nvram.h> 62#include <machine/leds.h> 63 64#ifdef DDB 65#include <machine/db_machdep.h> 66#include <ddb/db_access.h> 67#include <ddb/db_sym.h> 68#include <ddb/db_extern.h> 69#ifndef DB_ELFSIZE 70#error Must define DB_ELFSIZE! 71#endif 72#define ELFSIZE DB_ELFSIZE 73#include <sys/exec_elf.h> 74#endif 75 76#include <dev/cons.h> 77 78/* For sysctl. */ 79char machine[] = MACHINE; 80char machine_arch[] = MACHINE_ARCH; 81char cpu_model[] = "Cobalt Microserver"; 82 83/* Our exported CPU info; we can have only one. */ 84struct cpu_info cpu_info_store; 85 86/* Maps for VM objects. */ 87vm_map_t exec_map = NULL; 88vm_map_t mb_map = NULL; 89vm_map_t phys_map = NULL; 90 91int physmem; /* Total physical memory */ 92 93char bootstring[512]; /* Boot command */ 94int netboot; /* Are we netbooting? */ 95 96phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 97int mem_cluster_cnt; 98 99void configure(void); 100void mach_init(unsigned int); 101 102/* 103 * safepri is a safe priority for sleep to set for a spin-wait during 104 * autoconfiguration or after a panic. Used as an argument to splx(). 105 */ 106int safepri = MIPS1_PSL_LOWIPL; 107 108extern caddr_t esym; 109extern struct user *proc0paddr; 110 111/* 112 * Do all the stuff that locore normally does before calling main(). 113 */ 114void 115mach_init(memsize) 116 unsigned int memsize; 117{ 118 caddr_t kernend, v; 119 u_long first, last; 120 vsize_t size; 121 extern char edata[], end[]; 122 int i; 123 124 /* 125 * Clear the BSS segment. 126 */ 127#ifdef DDB 128 if (memcmp(((Elf_Ehdr *)end)->e_ident, ELFMAG, SELFMAG) == 0 && 129 ((Elf_Ehdr *)end)->e_ident[EI_CLASS] == ELFCLASS) { 130 esym = end; 131 esym += ((Elf_Ehdr *)end)->e_entry; 132 kernend = (caddr_t)mips_round_page(esym); 133 bzero(edata, end - edata); 134 } else 135#endif 136 { 137 kernend = (caddr_t)mips_round_page(end); 138 memset(edata, 0, kernend - edata); 139 } 140 141 physmem = btoc(memsize - MIPS_KSEG0_START); 142 143 consinit(); 144 145 uvm_setpagesize(); 146 147 /* 148 * Copy exception-dispatch code down to exception vector. 149 * Initialize locore-function vector. 150 * Clear out the I and D caches. 151 */ 152 mips_vector_init(); 153 154 /* 155 * The boot command is passed in the top 512 bytes, 156 * so don't clobber that. 157 */ 158 mem_clusters[0].start = 0; 159 mem_clusters[0].size = ctob(physmem) - 512; 160 mem_cluster_cnt = 1; 161 162 memcpy(bootstring, (char *)(memsize - 512), 512); 163 memset((char *)(memsize - 512), 0, 512); 164 bootstring[511] = '\0'; 165 166 for (i = 0; i < 512; i++) { 167 switch (bootstring[i]) { 168 case '\0': 169 break; 170 case ' ': 171 continue; 172 case '-': 173 while (bootstring[i] != ' ' && bootstring[i] != '\0') { 174 BOOT_FLAG(bootstring[i], boothowto); 175 i++; 176 } 177 } 178 if (memcmp("single", bootstring + i, 5) == 0) 179 boothowto |= RB_SINGLE; 180 if (memcmp("nfsroot=", bootstring + i, 8) == 0) 181 netboot = 1; 182 /* 183 * XXX Select root device from 'root=/dev/hd[abcd][1234]' too. 184 */ 185 } 186 187#ifdef DDB 188 if (boothowto & RB_KDB) 189 Debugger(); 190#endif 191 192 /* 193 * Load the rest of the available pages into the VM system. 194 */ 195 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 196 last = mem_clusters[0].start + mem_clusters[0].size; 197 uvm_page_physload(atop(first), atop(last), atop(first), atop(last), 198 VM_FREELIST_DEFAULT); 199 200 /* 201 * Initialize error message buffer (at end of core). 202 */ 203 mips_init_msgbuf(); 204 205 /* 206 * Allocate space for proc0's USPACE. 207 */ 208 v = (caddr_t)pmap_steal_memory(USPACE, NULL, NULL); 209 proc0.p_addr = proc0paddr = (struct user *)v; 210 proc0.p_md.md_regs = (struct frame *)(v + USPACE) - 1; 211 curpcb = &proc0.p_addr->u_pcb; 212 curpcb->pcb_context[11] = MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */ 213 214 /* 215 * Allocate space for system data structures. These data structures 216 * are allocated here instead of cpu_startup() because physical 217 * memory is directly addressable. We don't have to map these into 218 * virtual address space. 219 */ 220 size = (vsize_t)allocsys(NULL, NULL); 221 v = (caddr_t)pmap_steal_memory(size, NULL, NULL); 222 if ((allocsys(v, NULL) - v) != size) 223 panic("mach_init: table size inconsistency"); 224 225 pmap_bootstrap(); 226} 227 228/* 229 * Allocate memory for variable-sized tables, 230 */ 231void 232cpu_startup() 233{ 234 unsigned i; 235 int base, residual; 236 vaddr_t minaddr, maxaddr; 237 vsize_t size; 238 char pbuf[9]; 239 240 /* 241 * Good {morning,afternoon,evening,night}. 242 */ 243 printf(version); 244 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 245 printf("%s memory", pbuf); 246 247 /* 248 * Allocate virtual address space for file I/O buffers. 249 * Note they are different than the array of headers, 'buf', 250 * and usually occupy more virtual memory than physical. 251 */ 252 size = MAXBSIZE * nbuf; 253 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(size), 254 NULL, UVM_UNKNOWN_OFFSET, 0, 255 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 256 UVM_ADV_NORMAL, 0)) != 0) 257 panic("startup: cannot allocate VM for buffers"); 258 minaddr = (vaddr_t)buffers; 259 base = bufpages / nbuf; 260 residual = bufpages % nbuf; 261 for (i = 0; i < nbuf; i++) { 262 vsize_t curbufsize; 263 vaddr_t curbuf; 264 struct vm_page *pg; 265 266 /* 267 * Each buffer has MAXBSIZE bytes of VM space allocated. Of 268 * that MAXBSIZE space, we allocate and map (base+1) pages 269 * for the first "residual" buffers, and then we allocate 270 * "base" pages for the rest. 271 */ 272 curbuf = (vaddr_t) buffers + (i * MAXBSIZE); 273 curbufsize = NBPG * ((i < residual) ? (base + 1) : base); 274 275 while (curbufsize) { 276 pg = uvm_pagealloc(NULL, 0, NULL, 0); 277 if (pg == NULL) 278 panic("cpu_startup: not enough memory for " 279 "buffer cache"); 280 pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 281 VM_PROT_READ|VM_PROT_WRITE); 282 curbuf += PAGE_SIZE; 283 curbufsize -= PAGE_SIZE; 284 } 285 } 286 287 /* 288 * Allocate a submap for exec arguments. This map effectively 289 * limits the number of processes exec'ing at any time. 290 */ 291 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 292 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 293 /* 294 * Allocate a submap for physio. 295 */ 296 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 297 VM_PHYS_SIZE, 0, FALSE, NULL); 298 299 /* 300 * (No need to allocate an mbuf cluster submap. Mbuf clusters 301 * are allocated via the pool allocator, and we use KSEG to 302 * map those pages.) 303 */ 304 305 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 306 printf(", %s free", pbuf); 307 format_bytes(pbuf, sizeof(pbuf), bufpages * NBPG); 308 printf(", %s in %d buffers\n", pbuf, nbuf); 309 310 /* 311 * Set up buffers, so they can be used to read disk labels. 312 */ 313 bufinit(); 314} 315 316int 317cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 318 int *name; 319 u_int namelen; 320 void *oldp; 321 size_t *oldlenp; 322 void *newp; 323 size_t newlen; 324 struct proc *p; 325{ 326 /* All sysctl names at this level are terminal. */ 327 if (namelen != 1) 328 return ENOTDIR; 329 330 switch (name[0]) { 331 default: 332 return EOPNOTSUPP; 333 } 334} 335 336int waittime = -1; 337 338void 339cpu_reboot(howto, bootstr) 340 int howto; 341 char *bootstr; 342{ 343 /* Take a snapshot before clobbering any registers. */ 344 if (curproc) 345 savectx((struct user *)curpcb); 346 347 if (cold) { 348 howto |= RB_HALT; 349 goto haltsys; 350 } 351 352 /* If "always halt" was specified as a boot flag, obey. */ 353 if (boothowto & RB_HALT) 354 howto |= RB_HALT; 355 356 boothowto = howto; 357 if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) { 358 waittime = 0; 359 vfs_shutdown(); 360 361 /* 362 * If we've been adjusting the clock, the todr 363 * will be out of synch; adjust it now. 364 */ 365 resettodr(); 366 } 367 368 splhigh(); 369 370 if (howto & RB_DUMP) 371 dumpsys(); 372 373haltsys: 374 doshutdownhooks(); 375 376 if (howto & RB_HALT) { 377 printf("\n"); 378 printf("The operating system has halted.\n"); 379 printf("Please press any key to reboot.\n\n"); 380 cnpollc(1); /* For proper keyboard command handling */ 381 cngetc(); 382 cnpollc(0); 383 } 384 385 printf("rebooting...\n\n"); 386 delay(500000); 387 388 *(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; 389 printf("WARNING: reboot failed!\n"); 390 391 for (;;); 392} 393 394void 395microtime(tvp) 396 struct timeval *tvp; 397{ 398 int s = splclock(); 399 static struct timeval lasttime; 400 u_int32_t counter0; 401 402 *tvp = time; 403 404 counter0 = *(volatile u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000850); 405 406 /* 407 * XXX 408 */ 409 410 counter0 /= 50; 411 counter0 %= 10000; 412 413 if (counter0 > 9999) { 414 counter0 = 9999; 415 } 416 417 tvp->tv_usec -= tvp->tv_usec % 10000; 418 tvp->tv_usec += 10000 - counter0; 419 420 lasttime = *tvp; 421 splx(s); 422} 423 424unsigned long cpuspeed; 425 426__inline void 427delay(n) 428 unsigned long n; 429{ 430 volatile register long N = cpuspeed * n; 431 432 while (--N > 0); 433} 434 435#define NINTR 6 436 437static struct { 438 int (*func)(void *); 439 void *arg; 440} intrtab[NINTR]; 441 442void * 443cpu_intr_establish(level, ipl, func, arg) 444 int level; 445 int ipl; 446 int (*func)(void *); 447 void *arg; 448{ 449 if (level < 0 || level >= NINTR) 450 panic("invalid interrupt level"); 451 452 if (intrtab[level].func != NULL) 453 panic("cannot share CPU interrupts"); 454 455 intrtab[level].func = func; 456 intrtab[level].arg = arg; 457 458 return (void *)-1; 459} 460 461void 462cpu_intr(status, cause, pc, ipending) 463 u_int32_t status; 464 u_int32_t cause; 465 u_int32_t pc; 466 u_int32_t ipending; 467{ 468 struct clockframe cf; 469 static u_int32_t cycles; 470 int i; 471 472 uvmexp.intrs++; 473 474 if (ipending & MIPS_INT_MASK_0) { 475 volatile u_int32_t *irq_src = 476 (u_int32_t *)MIPS_PHYS_TO_KSEG1(0x14000c18); 477 478 if (*irq_src & 0x00000100) { 479 *irq_src = 0; 480 481 cf.pc = pc; 482 cf.sr = status; 483 484 hardclock(&cf); 485 } 486 cause &= ~MIPS_INT_MASK_0; 487 } 488 489 for (i = 0; i < 5; i++) { 490 if (ipending & (MIPS_INT_MASK_0 << i)) 491 if (intrtab[i].func != NULL) 492 if ((*intrtab[i].func)(intrtab[i].arg)) 493 cause &= ~(MIPS_INT_MASK_0 << i); 494 } 495 496 if (ipending & MIPS_INT_MASK_5) { 497 cycles = mips3_cp0_count_read(); 498 mips3_cp0_compare_write(cycles + 1250000); /* XXX */ 499 500#if 0 501 cf.pc = pc; 502 cf.sr = status; 503 504 statclock(&cf); 505#endif 506 cause &= ~MIPS_INT_MASK_5; 507 } 508 509 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 510 511 /* 'softnet' interrupt */ 512 if (ipending & MIPS_SOFT_INT_MASK_1) { 513 clearsoftnet(); 514 uvmexp.softs++; 515 netintr(); 516 } 517 518 /* 'softclock' interrupt */ 519 if (ipending & MIPS_SOFT_INT_MASK_0) { 520 clearsoftclock(); 521 uvmexp.softs++; 522 intrcnt[SOFTCLOCK_INTR]++; 523 softclock(NULL); 524 } 525} 526