1/* $NetBSD: machdep.c,v 1.5 2011/06/12 03:21:21 tsutsui 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 * from: Utah Hdr: machdep.c 1.63 91/04/24 39 */ 40 41#include <sys/cdefs.h> 42__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.5 2011/06/12 03:21:21 tsutsui Exp $"); 43 44#include "opt_ddb.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/extent.h> 49#include <sys/kernel.h> 50#include <sys/buf.h> 51#include <sys/mbuf.h> 52#include <sys/reboot.h> 53#include <sys/mount.h> 54#include <sys/kcore.h> 55#include <sys/boot_flag.h> 56#include <sys/ksyms.h> 57#include <sys/proc.h> 58#include <sys/device.h> 59 60#include <uvm/uvm_extern.h> 61 62#include <dev/cons.h> 63 64#include <ufs/mfs/mfs_extern.h> /* mfs_initminiroot() */ 65 66#include <mips/cache.h> 67#include <machine/psl.h> 68#include <machine/autoconf.h> 69#include <emips/stand/common/prom_iface.h> 70#include <machine/sysconf.h> 71#include <machine/bootinfo.h> 72#include <machine/locore.h> 73#include <emips/emips/machdep.h> 74#include <machine/emipsreg.h> 75 76#define _EMIPS_BUS_DMA_PRIVATE 77#include <machine/bus.h> 78 79#if NKSYMS || defined(DDB) || defined(MODULAR) 80#include <machine/db_machdep.h> 81#include <ddb/db_extern.h> 82#endif 83 84extern vaddr_t iospace; 85extern vsize_t iospace_size; 86 87#include "ksyms.h" 88 89/* Our exported CPU info; we can have only one. */ 90struct cpu_info cpu_info_store; 91 92/* 93 * Extent map to manage I/O register space. We allocate storage for 94 * 32 regions in the map. iomap_ex_malloc_safe will indicate that it's 95 * safe to use malloc() to dynamically allocate region descriptors in 96 * case we run out. 97 */ 98static long iomap_ex_storage[EXTENT_FIXED_STORAGE_SIZE(32) / sizeof(long)]; 99static struct extent *iomap_ex; 100static int iomap_ex_malloc_safe; 101 102/* maps for VM objects */ 103struct vm_map *phys_map = NULL; 104 105int systype; /* mother board type */ 106char *bootinfo = NULL; /* pointer to bootinfo structure */ 107int cpuspeed = 30; /* approx # instr per usec. */ 108int physmem; /* max supported memory, changes to actual */ 109intptr_t physmem_boardmax; /* {model,SIMM}-specific bound on physmem */ 110int mem_cluster_cnt; 111phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 112 113void mach_init (int, char *[], int, intptr_t, u_int, char *); /* XXX */ 114 115/* Motherboard or system-specific initialization vector */ 116static void unimpl_bus_reset(void); 117static void unimpl_cons_init(void); 118static void unimpl_iointr(uint32_t, vaddr_t, uint32_t); 119static void unimpl_intr_establish(struct device *, void *, int, 120 int (*)(void *, void *), void *); 121static int unimpl_memsize(void *); 122 123struct platform platform = { 124 "iobus not set", 125 unimpl_bus_reset, 126 unimpl_cons_init, 127 unimpl_iointr, 128 unimpl_intr_establish, 129 unimpl_memsize 130}; 131 132extern char *esym; /* XXX */ 133extern struct consdev promcd; /* XXX */ 134extern const struct callback *callv; 135extern const struct callback callvec; 136 137/* 138 * Do all the stuff that locore normally does before calling main(). 139 * The first 4 argments are passed by PROM monitor, and remaining two 140 * are built on temporary stack by our boot loader. 141 */ 142void 143mach_init(int argc, char *argv[], int code, intptr_t cv, u_int bim, char *bip) 144{ 145 char *cp; 146 const char *bootinfo_msg; 147 u_long first, last; 148 int i, howtoboot; 149#if NKSYMS || defined(DDB) || defined(MODULAR) 150 void *ssym = 0; 151 struct btinfo_symtab *bi_syms; 152#endif 153 void *kernend; 154 extern char edata[], end[]; /* XXX */ 155 156 /* Set up bootinfo structure looking at stack. */ 157 if (bim == BOOTINFO_MAGIC) { 158 struct btinfo_magic *bi_magic; 159 160 bootinfo = bip; 161 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 162 if (bi_magic == NULL || bi_magic->magic != BOOTINFO_MAGIC) 163 bootinfo_msg = 164 "invalid magic number in bootinfo structure.\n"; 165 else 166 bootinfo_msg = NULL; 167 } else 168 bootinfo_msg = "invalid bootinfo pointer (old bootblocks?)\n"; 169 170 /* 171 * Look at arguments passed to us and compute boothowto. 172 * Do it before we decide to keep symbols. 173 * NB: "boothowto" is in the BSS. 174 */ 175 howtoboot = 0; 176#ifdef KADB 177 howtoboot |= RB_KDB; 178#endif 179 for (i = 1; i < argc; i++) { 180 for (cp = argv[i]; *cp; cp++) { 181 switch (*cp) { 182 183#define RB_NOSYMBOLS 0x10000000 184 case 'e': /* empty the symtable */ 185 howtoboot |= RB_NOSYMBOLS; 186 break; 187 188 case 'n': /* ask for names */ 189 howtoboot |= RB_ASKNAME; 190 break; 191 192 case 'N': /* don't ask for names */ 193 howtoboot &= ~RB_ASKNAME; 194 break; 195 196 default: 197 BOOT_FLAG(*cp, howtoboot); /* see sys/boot_flag.h */ 198 break; 199 } 200 } 201 } 202 203 /* clear the BSS segment */ 204#if NKSYMS || defined(DDB) || defined(MODULAR) 205 bi_syms = lookup_bootinfo(BTINFO_SYMTAB); 206 207 /* Was it a valid bootinfo symtab info? */ 208 if ((bi_syms != NULL) && (!(howtoboot & RB_NOSYMBOLS))) { 209 ssym = (void *)(intptr_t)bi_syms->ssym; 210 esym = (void *)(intptr_t)bi_syms->esym; 211 kernend = (void *)mips_round_page(esym); 212 memset(edata, 0, end - edata); 213 } else 214#endif 215 { 216 kernend = (char *)mips_round_page(end); 217 /* should be done by bootloader? */ 218 memset(edata, 0, (char *)kernend - (char *)edata); 219 } 220 221 /* Initialize callv so we can do PROM output... */ 222 callv = (code == PROM_MAGIC) ? (void *)cv : &callvec; 223 224 /* Use PROM console output until we initialize a console driver. */ 225 cn_tab = &promcd; 226 227#if 1 228 if (bootinfo_msg != NULL) 229 printf(bootinfo_msg); 230#endif 231 /* 232 * Set the VM page size. 233 */ 234 uvm_setpagesize(); 235 236 /* 237 * Copy exception-dispatch code down to exception vector. 238 * Initialize locore-function vector. 239 * Clear out the I and D caches. 240 */ 241 mips_vector_init(NULL, false); 242 243 /* 244 * We know the CPU type now. Initialize our DMA tags (might 245 * need this early, for certain types of console devices!!). 246 */ 247 emips_bus_dma_init(); 248 249 /* Look at argv[0] and compute bootdev */ 250 makebootdev(argv[0]); 251 252 boothowto = howtoboot & ~RB_NOSYMBOLS; 253 254 /* 255 * Check to see if a mini-root was loaded into memory. It resides 256 * at the start of the next page just after the end of BSS. 257 */ 258 if (boothowto & RB_MINIROOT) 259 kernend = (char *)kernend 260 + round_page(mfs_initminiroot(kernend)); 261 262#if NKSYMS || defined(DDB) || defined(MODULAR) 263 /* init symbols if present */ 264 if (esym) { 265 ksyms_addsyms_elf((char *)esym - (char *)ssym, ssym, esym); 266 } 267#endif 268#ifdef DDB 269 if (boothowto & RB_KDB) 270 Debugger(); 271#endif 272 273 /* 274 * Initialize physmem_boardmax; assume no SIMM-bank limits. 275 * Adjust later in model-specific code if necessary. 276 */ 277 physmem_boardmax = MIPS_MAX_MEM_ADDR; 278 279 /* 280 * Determine what model of computer we are running on. 281 */ 282 systype = ((prom_systype() >> 16) & 0xff); 283 if (systype >= nsysinit) { 284 platform_not_supported(); 285 /* NOTREACHED */ 286 } 287 288 /* Machine specific initialization. */ 289 (*sysinit[systype].init)(); 290 291 /* Find out how much memory is available. */ 292 physmem = (*platform.memsize)(kernend); 293 294 /* 295 * Load the rest of the available pages into the VM system. 296 * NB: The kernel can span multiple segments. 297 */ 298 for (i = 0, physmem = 0; i < mem_cluster_cnt; ++i) { 299 first = mem_clusters[i].start; 300 if (first < round_page(MIPS_KSEG0_TO_PHYS(kernend))) 301 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 302 last = mem_clusters[i].start + mem_clusters[i].size; 303 physmem += atop(mem_clusters[i].size); 304 305 /* if the kernel spans multiple segments (does on ML40x) */ 306 if (last <= first) 307 continue; 308 309 uvm_page_physload(atop(first), atop(last), atop(first), 310 atop(last), VM_FREELIST_DEFAULT); 311 } 312 313 /* 314 * Initialize error message buffer (at end of core). 315 */ 316 mips_init_msgbuf(); 317 318 /* 319 * Initialize the virtual memory system. 320 */ 321 iospace_size = 64*1024; /* BUGBUG make it an option? */ 322 pmap_bootstrap(); 323 324 mips_init_lwp0_uarea(); 325} 326 327void 328mips_machdep_cache_config(void) 329{ 330} 331 332void 333consinit(void) 334{ 335 /* 336 * Init I/O memory extent map. Must be done before cninit() 337 * is called; we may want to use iospace in the console routines. 338 */ 339 KASSERT(iospace != 0); 340 iomap_ex = extent_create("iomap", iospace, 341 iospace + iospace_size - 1, 342 (void *) iomap_ex_storage, sizeof(iomap_ex_storage), 343 EX_NOCOALESCE|EX_NOWAIT); 344 345 /* 346 * Up until now we have kept the TLB disabled, 347 * and that allowed the "PROM" to work. 348 * Specifically, romputc() and the debugger's getc() functions worked. 349 * Now is the last chance we get to turn it on. 350 * That means no more console I/O until autoconf() [sigh!], or.. 351 * The platform-specific code will have to map [1:1 probably] 352 * the I/O registers. 353 */ 354 register_t s = mips_cp0_status_read(); 355 s &= ~MIPS_SR_TS; 356 mips_cp0_status_write(s); 357 358 (*platform.cons_init)(); 359 360 /* Do NOT call cninit(); It will clobber cn_tab using constab[] which we do not use 361 */ 362} 363 364/* 365 * Allocates a virtual range suitable for mapping in physical memory. 366 * Uses resource maps when allocating space, which is allocated from 367 * the IOMAP submap. SIZE is a linear range (NOT vax-pages like the VAX). 368 * If the page requested is bigger than a logical page, space is 369 * allocated from the kernel map instead. 370 */ 371vaddr_t 372mips_map_physmem(paddr_t phys, vsize_t size) 373{ 374 vaddr_t addr; 375 int error; 376 static int warned = 0; 377 378 size += phys & PAGE_MASK; 379 if (size >= PAGE_SIZE) { 380 addr = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY); 381 if (addr == 0) 382 panic("mips_map_physmem: kernel map full"); 383 } else { 384 error = extent_alloc(iomap_ex, size, PAGE_SIZE, 0, 385 EX_FAST | EX_NOWAIT | 386 (iomap_ex_malloc_safe ? EX_MALLOCOK : 0), (u_long *)&addr); 387 if (error) { 388 if (warned++ == 0) /* Warn only once */ 389 printf("mips_map_physmem: iomap too small"); 390 return 0; 391 } 392 } 393 ioaccess(addr, phys, size); 394#ifdef PHYSMEMDEBUG 395 printf("mips_map_physmem: alloc'ed %lx bytes for paddr %lx, at %lx\n", 396 size, phys, addr); 397#endif 398 return addr | (phys & PAGE_MASK); 399} 400 401/* 402 * Unmaps the previous mapped (addr, size) pair. 403 */ 404void 405mips_unmap_physmem(vaddr_t addr, vsize_t size) 406{ 407#ifdef PHYSMEMDEBUG 408 printf("mips_unmap_physmem: unmapping %lx bytes at addr %lx\n", 409 size, addr); 410#endif 411 size += addr & PAGE_MASK; 412 addr &= ~PAGE_MASK; 413 414 iounaccess(addr, size); 415 if (size >= PAGE_SIZE) 416 uvm_km_free(kernel_map, addr, size, UVM_KMF_VAONLY); 417 else if (extent_free(iomap_ex, addr, size, 418 EX_NOWAIT | (iomap_ex_malloc_safe ? EX_MALLOCOK : 0))) 419 printf("mips_unmap_physmem: addr 0x%llx size %llx: " 420 "can't free region\n", (long long)addr, (long long)size); 421} 422 423/* 424 * Machine-dependent startup code: allocate memory for variable-sized 425 * tables. 426 */ 427void 428cpu_startup(void) 429{ 430 vaddr_t minaddr, maxaddr; 431 char pbuf[9]; 432#ifdef DEBUG 433 extern int pmapdebug; /* XXX */ 434 int opmapdebug = pmapdebug; 435 436 pmapdebug = 0; 437#endif 438 439 /* 440 * Good {morning,afternoon,evening,night}. 441 */ 442 printf("%s%s", copyright, version); 443 printf("%s\n", cpu_model); 444 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 445 printf("total memory = %s\n", pbuf); 446 447 minaddr = 0; 448 449 /* 450 * Allocate a submap for physio 451 */ 452 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 453 VM_PHYS_SIZE, 0, false, NULL); 454 455 /* 456 * No need to allocate an mbuf cluster submap. Mbuf clusters 457 * are allocated via the pool allocator, and we use KSEG to 458 * map those pages. 459 */ 460 461 iomap_ex_malloc_safe = 1; 462 463#ifdef DEBUG 464 pmapdebug = opmapdebug; 465#endif 466 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 467 printf("avail memory = %s\n", pbuf); 468} 469 470/* 471 * Look up information in bootinfo of boot loader. 472 */ 473void * 474lookup_bootinfo(int type) 475{ 476 struct btinfo_common *bt; 477 char *help = bootinfo; 478 479 /* Check for a bootinfo record first. */ 480 if (help == NULL) 481 return (NULL); 482 483 do { 484 bt = (struct btinfo_common *)help; 485 if (bt->type == type) 486 return ((void *)help); 487 help += bt->next; 488 } while (bt->next != 0 && 489 (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); 490 491 return (NULL); 492} 493 494void 495cpu_reboot(volatile int howto, /* XXX volatile to keep gcc happy */ 496 char *bootstr) 497{ 498 int s = 0; 499 500 /* take a snap shot before clobbering any registers */ 501 if (curlwp) 502 savectx(curpcb); 503 504#ifdef DEBUG 505 if (panicstr) 506 stacktrace(); 507#endif 508 509 /* If system is cold, just halt. */ 510 if (cold) { 511 howto |= RB_HALT; 512 goto haltsys; 513 } 514 515 /* If "always halt" was specified as a boot flag, obey. */ 516 if ((boothowto & RB_HALT) != 0) 517 howto |= RB_HALT; 518 519 boothowto = howto; 520 if ((howto & RB_NOSYNC) == 0) { 521 /* 522 * Synchronize the disks.... 523 */ 524 vfs_shutdown(); 525 526 /* 527 * If we've been adjusting the clock, the todr 528 * will be out of synch; adjust it now. 529 */ 530 resettodr(); 531 } 532 533 /* Disable interrupts. */ 534 s = splhigh(); 535 536 /* If rebooting and a dump is requested do it. */ 537 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 538 dumpsys(); 539 540haltsys: 541 /* run any shutdown hooks */ 542 doshutdownhooks(); 543 544 pmf_system_shutdown(boothowto); 545 546 /* Finally, halt/reboot the system. */ 547 printf("%s\n\n", ((howto & RB_HALT) != 0) ? "halted." : "rebooting..."); 548 549 prom_halt(howto); 550 for (;;) ; 551 /*NOTREACHED*/ 552} 553 554#if defined(MIPS_4GB_PHYSICAL_MEMORY) 555#define trim_memory(n) n 556#else 557#if 0 558#define TOO_MUCH (MIPS_PHYS_MASK+1) 559#else 560#define TOO_MUCH (2*64*1024*1024) 561#endif 562u_long trim_memory(uint32_t nbytes);/*cheat*/ 563u_long trim_memory(uint32_t nbytes) 564{ 565 int i; 566 u_long first, last; 567 568 nbytes *= 4096; 569 if (nbytes <= TOO_MUCH) 570 return nbytes; 571 572 /* We have more memory than we can handle */ 573 574 mem_clusters[mem_cluster_cnt].start = 0;/* sentinel record */ 575 mem_clusters[mem_cluster_cnt].size = 0; 576 for (i = 0; i < mem_cluster_cnt;) { 577 first = mem_clusters[i].start; 578 last = mem_clusters[i].start + mem_clusters[i].size; 579 580 if (first > TOO_MUCH) { 581 printf("Too much memory, ignoring memory " 582 "range %08lx..%08lx\n", first, last); 583 memcpy(mem_clusters+i,mem_clusters+i+1, 584 (sizeof(mem_clusters[0])*(mem_cluster_cnt-i))); 585 mem_cluster_cnt--; 586 continue; 587 } 588 589 if (last > TOO_MUCH) { 590 last = TOO_MUCH; 591 printf("Too much memory in cluster %d, trimming " 592 "memory to range %08lx..%08lx\n", 593 i, first, last); 594 mem_clusters[i].size = last - mem_clusters[i].start; 595 } 596 i++; 597 } 598 return TOO_MUCH; 599} 600#endif 601 602/* 603 * Find out how much memory is available by testing memory. 604 */ 605int 606memsize_scan(void *first) 607{ 608 int i, mem; 609 char *cp; 610 611 mem = btoc((paddr_t)first - MIPS_KSEG0_START); 612 cp = (char *)MIPS_PHYS_TO_KSEG1(mem << PGSHIFT); 613 while (cp < (char *)physmem_boardmax) { 614 int j; 615 if (badaddr(cp, 4)) 616 break; 617 i = *(int *)cp; 618 j = ((int *)cp)[4]; 619 *(int *)cp = 0xa5a5a5a5; 620 /* 621 * Data will persist on the bus if we read it right away. 622 * Have to be tricky here. 623 */ 624 ((int *)cp)[4] = 0x5a5a5a5a; 625 wbflush(); 626 if (*(int *)cp != 0xa5a5a5a5) 627 break; 628 *(int *)cp = i; 629 ((int *)cp)[4] = j; 630 cp += PAGE_SIZE; 631 mem++; 632 } 633 634 /* 635 * Now that we know how much memory we have, initialize the 636 * mem cluster array. 637 */ 638 mem_clusters[0].start = 0; /* XXX is this correct? */ 639 mem_clusters[0].size = ctob(mem); 640 mem_cluster_cnt = 1; 641 642 /* clear any memory error conditions possibly caused by probe */ 643 (*platform.bus_reset)(); 644 return (mem); 645} 646 647/* 648 * Find out how much memory is available by testing memory, starting at first. 649 * Returns the total number of pages. 650 */ 651int 652memsize_pmt(void * first) 653{ 654 int i, mem; 655 struct _Pmt *Pmt = ThePmt; 656 struct _Sram *ram; 657 uint32_t addr, len; 658 659 /* 660 * Build the RAM memory map from the PMT. 661 */ 662 mem = 0; 663 for (i = 0; i < VM_PHYSSEG_MAX; Pmt--) { 664 uint16_t tag = Pmt->Tag; 665 666 if (tag == PMTTAG_END_OF_TABLE) 667 break; 668 669 if ((tag != PMTTAG_SRAM) && (tag != PMTTAG_DDRAM)) 670 continue; 671 672 /* 673 * Got a memory controller segment, 674 * scan all the controllers in it 675 */ 676 ram = (struct _Sram *)(Pmt->TopOfPhysicalAddress << 16); 677 678 for (;(ram->BaseAddressAndTag & SRAMBT_TAG) == tag;) { 679 addr = ram->BaseAddressAndTag & SRAMBT_BASE; 680 len = ram->Control & SRAMST_SIZE; 681 682 mem_clusters[i].start = addr; 683 mem_clusters[i].size = len; 684 printf("memory segment %2d start %08lx size %08lx\n", i, 685 (long)mem_clusters[i].start, 686 (long)mem_clusters[i].size); 687 i++; 688 mem += len; 689 690 /* SRAM and DDRAM have different sizes */ 691 ram = (tag == PMTTAG_SRAM) ? ram+1 : ram+2; 692 } 693 } 694 mem_cluster_cnt = i; 695 696 return trim_memory(btoc(mem)); 697} 698/* 699 * Ensure all platform vectors are always initialized. 700 */ 701static void 702unimpl_bus_reset(void) 703{ 704 705 panic("sysconf.init didn't set bus_reset"); 706} 707 708static void 709unimpl_cons_init(void) 710{ 711 712 panic("sysconf.init didn't set cons_init"); 713} 714 715static void 716unimpl_iointr(uint32_t status, vaddr_t pc, uint32_t ipending) 717{ 718 719 panic("sysconf.init didn't set intr"); 720} 721 722static void 723unimpl_intr_establish(struct device *dev, void *cookie, int level, 724 int (*handler) (void *,void *), void *arg) 725{ 726 727 panic("sysconf.init didn't set intr_establish"); 728} 729 730static int 731unimpl_memsize(void * first) 732{ 733 734 panic("sysconf.init didn't set memsize"); 735} 736 737/* 738 * Wait "n" microseconds. 739 */ 740void 741delay(int n) 742{ 743 744 DELAY(n); 745} 746