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