1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: machdep.c 1.63 91/04/24$ 13 * 14 * @(#)machdep.c 7.17 (Berkeley) 06/25/91 15 */ 16 17 #include "param.h" 18 #include "systm.h" 19 #include "signalvar.h" 20 #include "kernel.h" 21 #include "map.h" 22 #include "proc.h" 23 #include "buf.h" 24 #include "reboot.h" 25 #include "conf.h" 26 #include "file.h" 27 #include "clist.h" 28 #include "callout.h" 29 #include "malloc.h" 30 #include "mbuf.h" 31 #include "msgbuf.h" 32 #include "user.h" 33 #ifdef SYSVSHM 34 #include "shm.h" 35 #endif 36 #ifdef HPUXCOMPAT 37 #include "../hpux/hpux.h" 38 #endif 39 40 #include "../include/cpu.h" 41 #include "../include/reg.h" 42 #include "../include/psl.h" 43 #include "isr.h" 44 #include "pte.h" 45 #include "net/netisr.h" 46 47 #define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */ 48 #include "vm/vm_param.h" 49 #include "vm/pmap.h" 50 #include "vm/vm_map.h" 51 #include "vm/vm_object.h" 52 #include "vm/vm_kern.h" 53 #include "vm/vm_page.h" 54 55 vm_map_t buffer_map; 56 extern vm_offset_t avail_end; 57 58 /* 59 * Declare these as initialized data so we can patch them. 60 */ 61 int nswbuf = 0; 62 #ifdef NBUF 63 int nbuf = NBUF; 64 #else 65 int nbuf = 0; 66 #endif 67 #ifdef BUFPAGES 68 int bufpages = BUFPAGES; 69 #else 70 int bufpages = 0; 71 #endif 72 int msgbufmapped; /* set when safe to use msgbuf */ 73 int maxmem; /* max memory per process */ 74 int physmem = MAXMEM; /* max supported memory, changes to actual */ 75 /* 76 * safepri is a safe priority for sleep to set for a spin-wait 77 * during autoconfiguration or after a panic. 78 */ 79 int safepri = PSL_LOWIPL; 80 81 extern u_int lowram; 82 83 /* 84 * Console initialization: called early on from main, 85 * before vm init or startup. Do enough configuration 86 * to choose and initialize a console. 87 */ 88 consinit() 89 { 90 91 /* 92 * Set cpuspeed immediately since cninit() called routines 93 * might use delay. 94 */ 95 switch (machineid) { 96 case HP_320: 97 case HP_330: 98 case HP_340: 99 cpuspeed = MHZ_16; 100 break; 101 case HP_350: 102 case HP_360: 103 cpuspeed = MHZ_25; 104 break; 105 case HP_370: 106 cpuspeed = MHZ_33; 107 break; 108 case HP_375: 109 cpuspeed = MHZ_50; 110 break; 111 } 112 /* 113 * Find what hardware is attached to this machine. 114 */ 115 find_devs(); 116 117 /* 118 * Initialize the console before we print anything out. 119 */ 120 cninit(); 121 } 122 123 /* 124 * cpu_startup: allocate memory for variable-sized tables, 125 * initialize cpu, and do autoconfiguration. 126 */ 127 cpu_startup() 128 { 129 register unsigned i; 130 register caddr_t v, firstaddr; 131 int base, residual; 132 extern long Usrptsize; 133 extern struct map *useriomap; 134 #ifdef DEBUG 135 extern int pmapdebug; 136 int opmapdebug = pmapdebug; 137 #endif 138 vm_offset_t minaddr, maxaddr; 139 vm_size_t size; 140 141 /* 142 * Initialize error message buffer (at end of core). 143 */ 144 #ifdef DEBUG 145 pmapdebug = 0; 146 #endif 147 /* avail_end was pre-decremented in pmap_bootstrap to compensate */ 148 for (i = 0; i < btoc(sizeof (struct msgbuf)); i++) 149 pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG, 150 VM_PROT_ALL, TRUE); 151 msgbufmapped = 1; 152 153 /* 154 * Good {morning,afternoon,evening,night}. 155 */ 156 printf(version); 157 identifycpu(); 158 printf("real mem = %d\n", ctob(physmem)); 159 160 /* 161 * Allocate space for system data structures. 162 * The first available real memory address is in "firstaddr". 163 * The first available kernel virtual address is in "v". 164 * As pages of kernel virtual memory are allocated, "v" is incremented. 165 * As pages of memory are allocated and cleared, 166 * "firstaddr" is incremented. 167 * An index into the kernel page table corresponding to the 168 * virtual memory address maintained in "v" is kept in "mapaddr". 169 */ 170 /* 171 * Make two passes. The first pass calculates how much memory is 172 * needed and allocates it. The second pass assigns virtual 173 * addresses to the various data structures. 174 */ 175 firstaddr = 0; 176 again: 177 v = (caddr_t)firstaddr; 178 179 #define valloc(name, type, num) \ 180 (name) = (type *)v; v = (caddr_t)((name)+(num)) 181 #define valloclim(name, type, num, lim) \ 182 (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) 183 valloc(cfree, struct cblock, nclist); 184 valloc(callout, struct callout, ncallout); 185 valloc(swapmap, struct map, nswapmap = maxproc * 2); 186 #ifdef SYSVSHM 187 valloc(shmsegs, struct shmid_ds, shminfo.shmmni); 188 #endif 189 190 /* 191 * Determine how many buffers to allocate. 192 * Since HPs tend to be long on memory and short on disk speed, 193 * we allocate more buffer space than the BSD standard of 194 * use 10% of memory for the first 2 Meg, 5% of remaining. 195 * We just allocate a flat 10%. Insure a minimum of 16 buffers. 196 * We allocate 1/2 as many swap buffer headers as file i/o buffers. 197 */ 198 if (bufpages == 0) 199 bufpages = physmem / 10 / CLSIZE; 200 if (nbuf == 0) { 201 nbuf = bufpages; 202 if (nbuf < 16) 203 nbuf = 16; 204 } 205 if (nswbuf == 0) { 206 nswbuf = (nbuf / 2) &~ 1; /* force even */ 207 if (nswbuf > 256) 208 nswbuf = 256; /* sanity */ 209 } 210 valloc(swbuf, struct buf, nswbuf); 211 valloc(buf, struct buf, nbuf); 212 /* 213 * End of first pass, size has been calculated so allocate memory 214 */ 215 if (firstaddr == 0) { 216 size = (vm_size_t)(v - firstaddr); 217 firstaddr = (caddr_t) kmem_alloc(kernel_map, round_page(size)); 218 if (firstaddr == 0) 219 panic("startup: no room for tables"); 220 goto again; 221 } 222 /* 223 * End of second pass, addresses have been assigned 224 */ 225 if ((vm_size_t)(v - firstaddr) != size) 226 panic("startup: table size inconsistency"); 227 /* 228 * Now allocate buffers proper. They are different than the above 229 * in that they usually occupy more virtual memory than physical. 230 */ 231 size = MAXBSIZE * nbuf; 232 buffer_map = kmem_suballoc(kernel_map, (vm_offset_t)&buffers, 233 &maxaddr, size, FALSE); 234 minaddr = (vm_offset_t)buffers; 235 if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0, 236 &minaddr, size, FALSE) != KERN_SUCCESS) 237 panic("startup: cannot allocate buffers"); 238 base = bufpages / nbuf; 239 residual = bufpages % nbuf; 240 for (i = 0; i < nbuf; i++) { 241 vm_size_t curbufsize; 242 vm_offset_t curbuf; 243 244 /* 245 * First <residual> buffers get (base+1) physical pages 246 * allocated for them. The rest get (base) physical pages. 247 * 248 * The rest of each buffer occupies virtual space, 249 * but has no physical memory allocated for it. 250 */ 251 curbuf = (vm_offset_t)buffers + i * MAXBSIZE; 252 curbufsize = CLBYTES * (i < residual ? base+1 : base); 253 vm_map_pageable(buffer_map, curbuf, curbuf+curbufsize, FALSE); 254 vm_map_simplify(buffer_map, curbuf); 255 } 256 /* 257 * Allocate a submap for exec arguments. This map effectively 258 * limits the number of processes exec'ing at any time. 259 */ 260 exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, 261 16*NCARGS, TRUE); 262 /* 263 * Allocate a submap for physio 264 */ 265 phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, 266 VM_PHYS_SIZE, TRUE); 267 268 /* 269 * Finally, allocate mbuf pool. Since mclrefcnt is an off-size 270 * we use the more space efficient malloc in place of kmem_alloc. 271 */ 272 mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES, 273 M_MBUF, M_NOWAIT); 274 bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES); 275 mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr, 276 VM_MBUF_SIZE, FALSE); 277 /* 278 * Initialize callouts 279 */ 280 callfree = callout; 281 for (i = 1; i < ncallout; i++) 282 callout[i-1].c_next = &callout[i]; 283 284 #ifdef DEBUG 285 pmapdebug = opmapdebug; 286 #endif 287 printf("avail mem = %d\n", ptoa(vm_page_free_count)); 288 printf("using %d buffers containing %d bytes of memory\n", 289 nbuf, bufpages * CLBYTES); 290 /* 291 * Set up CPU-specific registers, cache, etc. 292 */ 293 initcpu(); 294 295 /* 296 * Set up buffers, so they can be used to read disk labels. 297 */ 298 bufinit(); 299 300 /* 301 * Configure the system. 302 */ 303 configure(); 304 } 305 306 /* 307 * Set registers on exec. 308 * XXX Should clear registers except sp, pc, 309 * but would break init; should be fixed soon. 310 */ 311 setregs(p, entry, retval) 312 register struct proc *p; 313 u_long entry; 314 int retval[2]; 315 { 316 p->p_regs[PC] = entry & ~1; 317 #ifdef FPCOPROC 318 /* restore a null state frame */ 319 p->p_addr->u_pcb.pcb_fpregs.fpf_null = 0; 320 m68881_restore(&p->p_addr->u_pcb.pcb_fpregs); 321 #endif 322 #ifdef HPUXCOMPAT 323 if (p->p_flag & SHPUX) { 324 325 p->p_regs[A0] = 0; /* not 68010 (bit 31), no FPA (30) */ 326 retval[0] = 0; /* no float card */ 327 #ifdef FPCOPROC 328 retval[1] = 1; /* yes 68881 */ 329 #else 330 retval[1] = 0; /* no 68881 */ 331 #endif 332 } 333 /* 334 * Ensure we perform the right action on traps type 1 and 2: 335 * If our parent is an HPUX process and we are being traced, turn 336 * on HPUX style interpretation. Else if we were using the HPUX 337 * style interpretation, revert to the BSD interpretation. 338 * 339 * XXX This doesn't have much to do with setting registers but 340 * I didn't want to muck up kern_exec.c with this code, so I 341 * stuck it here. 342 */ 343 if ((p->p_pptr->p_flag & SHPUX) && 344 (p->p_flag & STRC)) { 345 tweaksigcode(1); 346 p->p_addr->u_pcb.pcb_flags |= PCB_HPUXTRACE; 347 } else if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE) { 348 tweaksigcode(0); 349 p->p_addr->u_pcb.pcb_flags &= ~PCB_HPUXTRACE; 350 } 351 #endif 352 } 353 354 identifycpu() 355 { 356 357 printf("HP9000/"); 358 switch (machineid) { 359 case HP_320: 360 printf("320 (16.67Mhz"); 361 break; 362 case HP_330: 363 printf("318/319/330 (16.67Mhz"); 364 break; 365 case HP_340: 366 printf("340 (16.67Mhz"); 367 break; 368 case HP_350: 369 printf("350 (25Mhz"); 370 break; 371 case HP_360: 372 printf("360 (25Mhz"); 373 break; 374 case HP_370: 375 printf("370 (33.33Mhz"); 376 break; 377 case HP_375: 378 printf("345/375 (50Mhz"); 379 break; 380 default: 381 printf("\nunknown machine type %d\n", machineid); 382 panic("startup"); 383 } 384 printf(" MC680%s CPU", mmutype == MMU_68030 ? "30" : "20"); 385 switch (mmutype) { 386 case MMU_68030: 387 printf("+MMU"); 388 break; 389 case MMU_68851: 390 printf(", MC68851 MMU"); 391 break; 392 case MMU_HP: 393 printf(", HP MMU"); 394 break; 395 default: 396 printf("\nunknown MMU type %d\n", mmutype); 397 panic("startup"); 398 } 399 if (mmutype == MMU_68030) 400 printf(", %sMhz MC68882 FPU", 401 machineid == HP_340 ? "16.67" : 402 (machineid == HP_360 ? "25" : 403 (machineid == HP_370 ? "33.33" : "50"))); 404 else 405 printf(", %sMhz MC68881 FPU", 406 machineid == HP_350 ? "20" : "16.67"); 407 switch (ectype) { 408 case EC_VIRT: 409 printf(", %dK virtual-address cache", 410 machineid == HP_320 ? 16 : 32); 411 break; 412 case EC_PHYS: 413 printf(", %dK physical-address cache", 414 machineid == HP_370 ? 64 : 32); 415 break; 416 } 417 printf(")\n"); 418 /* 419 * Now that we have told the user what they have, 420 * let them know if that machine type isn't configured. 421 */ 422 switch (machineid) { 423 case -1: /* keep compilers happy */ 424 #if !defined(HP320) && !defined(HP350) 425 case HP_320: 426 case HP_350: 427 #endif 428 #ifndef HP330 429 case HP_330: 430 #endif 431 #if !defined(HP360) && !defined(HP370) 432 case HP_340: 433 case HP_360: 434 case HP_370: 435 #endif 436 panic("CPU type not configured"); 437 default: 438 break; 439 } 440 } 441 442 #ifdef HPUXCOMPAT 443 tweaksigcode(ishpux) 444 { 445 static short *sigtrap = NULL; 446 extern short sigcode[], esigcode[]; 447 448 /* locate trap instruction in pcb_sigc */ 449 if (sigtrap == NULL) { 450 sigtrap = esigcode; 451 while (--sigtrap >= sigcode) 452 if ((*sigtrap & 0xFFF0) == 0x4E40) 453 break; 454 if (sigtrap < sigcode) 455 panic("bogus sigcode\n"); 456 } 457 *sigtrap = ishpux ? 0x4E42 : 0x4E41; 458 } 459 #endif 460 461 #define SS_RTEFRAME 1 462 #define SS_FPSTATE 2 463 #define SS_USERREGS 4 464 465 struct sigstate { 466 int ss_flags; /* which of the following are valid */ 467 struct frame ss_frame; /* original exception frame */ 468 struct fpframe ss_fpstate; /* 68881/68882 state info */ 469 }; 470 471 /* 472 * WARNING: code in locore.s assumes the layout shown for sf_signum 473 * thru sf_handler so... don't screw with them! 474 */ 475 struct sigframe { 476 int sf_signum; /* signo for handler */ 477 int sf_code; /* additional info for handler */ 478 struct sigcontext *sf_scp; /* context ptr for handler */ 479 sig_t sf_handler; /* handler addr for u_sigc */ 480 struct sigstate sf_state; /* state of the hardware */ 481 struct sigcontext sf_sc; /* actual context */ 482 }; 483 484 #ifdef HPUXCOMPAT 485 struct hpuxsigcontext { 486 int hsc_syscall; 487 char hsc_action; 488 char hsc_pad1; 489 char hsc_pad2; 490 char hsc_onstack; 491 int hsc_mask; 492 int hsc_sp; 493 short hsc_ps; 494 int hsc_pc; 495 /* the rest aren't part of the context but are included for our convenience */ 496 short hsc_pad; 497 u_int hsc_magic; /* XXX sigreturn: cookie */ 498 struct sigcontext *hsc_realsc; /* XXX sigreturn: ptr to BSD context */ 499 }; 500 501 /* 502 * For an HP-UX process, a partial hpuxsigframe follows the normal sigframe. 503 * Tremendous waste of space, but some HP-UX applications (e.g. LCL) need it. 504 */ 505 struct hpuxsigframe { 506 int hsf_signum; 507 int hsf_code; 508 struct sigcontext *hsf_scp; 509 struct hpuxsigcontext hsf_sc; 510 int hsf_regs[15]; 511 }; 512 #endif 513 514 #ifdef DEBUG 515 int sigdebug = 0; 516 int sigpid = 0; 517 #define SDB_FOLLOW 0x01 518 #define SDB_KSTACK 0x02 519 #define SDB_FPSTATE 0x04 520 #endif 521 522 /* 523 * Send an interrupt to process. 524 */ 525 void 526 sendsig(catcher, sig, mask, code) 527 sig_t catcher; 528 int sig, mask; 529 unsigned code; 530 { 531 register struct proc *p = curproc; 532 register struct sigframe *fp, *kfp; 533 register struct frame *frame; 534 register struct sigacts *ps = p->p_sigacts; 535 register short ft; 536 int oonstack, fsize; 537 extern short exframesize[]; 538 extern char sigcode[], esigcode[]; 539 540 frame = (struct frame *)p->p_regs; 541 ft = frame->f_format; 542 oonstack = ps->ps_onstack; 543 /* 544 * Allocate and validate space for the signal handler 545 * context. Note that if the stack is in P0 space, the 546 * call to grow() is a nop, and the useracc() check 547 * will fail if the process has not already allocated 548 * the space with a `brk'. 549 */ 550 #ifdef HPUXCOMPAT 551 if (p->p_flag & SHPUX) 552 fsize = sizeof(struct sigframe) + sizeof(struct hpuxsigframe); 553 else 554 #endif 555 fsize = sizeof(struct sigframe); 556 if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) { 557 fp = (struct sigframe *)(ps->ps_sigsp - fsize); 558 ps->ps_onstack = 1; 559 } else 560 fp = (struct sigframe *)(frame->f_regs[SP] - fsize); 561 if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) 562 (void)grow(p, (unsigned)fp); 563 #ifdef DEBUG 564 if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 565 printf("sendsig(%d): sig %d ssp %x usp %x scp %x ft %d\n", 566 p->p_pid, sig, &oonstack, fp, &fp->sf_sc, ft); 567 #endif 568 if (useracc((caddr_t)fp, fsize, B_WRITE) == 0) { 569 #ifdef DEBUG 570 if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 571 printf("sendsig(%d): useracc failed on sig %d\n", 572 p->p_pid, sig); 573 #endif 574 /* 575 * Process has trashed its stack; give it an illegal 576 * instruction to halt it in its tracks. 577 */ 578 SIGACTION(p, SIGILL) = SIG_DFL; 579 sig = sigmask(SIGILL); 580 p->p_sigignore &= ~sig; 581 p->p_sigcatch &= ~sig; 582 p->p_sigmask &= ~sig; 583 psignal(p, SIGILL); 584 return; 585 } 586 kfp = (struct sigframe *)malloc((u_long)fsize, M_TEMP, M_WAITOK); 587 /* 588 * Build the argument list for the signal handler. 589 */ 590 kfp->sf_signum = sig; 591 kfp->sf_code = code; 592 kfp->sf_scp = &fp->sf_sc; 593 kfp->sf_handler = catcher; 594 /* 595 * Save necessary hardware state. Currently this includes: 596 * - general registers 597 * - original exception frame (if not a "normal" frame) 598 * - FP coprocessor state 599 */ 600 kfp->sf_state.ss_flags = SS_USERREGS; 601 bcopy((caddr_t)frame->f_regs, 602 (caddr_t)kfp->sf_state.ss_frame.f_regs, sizeof frame->f_regs); 603 if (ft >= FMT9) { 604 #ifdef DEBUG 605 if (ft != FMT9 && ft != FMTA && ft != FMTB) 606 panic("sendsig: bogus frame type"); 607 #endif 608 kfp->sf_state.ss_flags |= SS_RTEFRAME; 609 kfp->sf_state.ss_frame.f_format = frame->f_format; 610 kfp->sf_state.ss_frame.f_vector = frame->f_vector; 611 bcopy((caddr_t)&frame->F_u, 612 (caddr_t)&kfp->sf_state.ss_frame.F_u, exframesize[ft]); 613 /* 614 * Leave an indicator that we need to clean up the kernel 615 * stack. We do this by setting the "pad word" above the 616 * hardware stack frame to the amount the stack must be 617 * adjusted by. 618 * 619 * N.B. we increment rather than just set f_stackadj in 620 * case we are called from syscall when processing a 621 * sigreturn. In that case, f_stackadj may be non-zero. 622 */ 623 frame->f_stackadj += exframesize[ft]; 624 frame->f_format = frame->f_vector = 0; 625 #ifdef DEBUG 626 if (sigdebug & SDB_FOLLOW) 627 printf("sendsig(%d): copy out %d of frame %d\n", 628 p->p_pid, exframesize[ft], ft); 629 #endif 630 } 631 #ifdef FPCOPROC 632 kfp->sf_state.ss_flags |= SS_FPSTATE; 633 m68881_save(&kfp->sf_state.ss_fpstate); 634 #ifdef DEBUG 635 if ((sigdebug & SDB_FPSTATE) && *(char *)&kfp->sf_state.ss_fpstate) 636 printf("sendsig(%d): copy out FP state (%x) to %x\n", 637 p->p_pid, *(u_int *)&kfp->sf_state.ss_fpstate, 638 &kfp->sf_state.ss_fpstate); 639 #endif 640 #endif 641 /* 642 * Build the signal context to be used by sigreturn. 643 */ 644 kfp->sf_sc.sc_onstack = oonstack; 645 kfp->sf_sc.sc_mask = mask; 646 kfp->sf_sc.sc_sp = frame->f_regs[SP]; 647 kfp->sf_sc.sc_fp = frame->f_regs[A6]; 648 kfp->sf_sc.sc_ap = (int)&fp->sf_state; 649 kfp->sf_sc.sc_pc = frame->f_pc; 650 kfp->sf_sc.sc_ps = frame->f_sr; 651 #ifdef HPUXCOMPAT 652 /* 653 * Create an HP-UX style sigcontext structure and associated goo 654 */ 655 if (p->p_flag & SHPUX) { 656 register struct hpuxsigframe *hkfp; 657 658 hkfp = (struct hpuxsigframe *)&kfp[1]; 659 hkfp->hsf_signum = bsdtohpuxsig(kfp->sf_signum); 660 hkfp->hsf_code = kfp->sf_code; 661 hkfp->hsf_scp = (struct sigcontext *) 662 &((struct hpuxsigframe *)(&fp[1]))->hsf_sc; 663 hkfp->hsf_sc.hsc_syscall = 0; /* XXX */ 664 hkfp->hsf_sc.hsc_action = 0; /* XXX */ 665 hkfp->hsf_sc.hsc_pad1 = hkfp->hsf_sc.hsc_pad2 = 0; 666 hkfp->hsf_sc.hsc_onstack = kfp->sf_sc.sc_onstack; 667 hkfp->hsf_sc.hsc_mask = kfp->sf_sc.sc_mask; 668 hkfp->hsf_sc.hsc_sp = kfp->sf_sc.sc_sp; 669 hkfp->hsf_sc.hsc_ps = kfp->sf_sc.sc_ps; 670 hkfp->hsf_sc.hsc_pc = kfp->sf_sc.sc_pc; 671 hkfp->hsf_sc.hsc_pad = 0; 672 hkfp->hsf_sc.hsc_magic = 0xdeadbeef; 673 hkfp->hsf_sc.hsc_realsc = kfp->sf_scp; 674 bcopy((caddr_t)frame->f_regs, (caddr_t)hkfp->hsf_regs, 675 sizeof (hkfp->hsf_regs)); 676 677 kfp->sf_signum = hkfp->hsf_signum; 678 kfp->sf_scp = hkfp->hsf_scp; 679 } 680 #endif 681 (void) copyout((caddr_t)kfp, (caddr_t)fp, fsize); 682 frame->f_regs[SP] = (int)fp; 683 #ifdef DEBUG 684 if (sigdebug & SDB_FOLLOW) 685 printf("sendsig(%d): sig %d scp %x fp %x sc_sp %x sc_ap %x\n", 686 p->p_pid, sig, kfp->sf_scp, fp, 687 kfp->sf_sc.sc_sp, kfp->sf_sc.sc_ap); 688 #endif 689 /* 690 * Signal trampoline code is at base of user stack. 691 */ 692 frame->f_pc = USRSTACK - (esigcode - sigcode); 693 #ifdef DEBUG 694 if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 695 printf("sendsig(%d): sig %d returns\n", 696 p->p_pid, sig); 697 #endif 698 free((caddr_t)kfp, M_TEMP); 699 } 700 701 /* 702 * System call to cleanup state after a signal 703 * has been taken. Reset signal mask and 704 * stack state from context left by sendsig (above). 705 * Return to previous pc and psl as specified by 706 * context left by sendsig. Check carefully to 707 * make sure that the user has not modified the 708 * psl to gain improper priviledges or to cause 709 * a machine fault. 710 */ 711 /* ARGSUSED */ 712 sigreturn(p, uap, retval) 713 struct proc *p; 714 struct args { 715 struct sigcontext *sigcntxp; 716 } *uap; 717 int *retval; 718 { 719 register struct sigcontext *scp; 720 register struct frame *frame; 721 register int rf; 722 struct sigcontext tsigc; 723 struct sigstate tstate; 724 int flags; 725 extern short exframesize[]; 726 727 scp = uap->sigcntxp; 728 #ifdef DEBUG 729 if (sigdebug & SDB_FOLLOW) 730 printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp); 731 #endif 732 if ((int)scp & 1) 733 return (EINVAL); 734 #ifdef HPUXCOMPAT 735 /* 736 * Grab context as an HP-UX style context and determine if it 737 * was one that we contructed in sendsig. 738 */ 739 if (p->p_flag & SHPUX) { 740 struct hpuxsigcontext *hscp = (struct hpuxsigcontext *)scp; 741 struct hpuxsigcontext htsigc; 742 743 if (useracc((caddr_t)hscp, sizeof (*hscp), B_WRITE) == 0 || 744 copyin((caddr_t)hscp, (caddr_t)&htsigc, sizeof htsigc)) 745 return (EINVAL); 746 /* 747 * If not generated by sendsig or we cannot restore the 748 * BSD-style sigcontext, just restore what we can -- state 749 * will be lost, but them's the breaks. 750 */ 751 hscp = &htsigc; 752 if (hscp->hsc_magic != 0xdeadbeef || 753 (scp = hscp->hsc_realsc) == 0 || 754 useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || 755 copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) { 756 p->p_sigacts->ps_onstack = hscp->hsc_onstack & 01; 757 p->p_sigmask = hscp->hsc_mask &~ sigcantmask; 758 frame = (struct frame *) p->p_regs; 759 frame->f_regs[SP] = hscp->hsc_sp; 760 frame->f_pc = hscp->hsc_pc; 761 frame->f_sr = hscp->hsc_ps &~ PSL_USERCLR; 762 return (EJUSTRETURN); 763 } 764 /* 765 * Otherwise, overlay BSD context with possibly modified 766 * HP-UX values. 767 */ 768 tsigc.sc_onstack = hscp->hsc_onstack; 769 tsigc.sc_mask = hscp->hsc_mask; 770 tsigc.sc_sp = hscp->hsc_sp; 771 tsigc.sc_ps = hscp->hsc_ps; 772 tsigc.sc_pc = hscp->hsc_pc; 773 } else 774 #endif 775 /* 776 * Test and fetch the context structure. 777 * We grab it all at once for speed. 778 */ 779 if (useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || 780 copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) 781 return (EINVAL); 782 scp = &tsigc; 783 if ((scp->sc_ps & (PSL_MBZ|PSL_IPL|PSL_S)) != 0) 784 return (EINVAL); 785 /* 786 * Restore the user supplied information 787 */ 788 p->p_sigacts->ps_onstack = scp->sc_onstack & 01; 789 p->p_sigmask = scp->sc_mask &~ sigcantmask; 790 frame = (struct frame *) p->p_regs; 791 frame->f_regs[SP] = scp->sc_sp; 792 frame->f_regs[A6] = scp->sc_fp; 793 frame->f_pc = scp->sc_pc; 794 frame->f_sr = scp->sc_ps; 795 /* 796 * Grab pointer to hardware state information. 797 * If zero, the user is probably doing a longjmp. 798 */ 799 if ((rf = scp->sc_ap) == 0) 800 return (EJUSTRETURN); 801 /* 802 * See if there is anything to do before we go to the 803 * expense of copying in close to 1/2K of data 804 */ 805 flags = fuword((caddr_t)rf); 806 #ifdef DEBUG 807 if (sigdebug & SDB_FOLLOW) 808 printf("sigreturn(%d): sc_ap %x flags %x\n", 809 p->p_pid, rf, flags); 810 #endif 811 /* 812 * fuword failed (bogus sc_ap value). 813 */ 814 if (flags == -1) 815 return (EINVAL); 816 if (flags == 0 || copyin((caddr_t)rf, (caddr_t)&tstate, sizeof tstate)) 817 return (EJUSTRETURN); 818 #ifdef DEBUG 819 if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 820 printf("sigreturn(%d): ssp %x usp %x scp %x ft %d\n", 821 p->p_pid, &flags, scp->sc_sp, uap->sigcntxp, 822 (flags&SS_RTEFRAME) ? tstate.ss_frame.f_format : -1); 823 #endif 824 /* 825 * Restore most of the users registers except for A6 and SP 826 * which were handled above. 827 */ 828 if (flags & SS_USERREGS) 829 bcopy((caddr_t)tstate.ss_frame.f_regs, 830 (caddr_t)frame->f_regs, sizeof(frame->f_regs)-2*NBPW); 831 /* 832 * Restore long stack frames. Note that we do not copy 833 * back the saved SR or PC, they were picked up above from 834 * the sigcontext structure. 835 */ 836 if (flags & SS_RTEFRAME) { 837 register int sz; 838 839 /* grab frame type and validate */ 840 sz = tstate.ss_frame.f_format; 841 if (sz > 15 || (sz = exframesize[sz]) < 0) 842 return (EINVAL); 843 frame->f_stackadj -= sz; 844 frame->f_format = tstate.ss_frame.f_format; 845 frame->f_vector = tstate.ss_frame.f_vector; 846 bcopy((caddr_t)&tstate.ss_frame.F_u, (caddr_t)&frame->F_u, sz); 847 #ifdef DEBUG 848 if (sigdebug & SDB_FOLLOW) 849 printf("sigreturn(%d): copy in %d of frame type %d\n", 850 p->p_pid, sz, tstate.ss_frame.f_format); 851 #endif 852 } 853 #ifdef FPCOPROC 854 /* 855 * Finally we restore the original FP context 856 */ 857 if (flags & SS_FPSTATE) 858 m68881_restore(&tstate.ss_fpstate); 859 #ifdef DEBUG 860 if ((sigdebug & SDB_FPSTATE) && *(char *)&tstate.ss_fpstate) 861 printf("sigreturn(%d): copied in FP state (%x) at %x\n", 862 p->p_pid, *(u_int *)&tstate.ss_fpstate, 863 &tstate.ss_fpstate); 864 #endif 865 #endif 866 #ifdef DEBUG 867 if ((sigdebug & SDB_FOLLOW) || 868 ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)) 869 printf("sigreturn(%d): returns\n", p->p_pid); 870 #endif 871 return (EJUSTRETURN); 872 } 873 874 int waittime = -1; 875 876 boot(howto) 877 register int howto; 878 { 879 /* take a snap shot before clobbering any registers */ 880 if (curproc) 881 savectx(curproc->p_addr, 0); 882 883 boothowto = howto; 884 if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) { 885 register struct buf *bp; 886 int iter, nbusy; 887 888 waittime = 0; 889 (void) spl0(); 890 printf("syncing disks... "); 891 /* 892 * Release vnodes held by texts before sync. 893 */ 894 if (panicstr == 0) 895 vnode_pager_umount(NULL); 896 #ifdef notdef 897 #include "fd.h" 898 #if NFD > 0 899 fdshutdown(); 900 #endif 901 #endif 902 sync(&proc0, (void *)NULL, (int *)NULL); 903 904 for (iter = 0; iter < 20; iter++) { 905 nbusy = 0; 906 for (bp = &buf[nbuf]; --bp >= buf; ) 907 if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY) 908 nbusy++; 909 if (nbusy == 0) 910 break; 911 printf("%d ", nbusy); 912 DELAY(40000 * iter); 913 } 914 if (nbusy) 915 printf("giving up\n"); 916 else 917 printf("done\n"); 918 /* 919 * If we've been adjusting the clock, the todr 920 * will be out of synch; adjust it now. 921 */ 922 resettodr(); 923 } 924 splhigh(); /* extreme priority */ 925 if (howto&RB_HALT) { 926 printf("halted\n\n"); 927 asm(" stop #0x2700"); 928 } else { 929 if (howto & RB_DUMP) 930 dumpsys(); 931 doboot(); 932 /*NOTREACHED*/ 933 } 934 /*NOTREACHED*/ 935 } 936 937 int dumpmag = 0x8fca0101; /* magic number for savecore */ 938 int dumpsize = 0; /* also for savecore */ 939 long dumplo = 0; 940 941 dumpconf() 942 { 943 int nblks; 944 945 dumpsize = physmem; 946 if (dumpdev != NODEV && bdevsw[major(dumpdev)].d_psize) { 947 nblks = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); 948 if (dumpsize > btoc(dbtob(nblks - dumplo))) 949 dumpsize = btoc(dbtob(nblks - dumplo)); 950 else if (dumplo == 0) 951 dumplo = nblks - btodb(ctob(physmem)); 952 } 953 /* 954 * Don't dump on the first CLBYTES (why CLBYTES?) 955 * in case the dump device includes a disk label. 956 */ 957 if (dumplo < btodb(CLBYTES)) 958 dumplo = btodb(CLBYTES); 959 } 960 961 /* 962 * Doadump comes here after turning off memory management and 963 * getting on the dump stack, either when called above, or by 964 * the auto-restart code. 965 */ 966 dumpsys() 967 { 968 969 msgbufmapped = 0; 970 if (dumpdev == NODEV) 971 return; 972 /* 973 * For dumps during autoconfiguration, 974 * if dump device has already configured... 975 */ 976 if (dumpsize == 0) 977 dumpconf(); 978 if (dumplo < 0) 979 return; 980 printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo); 981 printf("dump "); 982 switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) { 983 984 case ENXIO: 985 printf("device bad\n"); 986 break; 987 988 case EFAULT: 989 printf("device not ready\n"); 990 break; 991 992 case EINVAL: 993 printf("area improper\n"); 994 break; 995 996 case EIO: 997 printf("i/o error\n"); 998 break; 999 1000 default: 1001 printf("succeeded\n"); 1002 break; 1003 } 1004 } 1005 1006 /* 1007 * Return the best possible estimate of the time in the timeval 1008 * to which tvp points. We do this by returning the current time 1009 * plus the amount of time since the last clock interrupt (clock.c:clkread). 1010 * 1011 * Check that this time is no less than any previously-reported time, 1012 * which could happen around the time of a clock adjustment. Just for fun, 1013 * we guarantee that the time will be greater than the value obtained by a 1014 * previous call. 1015 */ 1016 microtime(tvp) 1017 register struct timeval *tvp; 1018 { 1019 int s = splhigh(); 1020 static struct timeval lasttime; 1021 1022 *tvp = time; 1023 tvp->tv_usec += clkread(); 1024 while (tvp->tv_usec > 1000000) { 1025 tvp->tv_sec++; 1026 tvp->tv_usec -= 1000000; 1027 } 1028 if (tvp->tv_sec == lasttime.tv_sec && 1029 tvp->tv_usec <= lasttime.tv_usec && 1030 (tvp->tv_usec = lasttime.tv_usec + 1) > 1000000) { 1031 tvp->tv_sec++; 1032 tvp->tv_usec -= 1000000; 1033 } 1034 lasttime = *tvp; 1035 splx(s); 1036 } 1037 1038 initcpu() 1039 { 1040 parityenable(); 1041 } 1042 1043 straytrap(pc, evec) 1044 int pc; 1045 u_short evec; 1046 { 1047 printf("unexpected trap (vector offset %x) from %x\n", 1048 evec & 0xFFF, pc); 1049 } 1050 1051 int *nofault; 1052 1053 badaddr(addr) 1054 register caddr_t addr; 1055 { 1056 register int i; 1057 label_t faultbuf; 1058 1059 #ifdef lint 1060 i = *addr; if (i) return(0); 1061 #endif 1062 nofault = (int *) &faultbuf; 1063 if (setjmp((label_t *)nofault)) { 1064 nofault = (int *) 0; 1065 return(1); 1066 } 1067 i = *(volatile short *)addr; 1068 nofault = (int *) 0; 1069 return(0); 1070 } 1071 1072 badbaddr(addr) 1073 register caddr_t addr; 1074 { 1075 register int i; 1076 label_t faultbuf; 1077 1078 #ifdef lint 1079 i = *addr; if (i) return(0); 1080 #endif 1081 nofault = (int *) &faultbuf; 1082 if (setjmp((label_t *)nofault)) { 1083 nofault = (int *) 0; 1084 return(1); 1085 } 1086 i = *(volatile char *)addr; 1087 nofault = (int *) 0; 1088 return(0); 1089 } 1090 1091 netintr() 1092 { 1093 #ifdef INET 1094 if (netisr & (1 << NETISR_ARP)) { 1095 netisr &= ~(1 << NETISR_ARP); 1096 arpintr(); 1097 } 1098 if (netisr & (1 << NETISR_IP)) { 1099 netisr &= ~(1 << NETISR_IP); 1100 ipintr(); 1101 } 1102 #endif 1103 #ifdef NS 1104 if (netisr & (1 << NETISR_NS)) { 1105 netisr &= ~(1 << NETISR_NS); 1106 nsintr(); 1107 } 1108 #endif 1109 #ifdef ISO 1110 if (netisr & (1 << NETISR_ISO)) { 1111 netisr &= ~(1 << NETISR_ISO); 1112 clnlintr(); 1113 } 1114 #endif 1115 } 1116 1117 intrhand(sr) 1118 int sr; 1119 { 1120 register struct isr *isr; 1121 register int found = 0; 1122 register int ipl; 1123 extern struct isr isrqueue[]; 1124 1125 ipl = (sr >> 8) & 7; 1126 switch (ipl) { 1127 1128 case 3: 1129 case 4: 1130 case 5: 1131 ipl = ISRIPL(ipl); 1132 isr = isrqueue[ipl].isr_forw; 1133 for (; isr != &isrqueue[ipl]; isr = isr->isr_forw) { 1134 if ((isr->isr_intr)(isr->isr_arg)) { 1135 found++; 1136 break; 1137 } 1138 } 1139 if (found == 0) 1140 printf("stray interrupt, sr 0x%x\n", sr); 1141 break; 1142 1143 case 0: 1144 case 1: 1145 case 2: 1146 case 6: 1147 case 7: 1148 printf("intrhand: unexpected sr 0x%x\n", sr); 1149 break; 1150 } 1151 } 1152 1153 #if defined(DEBUG) && !defined(PANICBUTTON) 1154 #define PANICBUTTON 1155 #endif 1156 1157 #ifdef PANICBUTTON 1158 int panicbutton = 1; /* non-zero if panic buttons are enabled */ 1159 int crashandburn = 0; 1160 int candbdelay = 50; /* give em half a second */ 1161 1162 candbtimer() 1163 { 1164 crashandburn = 0; 1165 } 1166 #endif 1167 1168 /* 1169 * Level 7 interrupts can be caused by the keyboard or parity errors. 1170 */ 1171 nmihand(frame) 1172 struct frame frame; 1173 { 1174 if (kbdnmi()) { 1175 #ifdef PANICBUTTON 1176 static int innmihand = 0; 1177 1178 /* 1179 * Attempt to reduce the window of vulnerability for recursive 1180 * NMIs (e.g. someone holding down the keyboard reset button). 1181 */ 1182 if (innmihand == 0) { 1183 innmihand = 1; 1184 printf("Got a keyboard NMI\n"); 1185 innmihand = 0; 1186 } 1187 if (panicbutton) { 1188 if (crashandburn) { 1189 crashandburn = 0; 1190 panic(panicstr ? 1191 "forced crash, nosync" : "forced crash"); 1192 } 1193 crashandburn++; 1194 timeout(candbtimer, (caddr_t)0, candbdelay); 1195 } 1196 #endif 1197 return; 1198 } 1199 if (parityerror(&frame)) 1200 return; 1201 /* panic?? */ 1202 printf("unexpected level 7 interrupt ignored\n"); 1203 } 1204 1205 /* 1206 * Parity error section. Contains magic. 1207 */ 1208 #define PARREG ((volatile short *)IIOV(0x5B0000)) 1209 static int gotparmem = 0; 1210 #ifdef DEBUG 1211 int ignorekperr = 0; /* ignore kernel parity errors */ 1212 #endif 1213 1214 /* 1215 * Enable parity detection 1216 */ 1217 parityenable() 1218 { 1219 label_t faultbuf; 1220 1221 nofault = (int *) &faultbuf; 1222 if (setjmp((label_t *)nofault)) { 1223 nofault = (int *) 0; 1224 #ifdef DEBUG 1225 printf("No parity memory\n"); 1226 #endif 1227 return; 1228 } 1229 *PARREG = 1; 1230 nofault = (int *) 0; 1231 gotparmem = 1; 1232 #ifdef DEBUG 1233 printf("Parity detection enabled\n"); 1234 #endif 1235 } 1236 1237 /* 1238 * Determine if level 7 interrupt was caused by a parity error 1239 * and deal with it if it was. Returns 1 if it was a parity error. 1240 */ 1241 parityerror(fp) 1242 struct frame *fp; 1243 { 1244 if (!gotparmem) 1245 return(0); 1246 *PARREG = 0; 1247 DELAY(10); 1248 *PARREG = 1; 1249 if (panicstr) { 1250 printf("parity error after panic ignored\n"); 1251 return(1); 1252 } 1253 if (!findparerror()) 1254 printf("WARNING: transient parity error ignored\n"); 1255 else if (USERMODE(fp->f_sr)) { 1256 printf("pid %d: parity error\n", curproc->p_pid); 1257 uprintf("sorry, pid %d killed due to memory parity error\n", 1258 curproc->p_pid); 1259 psignal(curproc, SIGKILL); 1260 #ifdef DEBUG 1261 } else if (ignorekperr) { 1262 printf("WARNING: kernel parity error ignored\n"); 1263 #endif 1264 } else { 1265 regdump(fp->f_regs, 128); 1266 panic("kernel parity error"); 1267 } 1268 return(1); 1269 } 1270 1271 /* 1272 * Yuk! There has got to be a better way to do this! 1273 * Searching all of memory with interrupts blocked can lead to disaster. 1274 */ 1275 findparerror() 1276 { 1277 static label_t parcatch; 1278 static int looking = 0; 1279 volatile struct pte opte; 1280 volatile int pg, o, s; 1281 register volatile int *ip; 1282 register int i; 1283 int found; 1284 1285 #ifdef lint 1286 ip = &found; 1287 i = o = pg = 0; if (i) return(0); 1288 #endif 1289 /* 1290 * If looking is true we are searching for a known parity error 1291 * and it has just occured. All we do is return to the higher 1292 * level invocation. 1293 */ 1294 if (looking) 1295 longjmp(&parcatch); 1296 s = splhigh(); 1297 /* 1298 * If setjmp returns true, the parity error we were searching 1299 * for has just occured (longjmp above) at the current pg+o 1300 */ 1301 if (setjmp(&parcatch)) { 1302 printf("Parity error at 0x%x\n", ctob(pg)|o); 1303 found = 1; 1304 goto done; 1305 } 1306 /* 1307 * If we get here, a parity error has occured for the first time 1308 * and we need to find it. We turn off any external caches and 1309 * loop thru memory, testing every longword til a fault occurs and 1310 * we regain control at setjmp above. Note that because of the 1311 * setjmp, pg and o need to be volatile or their values will be lost. 1312 */ 1313 looking = 1; 1314 ecacheoff(); 1315 for (pg = btoc(lowram); pg < btoc(lowram)+physmem; pg++) { 1316 pmap_enter(pmap_kernel(), vmmap, ctob(pg), VM_PROT_READ, TRUE); 1317 for (o = 0; o < NBPG; o += sizeof(int)) 1318 i = *(int *)(&vmmap[o]); 1319 } 1320 /* 1321 * Getting here implies no fault was found. Should never happen. 1322 */ 1323 printf("Couldn't locate parity error\n"); 1324 found = 0; 1325 done: 1326 looking = 0; 1327 pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]); 1328 ecacheon(); 1329 splx(s); 1330 return(found); 1331 } 1332 1333 regdump(rp, sbytes) 1334 int *rp; /* must not be register */ 1335 int sbytes; 1336 { 1337 static int doingdump = 0; 1338 register int i; 1339 int s; 1340 extern char *hexstr(); 1341 1342 if (doingdump) 1343 return; 1344 s = splhigh(); 1345 doingdump = 1; 1346 printf("pid = %d, pc = %s, ", curproc->p_pid, hexstr(rp[PC], 8)); 1347 printf("ps = %s, ", hexstr(rp[PS], 4)); 1348 printf("sfc = %s, ", hexstr(getsfc(), 4)); 1349 printf("dfc = %s\n", hexstr(getdfc(), 4)); 1350 printf("Registers:\n "); 1351 for (i = 0; i < 8; i++) 1352 printf(" %d", i); 1353 printf("\ndreg:"); 1354 for (i = 0; i < 8; i++) 1355 printf(" %s", hexstr(rp[i], 8)); 1356 printf("\nareg:"); 1357 for (i = 0; i < 8; i++) 1358 printf(" %s", hexstr(rp[i+8], 8)); 1359 if (sbytes > 0) { 1360 if (rp[PS] & PSL_S) { 1361 printf("\n\nKernel stack (%s):", 1362 hexstr((int)(((int *)&rp)-1), 8)); 1363 dumpmem(((int *)&rp)-1, sbytes, 0); 1364 } else { 1365 printf("\n\nUser stack (%s):", hexstr(rp[SP], 8)); 1366 dumpmem((int *)rp[SP], sbytes, 1); 1367 } 1368 } 1369 doingdump = 0; 1370 splx(s); 1371 } 1372 1373 extern char kstack[]; 1374 #define KSADDR ((int *)&(kstack[(UPAGES-1)*NBPG])) 1375 1376 dumpmem(ptr, sz, ustack) 1377 register int *ptr; 1378 int sz; 1379 { 1380 register int i, val; 1381 extern char *hexstr(); 1382 1383 for (i = 0; i < sz; i++) { 1384 if ((i & 7) == 0) 1385 printf("\n%s: ", hexstr((int)ptr, 6)); 1386 else 1387 printf(" "); 1388 if (ustack == 1) { 1389 if ((val = fuword(ptr++)) == -1) 1390 break; 1391 } else { 1392 if (ustack == 0 && 1393 (ptr < KSADDR || ptr > KSADDR+(NBPG/4-1))) 1394 break; 1395 val = *ptr++; 1396 } 1397 printf("%s", hexstr(val, 8)); 1398 } 1399 printf("\n"); 1400 } 1401 1402 char * 1403 hexstr(val, len) 1404 register int val; 1405 { 1406 static char nbuf[9]; 1407 register int x, i; 1408 1409 if (len > 8) 1410 return(""); 1411 nbuf[len] = '\0'; 1412 for (i = len-1; i >= 0; --i) { 1413 x = val & 0xF; 1414 if (x > 9) 1415 nbuf[i] = x - 10 + 'A'; 1416 else 1417 nbuf[i] = x + '0'; 1418 val >>= 4; 1419 } 1420 return(nbuf); 1421 } 1422