1 /* $NetBSD: machdep.c,v 1.38 2003/04/26 11:05:15 ragge 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. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * @(#)machdep.c 8.3 (Berkeley) 1/12/94 42 */ 43 44 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 45 46 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.38 2003/04/26 11:05:15 ragge Exp $"); 47 48 /* from: Utah Hdr: machdep.c 1.63 91/04/24 */ 49 50 #include "opt_ddb.h" 51 #include "opt_kgdb.h" 52 53 #include <sys/param.h> 54 #include <sys/signalvar.h> 55 #include <sys/kernel.h> 56 #include <sys/proc.h> 57 #include <sys/buf.h> 58 #include <sys/reboot.h> 59 #include <sys/conf.h> 60 #include <sys/file.h> 61 #include <sys/callout.h> 62 #include <sys/malloc.h> 63 #include <sys/mbuf.h> 64 #include <sys/msgbuf.h> 65 #include <sys/ioctl.h> 66 #include <sys/device.h> 67 #include <sys/user.h> 68 #include <sys/exec.h> 69 #include <sys/mount.h> 70 #include <sys/sa.h> 71 #include <sys/syscallargs.h> 72 #include <sys/kcore.h> 73 #include <sys/ksyms.h> 74 75 #include <uvm/uvm_extern.h> 76 77 #include <ufs/mfs/mfs_extern.h> /* mfs_initminiroot() */ 78 79 #include <machine/cpu.h> 80 #include <machine/reg.h> 81 #include <machine/psl.h> 82 #include <machine/pte.h> 83 84 #ifdef DDB 85 #include <machine/db_machdep.h> 86 #include <ddb/db_extern.h> 87 #endif 88 89 #include <machine/intr.h> 90 #include <machine/mainboard.h> 91 #include <machine/sysconf.h> 92 #include <machine/autoconf.h> 93 #include <machine/bootinfo.h> 94 #include <machine/prom.h> 95 #include <dev/clock_subr.h> 96 #include <dev/cons.h> 97 98 #include <sys/boot_flag.h> 99 100 #include "fs_mfs.h" 101 #include "opt_ddb.h" 102 #include "opt_execfmt.h" 103 104 #include "zsc.h" /* XXX */ 105 #include "com.h" /* XXX */ 106 #include "ksyms.h" 107 108 /* the following is used externally (sysctl_hw) */ 109 extern char cpu_model[]; 110 111 /* Our exported CPU info; we can have only one. */ 112 struct cpu_info cpu_info_store; 113 114 /* maps for VM objects */ 115 116 struct vm_map *exec_map = NULL; 117 struct vm_map *mb_map = NULL; 118 struct vm_map *phys_map = NULL; 119 120 int physmem; /* max supported memory, changes to actual */ 121 char *bootinfo = NULL; /* pointer to bootinfo structure */ 122 123 phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; 124 int mem_cluster_cnt; 125 126 void to_monitor __P((int)) __attribute__((__noreturn__)); 127 void prom_halt __P((int)) __attribute__((__noreturn__)); 128 129 #ifdef KGDB 130 void zs_kgdb_init __P((void)); 131 void kgdb_connect __P((int)); 132 #endif 133 134 struct evcnt soft_evcnt[IPL_NSOFT]; 135 136 /* 137 * Local functions. 138 */ 139 int initcpu __P((void)); 140 void configure __P((void)); 141 142 void mach_init __P((int, char *[], char*[], u_int, char *)); 143 int memsize_scan __P((caddr_t)); 144 145 #ifdef DEBUG 146 /* stacktrace code violates prototypes to get callee's registers */ 147 extern void stacktrace __P((void)); /*XXX*/ 148 #endif 149 150 /* 151 * safepri is a safe priority for sleep to set for a spin-wait 152 * during autoconfiguration or after a panic. Used as an argument to splx(). 153 * XXX disables interrupt 5 to disable mips3 on-chip clock, which also 154 * disables mips1 FPU interrupts. 155 */ 156 int safepri = MIPS3_PSL_LOWIPL; /* XXX */ 157 extern struct user *proc0paddr; 158 159 /* locore callback-vector setup */ 160 extern void mips_vector_init __P((void)); 161 extern void prom_init __P((void)); 162 extern void pizazz_init __P((void)); 163 164 /* platform-specific initialization vector */ 165 static void unimpl_cons_init __P((void)); 166 static void unimpl_iointr __P((unsigned, unsigned, unsigned, unsigned)); 167 static int unimpl_memsize __P((caddr_t)); 168 static unsigned unimpl_clkread __P((void)); 169 static void unimpl_todr __P((struct clock_ymdhms *)); 170 static void unimpl_intr_establish __P((int, int (*)__P((void *)), void *)); 171 172 struct platform platform = { 173 "iobus not set", 174 unimpl_cons_init, 175 unimpl_iointr, 176 unimpl_memsize, 177 unimpl_clkread, 178 unimpl_todr, 179 unimpl_todr, 180 unimpl_intr_establish, 181 }; 182 183 struct consdev *cn_tab = NULL; 184 extern struct consdev consdev_prom; 185 extern struct consdev consdev_zs; 186 187 static void null_cnprobe __P((struct consdev *)); 188 static void prom_cninit __P((struct consdev *)); 189 static int prom_cngetc __P((dev_t)); 190 static void prom_cnputc __P((dev_t, int)); 191 static void null_cnpollc __P((dev_t, int)); 192 193 struct consdev consdev_prom = { 194 null_cnprobe, 195 prom_cninit, 196 prom_cngetc, 197 prom_cnputc, 198 null_cnpollc, 199 }; 200 201 202 /* 203 * Do all the stuff that locore normally does before calling main(). 204 * Process arguments passed to us by the prom monitor. 205 * Return the first page address following the system. 206 */ 207 void 208 mach_init(argc, argv, envp, bim, bip) 209 int argc; 210 char *argv[]; 211 char *envp[]; 212 u_int bim; 213 char *bip; 214 { 215 u_long first, last; 216 caddr_t kernend, v; 217 vsize_t size; 218 char *cp; 219 int i, howto; 220 extern char edata[], end[]; 221 char *bi_msg; 222 #if NKSYMS || defined(DDB) || defined(LKM) 223 int nsym = 0; 224 caddr_t ssym = 0; 225 caddr_t esym = 0; 226 struct btinfo_symtab *bi_syms; 227 #endif 228 229 230 /* Check for valid bootinfo passed from bootstrap */ 231 if (bim == BOOTINFO_MAGIC) { 232 struct btinfo_magic *bi_magic; 233 234 bootinfo = (char *)BOOTINFO_ADDR; /* XXX */ 235 bi_magic = lookup_bootinfo(BTINFO_MAGIC); 236 if (bi_magic == NULL || bi_magic->magic != BOOTINFO_MAGIC) 237 bi_msg = "invalid bootinfo structure.\n"; 238 else 239 bi_msg = NULL; 240 } else 241 bi_msg = "invalid bootinfo (standalone boot?)\n"; 242 243 /* clear the BSS segment */ 244 kernend = (caddr_t)mips_round_page(end); 245 memset(edata, 0, end - edata); 246 247 #if NKSYMS || defined(DDB) || defined(LKM) 248 bi_syms = lookup_bootinfo(BTINFO_SYMTAB); 249 250 /* Load sysmbol table if present */ 251 if (bi_syms != NULL) { 252 nsym = bi_syms->nsym; 253 ssym = (caddr_t)bi_syms->ssym; 254 esym = (caddr_t)bi_syms->esym; 255 kernend = (caddr_t)mips_round_page(esym); 256 } 257 #endif 258 259 prom_init(); 260 consinit(); 261 262 if (bi_msg != NULL) 263 printf(bi_msg); 264 265 /* 266 * Set the VM page size. 267 */ 268 uvm_setpagesize(); 269 270 /* Find out how much memory is available. */ 271 physmem = memsize_scan(kernend); 272 273 /* 274 * Now that we know how much memory we have, initialize the 275 * mem cluster array. 276 */ 277 mem_clusters[0].start = 0; /* XXX is this correct? */ 278 mem_clusters[0].size = ctob(physmem); 279 mem_cluster_cnt = 1; 280 281 /* 282 * Copy exception-dispatch code down to exception vector. 283 * Initialize locore-function vector. 284 * Clear out the I and D caches. 285 */ 286 mips_vector_init(); 287 288 /* Look at argv[0] and compute bootdev */ 289 makebootdev(argv[0]); 290 291 /* 292 * Look at arguments passed to us and compute boothowto. 293 */ 294 boothowto = RB_AUTOBOOT; 295 for (i = 1; i < argc; i++) { 296 for (cp = argv[i]; *cp; cp++) { 297 /* Ignore superfluous '-', if there is one */ 298 if (*cp == '-') 299 continue; 300 301 howto = 0; 302 BOOT_FLAG(*cp, howto); 303 if (! howto) 304 printf("bootflag '%c' not recognised\n", *cp); 305 else 306 boothowto |= howto; 307 } 308 } 309 310 311 #if NKSYMS || defined(DDB) || defined(LKM) 312 /* init symbols if present */ 313 if (esym) 314 ksyms_init(esym - ssym, ssym, esym); 315 #endif 316 #ifdef DDB 317 if (boothowto & RB_KDB) 318 Debugger(); 319 #endif 320 #ifdef KGDB 321 zs_kgdb_init(); /* XXX */ 322 if (boothowto & RB_KDB) 323 kgdb_connect(0); 324 #endif 325 326 #ifdef MFS 327 /* 328 * Check to see if a mini-root was loaded into memory. It resides 329 * at the start of the next page just after the end of BSS. 330 */ 331 if (boothowto & RB_MINIROOT) 332 kernend += round_page(mfs_initminiroot(kernend)); 333 #endif 334 335 /* 336 * Load the rest of the available pages into the VM system. 337 */ 338 first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); 339 last = mem_clusters[0].start + mem_clusters[0].size; 340 uvm_page_physload(atop(first), atop(last), atop(first), atop(last), 341 VM_FREELIST_DEFAULT); 342 343 /* 344 * Initialize error message buffer (at end of core). 345 */ 346 mips_init_msgbuf(); 347 348 /* 349 * Compute the size of system data structures. pmap_bootstrap() 350 * needs some of this information. 351 */ 352 size = (vsize_t)allocsys(NULL, NULL); 353 354 /* 355 * Initialize the virtual memory system. 356 */ 357 pmap_bootstrap(); 358 359 /* 360 * Allocate space for proc0's USPACE. 361 */ 362 v = (caddr_t)uvm_pageboot_alloc(USPACE); 363 lwp0.l_addr = proc0paddr = (struct user *)v; 364 lwp0.l_md.md_regs = (struct frame *)(v + USPACE) - 1; 365 curpcb = &lwp0.l_addr->u_pcb; 366 curpcb->pcb_context[11] = MIPS_INT_MASK | MIPS_SR_INT_IE; /* SR */ 367 368 /* 369 * Allocate space for system data structures. These data structures 370 * are allocated here instead of cpu_startup() because physical 371 * memory is directly addressable. We don't have to map these into 372 * virtual address space. 373 */ 374 v = (caddr_t)uvm_pageboot_alloc(size); 375 if ((allocsys(v, NULL) - v) != size) 376 panic("mach_init: table size inconsistency"); 377 /* 378 * Set up interrupt handling and I/O addresses. 379 */ 380 381 pizazz_init(); 382 } 383 384 385 386 /* 387 * cpu_startup: allocate memory for variable-sized tables, 388 * initialize cpu, and do autoconfiguration. 389 */ 390 void 391 cpu_startup() 392 { 393 u_int i, base, residual; 394 vaddr_t minaddr, maxaddr; 395 vsize_t size; 396 char pbuf[9]; 397 #ifdef DEBUG 398 extern int pmapdebug; 399 int opmapdebug = pmapdebug; 400 401 pmapdebug = 0; 402 #endif 403 404 /* 405 * Good {morning,afternoon,evening,night}. 406 */ 407 printf(version); 408 printf("%s\n", cpu_model); 409 format_bytes(pbuf, sizeof(pbuf), ctob(physmem)); 410 printf("total memory = %s\n", pbuf); 411 412 /* 413 * Allocate virtual address space for file I/O buffers. 414 * Note they are different than the array of headers, 'buf', 415 * and usually occupy more virtual memory than physical. 416 */ 417 size = MAXBSIZE * nbuf; 418 if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(size), 419 NULL, UVM_UNKNOWN_OFFSET, 0, 420 UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 421 UVM_ADV_NORMAL, 0)) != 0) 422 panic("startup: cannot allocate VM for buffers"); 423 minaddr = (vaddr_t)buffers; 424 base = bufpages / nbuf; 425 residual = bufpages % nbuf; 426 for (i = 0; i < nbuf; i++) { 427 vsize_t curbufsize; 428 vaddr_t curbuf; 429 struct vm_page *pg; 430 431 /* 432 * Each buffer has MAXBSIZE bytes of VM space allocated. Of 433 * that MAXBSIZE space, we allocate and map (base+1) pages 434 * for the first "residual" buffers, and then we allocate 435 * "base" pages for the rest. 436 */ 437 curbuf = (vaddr_t) buffers + (i * MAXBSIZE); 438 curbufsize = PAGE_SIZE * ((i < residual) ? (base+1) : base); 439 440 while (curbufsize) { 441 pg = uvm_pagealloc(NULL, 0, NULL, 0); 442 if (pg == NULL) 443 panic("cpu_startup: not enough memory for " 444 "buffer cache"); 445 pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 446 VM_PROT_READ|VM_PROT_WRITE); 447 curbuf += PAGE_SIZE; 448 curbufsize -= PAGE_SIZE; 449 } 450 } 451 pmap_update(pmap_kernel()); 452 453 /* 454 * Allocate a submap for exec arguments. This map effectively 455 * limits the number of processes exec'ing at any time. 456 */ 457 exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 458 16 * NCARGS, TRUE, FALSE, NULL); 459 /* 460 * Allocate a submap for physio 461 */ 462 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 463 VM_PHYS_SIZE, TRUE, FALSE, NULL); 464 465 /* 466 * No need to allocate an mbuf cluster submap. Mbuf clusters 467 * are allocated via the pool allocator, and we use KSEG to 468 * map those pages. 469 */ 470 471 #ifdef DEBUG 472 pmapdebug = opmapdebug; 473 #endif 474 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free)); 475 printf("avail memory = %s\n", pbuf); 476 format_bytes(pbuf, sizeof(pbuf), bufpages * PAGE_SIZE); 477 printf("using %u buffers containing %s of memory\n", nbuf, pbuf); 478 479 /* 480 * Set up buffers, so they can be used to read disk labels. 481 */ 482 bufinit(); 483 } 484 485 /* 486 * Look up information in bootinfo of boot loader. 487 */ 488 void * 489 lookup_bootinfo(type) 490 int type; 491 { 492 struct btinfo_common *bt; 493 char *help = bootinfo; 494 495 /* Check for a bootinfo record first. */ 496 if (help == NULL) 497 return (NULL); 498 499 do { 500 bt = (struct btinfo_common *)help; 501 if (bt->type == type) 502 return ((void *)help); 503 help += bt->next; 504 } while (bt->next != 0 && 505 (size_t)help < (size_t)bootinfo + BOOTINFO_SIZE); 506 507 return (NULL); 508 } 509 510 int waittime = -1; 511 512 /* 513 * call PROM to halt or reboot. 514 */ 515 void 516 prom_halt(howto) 517 int howto; 518 { 519 if (howto & RB_HALT) 520 MIPS_PROM(reinit)(); 521 MIPS_PROM(reboot)(); 522 /* NOTREACHED */ 523 } 524 525 void 526 cpu_reboot(howto, bootstr) 527 volatile int howto; 528 char *bootstr; 529 { 530 /* take a snap shot before clobbering any registers */ 531 if (curlwp) 532 savectx((struct user *)curpcb); 533 534 #ifdef DEBUG 535 if (panicstr) 536 stacktrace(); 537 #endif 538 539 /* If system is cold, just halt. */ 540 if (cold) { 541 howto |= RB_HALT; 542 goto haltsys; 543 } 544 545 /* If "always halt" was specified as a boot flag, obey. */ 546 if ((boothowto & RB_HALT) != 0) 547 howto |= RB_HALT; 548 549 boothowto = howto; 550 if ((howto & RB_NOSYNC) == 0 && waittime < 0) { 551 /* 552 * Synchronize the disks.... 553 */ 554 waittime = 0; 555 vfs_shutdown(); 556 557 /* 558 * If we've been adjusting the clock, the todr 559 * will be out of synch; adjust it now. 560 */ 561 resettodr(); 562 } 563 564 /* Disable interrupts. */ 565 splhigh(); 566 567 /* If rebooting and a dump is requested do it. */ 568 #if 0 569 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) 570 #else 571 if (howto & RB_DUMP) 572 #endif 573 dumpsys(); 574 575 haltsys: 576 577 /* run any shutdown hooks */ 578 doshutdownhooks(); 579 580 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) 581 prom_halt(0x80); /* rom monitor RB_PWOFF */ 582 583 /* Finally, halt/reboot the system. */ 584 printf("%s\n\n", howto & RB_HALT ? "halted." : "rebooting..."); 585 prom_halt(howto & RB_HALT); 586 /*NOTREACHED*/ 587 } 588 589 /* 590 * Return the best possible estimate of the time in the timeval 591 * to which tvp points. Unfortunately, we can't read the hardware registers. 592 * We guarantee that the time will be greater than the value obtained by a 593 * previous call. 594 */ 595 void 596 microtime(tvp) 597 register struct timeval *tvp; 598 { 599 static struct timeval lasttime; 600 int s = splclock(); 601 602 *tvp = time; 603 604 tvp->tv_usec += (*platform.clkread)(); 605 606 while (tvp->tv_usec >= 1000000) { 607 tvp->tv_usec -= 1000000; 608 tvp->tv_sec++; 609 } 610 611 if (tvp->tv_sec == lasttime.tv_sec && 612 tvp->tv_usec <= lasttime.tv_usec && 613 (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { 614 tvp->tv_sec++; 615 tvp->tv_usec -= 1000000; 616 } 617 lasttime = *tvp; 618 splx(s); 619 } 620 621 int 622 initcpu() 623 { 624 spl0(); /* safe to turn interrupts on now */ 625 return 0; 626 } 627 628 static void 629 unimpl_cons_init() 630 { 631 632 panic("sysconf.init didn't set cons_init"); 633 } 634 635 static void 636 unimpl_iointr(mask, pc, statusreg, causereg) 637 u_int mask; 638 u_int pc; 639 u_int statusreg; 640 u_int causereg; 641 { 642 643 panic("sysconf.init didn't set intr"); 644 } 645 646 static int 647 unimpl_memsize(first) 648 caddr_t first; 649 { 650 651 panic("sysconf.init didn't set memsize"); 652 } 653 654 static unsigned 655 unimpl_clkread() 656 { 657 return 0; /* No microtime available */ 658 } 659 660 static void 661 unimpl_todr(dt) 662 struct clock_ymdhms *dt; 663 { 664 panic("sysconf.init didn't init TOD"); 665 } 666 667 void 668 unimpl_intr_establish(level, func, arg) 669 int level; 670 int (*func) __P((void *)); 671 void *arg; 672 { 673 panic("sysconf.init didn't init intr_establish"); 674 } 675 676 void 677 delay(n) 678 int n; 679 { 680 DELAY(n); 681 } 682 683 /* 684 * Find out how much memory is available by testing memory. 685 * Be careful to save and restore the original contents for msgbuf. 686 */ 687 int 688 memsize_scan(first) 689 caddr_t first; 690 { 691 volatile int *vp, *vp0; 692 int mem, tmp, tmp0; 693 694 #define PATTERN1 0xa5a5a5a5 695 #define PATTERN2 ~PATTERN1 696 697 /* 698 * Non destructive scan of memory to determine the size 699 * Use the first page to test for memory aliases. This 700 * also has the side effect of flushing the bus alignment 701 * buffer 702 */ 703 mem = btoc((paddr_t)first - MIPS_KSEG0_START); 704 vp = (int *)MIPS_PHYS_TO_KSEG1(mem << PGSHIFT); 705 vp0 = (int *)MIPS_PHYS_TO_KSEG1(0); /* Start of physical memory */ 706 tmp0 = *vp0; 707 while (vp < (int *)MIPS_MAX_MEM_ADDR) { 708 tmp = *vp; 709 *vp = PATTERN1; 710 *vp0 = PATTERN2; 711 wbflush(); 712 if (*vp != PATTERN1) 713 break; 714 *vp = PATTERN2; 715 *vp0 = PATTERN1; 716 wbflush(); 717 if (*vp != PATTERN2) 718 break; 719 *vp = tmp; 720 vp += PAGE_SIZE/sizeof(int); 721 mem++; 722 } 723 *vp0 = tmp0; 724 return mem; 725 } 726 727 /* 728 * Console initialization: called early on from main, 729 * before vm init or startup. Do enough configuration 730 * to choose and initialize a console. 731 */ 732 733 static void 734 null_cnprobe(cn) 735 struct consdev *cn; 736 { 737 } 738 739 static void 740 prom_cninit(cn) 741 struct consdev *cn; 742 { 743 extern const struct cdevsw cons_cdevsw; 744 745 cn->cn_dev = makedev(cdevsw_lookup_major(&cons_cdevsw), 0); 746 cn->cn_pri = CN_REMOTE; 747 } 748 749 static int 750 prom_cngetc(dev) 751 dev_t dev; 752 { 753 return MIPS_PROM(getchar)(); 754 } 755 756 static void 757 prom_cnputc(dev, c) 758 dev_t dev; 759 int c; 760 { 761 MIPS_PROM(putchar)(c); 762 } 763 764 static void 765 null_cnpollc(dev, on) 766 dev_t dev; 767 int on; 768 { 769 } 770 771 void 772 consinit() 773 { 774 int zs_unit; 775 776 zs_unit = 0; 777 cn_tab = &consdev_zs; 778 779 (*cn_tab->cn_init)(cn_tab); 780 } 781