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