changes for shared libs, new vm code, and debugging stuff for the

machdep.c routine that runs unmapped at the start of boot.  (The debugging
stuff should go away, but this is the 2nd time I had to write umprintf.c, so
I want it saved.)
This commit is contained in:
phil 1994-04-19 17:14:13 +00:00
parent b7685a8087
commit da19ea4f05
8 changed files with 198 additions and 62 deletions

View File

@ -1 +1 @@
revision 1.4 intentionally removed
revision 1.5 intentionally removed

View File

@ -35,7 +35,7 @@
*
* @(#)genassym.c 5.11 (Berkeley) 5/10/91
*
* $Id: genassym.c,v 1.2 1994/04/05 17:37:41 phil Exp $
* $Id: genassym.c,v 1.3 1994/04/19 17:14:14 phil Exp $
*/
#include "sys/param.h"
@ -92,6 +92,7 @@ main()
printf("#define\tKSTK_SIZE %d\n", UPAGES*NBPG);
printf("#define\tON_STK_SIZE %d\n", sizeof(struct on_stack));
printf("#define\tREGS_USP %d\n", &regs->pcb_usp);
printf("#define\tREGS_SB %d\n", &regs->pcb_sb);
printf("#define\tREGS_PSR %d\n", &regs->pcb_psr);
printf("#define\tPCB_ONSTACK %d\n", &pcb->pcb_onstack);

View File

@ -31,7 +31,7 @@
*
* icode.c
*
* $Id: icode.c,v 1.1.1.1 1993/09/09 23:53:48 phil Exp $
* $Id: icode.c,v 1.2 1994/04/19 17:14:16 phil Exp $
*/
/*
* This is the "user" code for process 1 that execs /sbin/init.
@ -65,7 +65,7 @@ void i_code()
/* Exec /sbin/init! */
void i_main()
{
extern char i_arg1;
extern char i_arg1();
char *argv[] = {"init", 0, 0};
#ifdef DEBUG
@ -80,7 +80,7 @@ void i_main()
printf ("ready to exec /sbin/init\n");
#endif
argv[1] = &i_arg1;
argv[1] = (char *)&i_arg1;
execve ("/sbin/init", argv, 0);
@ -101,7 +101,7 @@ asm(" ret 0");
asm("_myerrno: .long 0");
/* Call it a function to get space and a good address in the text segment. */
i_arg1()
char i_arg1()
{}
int szicode = 0;

View File

@ -306,7 +306,7 @@ ENTRY(bpt_to_monitor)
sprd sp, r1 /* save kernel's sp */
sprd fp, r2 /* save kernel's fp */
sprd intbase, r3 /* Save current intbase. */
smr ptb0, r4 /* Save current ptd! */
smr ptb0, r4 /* Save current ptd! */
/* Change to low addresses */
lmr ptb0, _IdlePTD(pc) /* Load the idle ptd */
@ -770,42 +770,47 @@ m_ll_fork: .asciz "_low_level_fork: kstack not double alligned."
/* Interrupt and trap processing. */
ENTRY(_trap_nvi)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 0, tos
br all_trap
ENTRY(_trap_nmi)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 1, tos
br all_trap
ENTRY(_trap_abt)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 2, tos
smr tear, tos
smr msr, tos
br abt_trap
ENTRY(_trap_slave)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 3, tos
br all_trap
ENTRY(_trap_ill)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 4, tos
br all_trap
ENTRY(_trap_svc)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
/* Save the usp in the pcb. */
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
/* Have an fpu? */
cmpqd 0, __have_fpu(pc)
@ -838,8 +843,9 @@ ENTRY(_trap_svc)
movl PCB_F6(r3),f6
movl PCB_F7(r3),f7
/* Restore the usp. */
/* Restore the usp and sb. */
lprd usp, REGS_USP(sp)
lprd sb, REGS_SB(sp)
exit [r0,r1,r2,r3,r4,r5,r6,r7]
rett 0
@ -848,75 +854,87 @@ svc_no_fpu:
/* Call the system. */
bsr _syscall
/* Restore the usp. */
/* Restore the usp and sb. */
lprd usp, REGS_USP(sp)
lprd sb, REGS_SB(sp)
exit [r0,r1,r2,r3,r4,r5,r6,r7]
rett 0
ENTRY(_trap_dvz)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 6, tos
br all_trap
ENTRY(_trap_flg)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movqd 7, tos
br all_trap
ENTRY(_trap_bpt)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 8, tos
br all_trap
ENTRY(_trap_trc)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 9, tos
br all_trap
ENTRY(_trap_und)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 10, tos
br all_trap
ENTRY(_trap_rbe)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 11, tos
br all_trap
ENTRY(_trap_nbe)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 12, tos
br all_trap
ENTRY(_trap_ovf)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 13, tos
br all_trap
ENTRY(_trap_dbg)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 14, tos
br all_trap
ENTRY(_trap_reserved)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd 15, tos
all_trap:
movqd 0,tos /* Add 2 zeros for msr,tear in frame. */
movqd 0,tos
abt_trap:
lprd sb, 0 /* for the kernel */
/* Was this a real process? */
cmpqd 0, _curproc(pc)
@ -952,8 +970,9 @@ abt_trap:
movl PCB_F6(r3),f6
movl PCB_F7(r3),f7
/* Reload the usp just in case anything has changed. */
/* Reload the usp and sb just in case anything has changed. */
lprd usp, REGS_USP(sp)
lprd sb, REGS_SB(sp)
exit [r0,r1,r2,r3,r4,r5,r6,r7]
rett 0
@ -962,8 +981,9 @@ trap_no_fpu:
bsr _trap
adjspb -12 /* Pop off software part of trap frame. */
/* Reload the usp just in case anything has changed. */
/* Reload the usp and sb just in case anything has changed. */
lprd usp, REGS_USP(sp)
lprd sb, REGS_SB(sp)
exit [r0,r1,r2,r3,r4,r5,r6,r7]
rett 0
@ -971,8 +991,10 @@ trap_no_fpu:
/* Interrupt service routines.... */
ENTRY(_int_clk)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
movqd 0,tos
addr 0(sp),tos /* The address of the frame. */
@ -981,8 +1003,10 @@ ENTRY(_int_clk)
br exit_int
ENTRY(_int_scsi0)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
#if NAIC > 0
movqd 0,tos
@ -994,8 +1018,9 @@ ENTRY(_int_scsi0)
br exit_int
ENTRY(_int_scsi1)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
movd Cur_pl(pc), tos
#if NDP > 0
movqd 1,tos
@ -1012,36 +1037,46 @@ ENTRY(_int_scsi1)
br exit_int
ENTRY(_int_uart0)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
movqd 0,tos
bsr _scnintr
br exit_int
ENTRY(_int_uart1)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
movqd 1,tos
bsr _scnintr
br exit_int
ENTRY(_int_uart2)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
movqd 2,tos
bsr _scnintr
br exit_int
ENTRY(_int_uart3)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
movqd 3,tos
bsr _scnintr
br exit_int
ENTRY(_int_bad)
enter [r0,r1,r2,r3,r4,r5,r6,r7],4
enter [r0,r1,r2,r3,r4,r5,r6,r7],8
sprd usp, REGS_USP(sp)
sprd sb, REGS_SB(sp)
lprd sb, 0 /* for the kernel */
movd Cur_pl(pc), tos
movqd 0,tos
bsr _bad_intr
@ -1054,6 +1089,7 @@ exit_int:
bfs do_user_intr /* branch if yes! */
lprd usp, REGS_USP(sp)
lprd sb, REGS_SB(sp)
exit [r0,r1,r2,r3,r4,r5,r6,r7]
reti
@ -1162,6 +1198,7 @@ do_usr_ret:
intr_ret_no_fpu:
lprd usp, REGS_USP(sp)
lprd sb, REGS_SB(sp)
exit [r0,r1,r2,r3,r4,r5,r6,r7]
rett 0

View File

@ -73,6 +73,7 @@ vm_map_t buffer_map;
#include "machine/psl.h"
#include "machine/reg.h"
#include "machine/cpu.h"
#include "machine/pmap.h"
#include "icu.h"
extern vm_offset_t avail_end;
@ -117,6 +118,13 @@ int IdlePTD;
int start_page;
int _istack;
#if 0
#include <pc532/umprintf.c>
#else
umprintf (char *fmt,...)
{} /* Dummy procedure. */
#endif
void
_low_level_init ()
{
@ -124,33 +132,39 @@ _low_level_init ()
int p0, p1, p2;
extern int _mapped;
umprintf ("starting low level init\n");
mem_size = ram_size(end);
physmem = btoc(mem_size);
start_page = ((int)&end + PAGE_SIZE) & ~(PAGE_SIZE-1);
start_page = (((int)&end + NS532_PAGE_SIZE) & ~(NS532_PAGE_SIZE-1)) & 0xfffff;
avail_start = start_page;
avail_end = mem_size - PAGE_SIZE;
avail_end = mem_size - NS532_PAGE_SIZE;
umprintf ("mem_size = 0x%x\nphysmem=%x\nstart_page=0x%x\navail_end=0x%x\n",
mem_size, physmem, start_page, avail_end);
/* Initialize the mmu with a simple memory map. */
/* A new interrupt stack, i.e. not the rom monitor's. */
_istack = avail_start;
avail_start += PAGE_SIZE;
avail_start += NS532_PAGE_SIZE;
/* The page directory that starts the entire mapping. */
p0 = (int) avail_start;
IdlePTD = p0;
KPTphys = p0;
avail_start += PAGE_SIZE;
avail_start += NS532_PAGE_SIZE;
/* First clear out the page table directory. */
bzero((char *)p0, PAGE_SIZE);
bzero((char *)p0, NS532_PAGE_SIZE);
/* Now for the memory mapped I/O, the ICU and the eprom. */
p1 = (int) avail_start;
avail_start += PAGE_SIZE;
bzero ((char *)p1, PAGE_SIZE);
avail_start += NS532_PAGE_SIZE;
bzero ((char *)p1, NS532_PAGE_SIZE);
umprintf ("point 1,");
/* Addresses here start at FFC00000... */
/* Map the interrupt stack to FFC00000 - FFC00FFF */
@ -158,30 +172,39 @@ _low_level_init ()
/* All futhur entries are cache inhibited. => 0x4? in low bits. */
umprintf ("2\n");
/* The Duarts and Parity. Addresses FFC80000 */
WR_ADR(int, p1+4*0x80, 0x28000043);
umprintf ("3 .. p1 = 0x%x\n", p1);
/* SCSI Polled (Reduced space.) Addresses FFD00000 - FFDFFFFF */
for (ix = 0x100; ix < 0x200; ix++)
WR_ADR(int, p1 + ix*4, 0x30000043 + ((ix - 0x100)<<12));
umprintf ("4,");
/* SCSI "DMA" (Reduced space.) Addresses FFE00000 - FFEEFFFF */
for (ix = 0x200; ix < 0x2ff; ix++)
WR_ADR(int, p1 + ix*4, 0x38000043 + ((ix - 0x200)<<12));
umprintf ("5,");
/* SCSI "DMA" With A22 (EOP) Addresses FFEFF000 - FFEFFFFF */
WR_ADR(int, p1 + 0x2ff*4, 0x38400043);
umprintf ("6,");
/* The e-prom Addresses FFF00000 - FFF3FFFF */
for (ix = 0x300; ix < 0x340; ix++)
WR_ADR(int, p1 + ix*4, 0x10000043 + ((ix - 0x300)<<12));
umprintf ("7,");
/* Finally the ICU! Addresses FFFFF000 - FFFFFFFF */
WR_ADR(int, p1+4*0x3ff, 0xFFFFF043);
umprintf ("8,");
/* Add the memory mapped I/O entry in the directory. */
WR_ADR(int, p0+4*1023, p1 + 0x43);
umprintf ("9,");
/* Map the kernel pages starting at FE00000 and at 0.
It also maps any pages past the end of the kernel,
@ -195,16 +218,18 @@ _low_level_init ()
*/
p2 = (int) avail_start;
avail_start += PAGE_SIZE;
bzero ((char *)p2, PAGE_SIZE);
avail_start += NS532_PAGE_SIZE;
bzero ((char *)p2, NS532_PAGE_SIZE);
WR_ADR(int,p0+4*pdei(KERNBASE), p2 + 3);
WR_ADR(int,p0, p2+3);
for (ix = 0; ix < (avail_start)/PAGE_SIZE; ix++) {
WR_ADR(int, p2 + ix*4, PAGE_SIZE * ix + 3);
umprintf ("10,");
for (ix = 0; ix < (avail_start)/NS532_PAGE_SIZE; ix++) {
WR_ADR(int, p2 + ix*4, NS532_PAGE_SIZE * ix + 3);
}
/* Load the ptb0 register and start mapping. */
umprintf ("exiting low level init\n");
_mapped = 1;
_load_ptb0 (p0);
@ -223,7 +248,9 @@ init532()
void (**int_tab)();
extern int _save_sp;
#ifdef DEBUG
umprintf ("starting init532\n");
#if 1
/* Initial testing messages .... Removed at a later time. */
printf ("Welcome to the first initial bits of NetBSD/532!\n");
@ -236,13 +263,15 @@ init532()
printf ("IdlePTD = 0x%x\n", IdlePTD);
printf ("avail_start = 0x%x\n", avail_start);
printf ("number of kernel pages = %d (0x%x)\n", start_page / PAGE_SIZE,
start_page / PAGE_SIZE);
printf ("number of kernel pages = %d (0x%x)\n", start_page / NS532_PAGE_SIZE,
start_page / NS532_PAGE_SIZE);
free_pages = (mem_size - start_page) / PAGE_SIZE;
free_pages = (mem_size - start_page) / NS532_PAGE_SIZE;
printf ("number of free pages = %d\n", free_pages);
#endif
umprintf ("after init532 printfs\n");
/*#include "ddb.h" */
#if NDDB > 0
kdb_init();
@ -396,7 +425,7 @@ again:
* in that they usually occupy more virtual memory than physical.
*/
size = MAXBSIZE * nbuf;
buffer_map = kmem_suballoc(kernel_map, (vm_offset_t)&buffers,
buffer_map = kmem_suballoc(kernel_map, (vm_offset_t *)&buffers,
&maxaddr, size, FALSE);
minaddr = (vm_offset_t)buffers;
if (vm_map_find(buffer_map, vm_object_allocate(size), (vm_offset_t)0,
@ -447,7 +476,7 @@ again:
mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
M_MBUF, M_NOWAIT);
bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
mb_map = kmem_suballoc(kernel_map, (vm_offset_t *)&mbutl, &maxaddr,
VM_MBUF_SIZE, FALSE);
/*
* Initialize callouts
@ -456,12 +485,10 @@ again:
for (i = 1; i < ncallout; i++)
callout[i-1].c_next = &callout[i];
printf("avail mem = 0x%x\n", ptoa(vm_page_free_count));
printf("avail mem = 0x%x\n", ptoa(cnt.v_free_count));
printf("using %d buffers containing %d bytes of memory\n",
nbuf, bufpages * CLBYTES);
/* CPU-specific ... ??? PAN */
/*
* Set up buffers, so they can be used to read disk labels.
*/
@ -581,6 +608,7 @@ sendsig(catcher, sig, mask, code)
fp->sf_sc.sc_fp = regs[FP];
fp->sf_sc.sc_pc = regs[PC];
fp->sf_sc.sc_ps = regs[PSR];
fp->sf_sc.sc_sb = regs[SB];
regs[SP] = (int)fp;
regs[PC] = (int)(((char *)PS_STRINGS) - (esigcode - sigcode));
}
@ -632,6 +660,7 @@ sigreturn(p, uap, retval)
regs[SP] = scp->sc_sp;
regs[PC] = scp->sc_pc;
regs[PSR] = scp->sc_ps;
regs[SB] = scp->sc_sb;
return(EJUSTRETURN);
}

View File

@ -57,7 +57,6 @@
#include "vm/vm_param.h"
#include "vm/lock.h"
#include "vm/vm_statistics.h"
#include "vm/pmap.h"
#include "vm/vm_prot.h"
@ -173,10 +172,10 @@ mmrw(dev, uio, flags)
/* minor device 1 is kernel memory */
case 1:
c = iov->iov_len;
if (!kernacc((caddr_t)uio->uio_offset, c,
if (!kernacc((caddr_t)(long)uio->uio_offset, c,
uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
return(EFAULT);
error = uiomove((caddr_t)uio->uio_offset, (int)c, uio);
error = uiomove((caddr_t)(long)uio->uio_offset, (int)c, uio);
continue;
/* minor device 2 is EOF/RATHOLE */

View File

@ -36,7 +36,7 @@
*
* @(#)pmap.c 7.7 (Berkeley) 5/12/91
*
* $Id: pmap.c,v 1.3 1994/01/28 03:47:57 phil Exp $
* $Id: pmap.c,v 1.4 1994/04/19 17:14:21 phil Exp $
*/
/*
@ -316,7 +316,7 @@ pmap_bootstrap(firstaddr, loadaddr)
#endif
extern vm_offset_t maxmem, physmem;
ns532pagesperpage = PAGE_SIZE / NS532_PAGE_SIZE;
ns532pagesperpage = 1; /* PAGE_SIZE / NS532_PAGE_SIZE; */
/*
* Initialize protection array.
@ -437,6 +437,9 @@ pmap_init(phys_start, phys_end)
if (pmapdebug & (PDB_FOLLOW|PDB_INIT))
printf("pmap_init(0x%x, 0x%x)\n", phys_start, phys_end);
#endif
if (PAGE_SIZE != NBPG)
panic("pmap_init: CLSIZE != 1");
/*
* Now that kernel map has been allocated, we can mark as
* unavailable regions which we have mapped in locore.

View File

@ -0,0 +1,67 @@
#include <stdarg.h>
static char *ksprintn __P((u_long num, int base, int *len));
void
umprintf(char *fmt,...)
{
va_list ap;
char *p;
int tmp;
int base;
unsigned long ul;
char ch;
va_start (ap,fmt);
for (;;) {
while ((ch = *fmt++) != '%') {
if (ch == '\0')
return;
scncnputc(0, ch);
}
ch = *fmt++;
switch (ch) {
case 'd':
ul = va_arg(ap, u_long);
base = 10;
goto number;
case 'x':
ul = va_arg(ap, u_long);
base = 16;
number: p = ksprintn(ul, base, &tmp);
while (ch = *p--)
scncnputc(0,ch);
break;
default:
scncnputc(0,ch);
}
}
}
/*
* Put a number (base <= 16) in a buffer in reverse order; return an
* optional length and a pointer to the NULL terminated (preceded?)
* buffer.
*/
static char *
ksprintn(ul, base, lenp)
register u_long ul;
register int base, *lenp;
{ /* A long in base 8, plus NULL. */
static char buf[sizeof(long) * NBBY / 3 + 2];
register char *p;
int d;
p = buf;
*p='\0';
do {
d = ul % base;
if (d < 10)
*++p = '0' + d;
else
*++p = 'a' + d - 10;
} while (ul /= base);
if (lenp)
*lenp = p - buf;
return (p);
}