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