1*27626149Smatthieu /* $OpenBSD: machdep.c,v 1.77 2002/08/24 17:21:44 matthieu Exp $ */ 22a2685f2Sart /* $NetBSD: machdep.c,v 1.210 2000/06/01 17:12:38 thorpej Exp $ */ 3aed035abSart 4aed035abSart /*- 5aed035abSart * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 6aed035abSart * All rights reserved. 7aed035abSart * 8aed035abSart * This code is derived from software contributed to The NetBSD Foundation 9aed035abSart * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 10aed035abSart * NASA Ames Research Center and by Chris G. Demetriou. 11aed035abSart * 12aed035abSart * Redistribution and use in source and binary forms, with or without 13aed035abSart * modification, are permitted provided that the following conditions 14aed035abSart * are met: 15aed035abSart * 1. Redistributions of source code must retain the above copyright 16aed035abSart * notice, this list of conditions and the following disclaimer. 17aed035abSart * 2. Redistributions in binary form must reproduce the above copyright 18aed035abSart * notice, this list of conditions and the following disclaimer in the 19aed035abSart * documentation and/or other materials provided with the distribution. 20aed035abSart * 3. All advertising materials mentioning features or use of this software 21aed035abSart * must display the following acknowledgement: 22aed035abSart * This product includes software developed by the NetBSD 23aed035abSart * Foundation, Inc. and its contributors. 24aed035abSart * 4. Neither the name of The NetBSD Foundation nor the names of its 25aed035abSart * contributors may be used to endorse or promote products derived 26aed035abSart * from this software without specific prior written permission. 27aed035abSart * 28aed035abSart * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29aed035abSart * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30aed035abSart * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31aed035abSart * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32aed035abSart * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33aed035abSart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34aed035abSart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35aed035abSart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36aed035abSart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37aed035abSart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38aed035abSart * POSSIBILITY OF SUCH DAMAGE. 39aed035abSart */ 40df930be7Sderaadt 41df930be7Sderaadt /* 42417eba8cSderaadt * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 43df930be7Sderaadt * All rights reserved. 44df930be7Sderaadt * 45df930be7Sderaadt * Author: Chris G. Demetriou 46df930be7Sderaadt * 47df930be7Sderaadt * Permission to use, copy, modify and distribute this software and 48df930be7Sderaadt * its documentation is hereby granted, provided that both the copyright 49df930be7Sderaadt * notice and this permission notice appear in all copies of the 50df930be7Sderaadt * software, derivative works or modified versions, and any portions 51df930be7Sderaadt * thereof, and that both notices appear in supporting documentation. 52df930be7Sderaadt * 53df930be7Sderaadt * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 54df930be7Sderaadt * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 55df930be7Sderaadt * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 56df930be7Sderaadt * 57df930be7Sderaadt * Carnegie Mellon requests users of this software to return to 58df930be7Sderaadt * 59df930be7Sderaadt * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 60df930be7Sderaadt * School of Computer Science 61df930be7Sderaadt * Carnegie Mellon University 62df930be7Sderaadt * Pittsburgh PA 15213-3890 63df930be7Sderaadt * 64df930be7Sderaadt * any improvements or extensions that they make and grant Carnegie the 65df930be7Sderaadt * rights to redistribute these changes. 66df930be7Sderaadt */ 67df930be7Sderaadt 68df930be7Sderaadt #include <sys/param.h> 69df930be7Sderaadt #include <sys/systm.h> 70df930be7Sderaadt #include <sys/signalvar.h> 71df930be7Sderaadt #include <sys/kernel.h> 72df930be7Sderaadt #include <sys/proc.h> 732a2685f2Sart #include <sys/sched.h> 74df930be7Sderaadt #include <sys/buf.h> 75df930be7Sderaadt #include <sys/reboot.h> 76417eba8cSderaadt #include <sys/device.h> 77df930be7Sderaadt #include <sys/conf.h> 78df930be7Sderaadt #include <sys/file.h> 79d66eba84Sart #include <sys/timeout.h> 80df930be7Sderaadt #include <sys/malloc.h> 81df930be7Sderaadt #include <sys/mbuf.h> 82df930be7Sderaadt #include <sys/msgbuf.h> 83df930be7Sderaadt #include <sys/ioctl.h> 84df930be7Sderaadt #include <sys/tty.h> 85df930be7Sderaadt #include <sys/user.h> 86df930be7Sderaadt #include <sys/exec.h> 87df930be7Sderaadt #include <sys/exec_ecoff.h> 88489e49f9Smiod #include <uvm/uvm_extern.h> 89df930be7Sderaadt #include <sys/sysctl.h> 9050ce9ee0Sniklas #include <sys/core.h> 9150ce9ee0Sniklas #include <sys/kcore.h> 9250ce9ee0Sniklas #include <machine/kcore.h> 93433075b6Spvalchev #ifndef NO_IEEE 94433075b6Spvalchev #include <machine/fpu.h> 95433075b6Spvalchev #endif 96df930be7Sderaadt #ifdef SYSVMSG 97df930be7Sderaadt #include <sys/msg.h> 98df930be7Sderaadt #endif 99df930be7Sderaadt #ifdef SYSVSEM 100df930be7Sderaadt #include <sys/sem.h> 101df930be7Sderaadt #endif 102df930be7Sderaadt #ifdef SYSVSHM 103df930be7Sderaadt #include <sys/shm.h> 104df930be7Sderaadt #endif 105df930be7Sderaadt 106df930be7Sderaadt #include <sys/mount.h> 107df930be7Sderaadt #include <sys/syscallargs.h> 108df930be7Sderaadt 109aed035abSart #include <uvm/uvm_extern.h> 110df930be7Sderaadt 111df930be7Sderaadt #include <dev/cons.h> 112df930be7Sderaadt 11350ce9ee0Sniklas #include <machine/autoconf.h> 114df930be7Sderaadt #include <machine/cpu.h> 115df930be7Sderaadt #include <machine/reg.h> 116df930be7Sderaadt #include <machine/rpb.h> 117df930be7Sderaadt #include <machine/prom.h> 1183a630e3fSniklas #include <machine/cpuconf.h> 119433075b6Spvalchev #ifndef NO_IEEE 120433075b6Spvalchev #include <machine/ieeefp.h> 121433075b6Spvalchev #endif 122df930be7Sderaadt 12345e5a1a0Sart #include <dev/pci/pcivar.h> 12445e5a1a0Sart 12512f8bbedSniklas #ifdef DDB 12612f8bbedSniklas #include <machine/db_machdep.h> 12712f8bbedSniklas #include <ddb/db_access.h> 12812f8bbedSniklas #include <ddb/db_sym.h> 12912f8bbedSniklas #include <ddb/db_extern.h> 13012f8bbedSniklas #endif 13112f8bbedSniklas 132c4071fd1Smillert int cpu_dump(void); 133c4071fd1Smillert int cpu_dumpsize(void); 134c4071fd1Smillert u_long cpu_dump_mempagecnt(void); 135c4071fd1Smillert void dumpsys(void); 136c4071fd1Smillert caddr_t allocsys(caddr_t); 137c4071fd1Smillert void identifycpu(void); 138c4071fd1Smillert void regdump(struct trapframe *framep); 139c4071fd1Smillert void printregs(struct reg *); 140df930be7Sderaadt 141df930be7Sderaadt /* 142df930be7Sderaadt * Declare these as initialized data so we can patch them. 143df930be7Sderaadt */ 144df930be7Sderaadt #ifdef NBUF 145df930be7Sderaadt int nbuf = NBUF; 146df930be7Sderaadt #else 147df930be7Sderaadt int nbuf = 0; 148df930be7Sderaadt #endif 14960535ec9Smaja 15060535ec9Smaja #ifndef BUFCACHEPERCENT 15160535ec9Smaja #define BUFCACHEPERCENT 10 15260535ec9Smaja #endif 15360535ec9Smaja 154df930be7Sderaadt #ifdef BUFPAGES 155df930be7Sderaadt int bufpages = BUFPAGES; 156df930be7Sderaadt #else 157df930be7Sderaadt int bufpages = 0; 158df930be7Sderaadt #endif 15960535ec9Smaja int bufcachepercent = BUFCACHEPERCENT; 160aed035abSart 161ab8e80c5Sart struct vm_map *exec_map = NULL; 162ab8e80c5Sart struct vm_map *phys_map = NULL; 163aed035abSart 164*27626149Smatthieu #ifdef APERTURE 165*27626149Smatthieu #ifdef INSECURE 166*27626149Smatthieu int allowaperture = 1; 167*27626149Smatthieu #else 168*27626149Smatthieu int allowaperture = 0; 169*27626149Smatthieu #endif 170*27626149Smatthieu #endif 171*27626149Smatthieu 172df930be7Sderaadt int maxmem; /* max memory per process */ 173df930be7Sderaadt 174df930be7Sderaadt int totalphysmem; /* total amount of physical memory in system */ 17574652a67Sniklas int physmem; /* physical mem used by OpenBSD + some rsvd */ 176df930be7Sderaadt int resvmem; /* amount of memory reserved for PROM */ 177df930be7Sderaadt int unusedmem; /* amount of memory for OS that we don't use */ 178df930be7Sderaadt int unknownmem; /* amount of memory with an unknown use */ 179df930be7Sderaadt 180df930be7Sderaadt int cputype; /* system type, from the RPB */ 181df930be7Sderaadt 1822a2685f2Sart int bootdev_debug = 0; /* patchable, or from DDB */ 1832a2685f2Sart 184df930be7Sderaadt /* 185df930be7Sderaadt * XXX We need an address to which we can assign things so that they 186df930be7Sderaadt * won't be optimized away because we didn't use the value. 187df930be7Sderaadt */ 188df930be7Sderaadt u_int32_t no_optimize; 189df930be7Sderaadt 190df930be7Sderaadt /* the following is used externally (sysctl_hw) */ 191aed035abSart char machine[] = MACHINE; /* from <machine/param.h> */ 192417eba8cSderaadt char cpu_model[128]; 193aed035abSart char root_device[17]; 194df930be7Sderaadt 195df930be7Sderaadt struct user *proc0paddr; 196df930be7Sderaadt 197df930be7Sderaadt /* Number of machine cycles per microsecond */ 198df930be7Sderaadt u_int64_t cycles_per_usec; 199df930be7Sderaadt 200df930be7Sderaadt /* number of cpus in the box. really! */ 201df930be7Sderaadt int ncpus; 202df930be7Sderaadt 203aed035abSart struct bootinfo_kernel bootinfo; 204aed035abSart 205aed035abSart /* For built-in TCDS */ 206aed035abSart #if defined(DEC_3000_300) || defined(DEC_3000_500) 207aed035abSart u_int8_t dec_3000_scsiid[2], dec_3000_scsifast[2]; 208aed035abSart #endif 209aed035abSart 210aed035abSart struct platform platform; 211417eba8cSderaadt 212417eba8cSderaadt /* for cpu_sysctl() */ 21350ce9ee0Sniklas int alpha_unaligned_print = 1; /* warn about unaligned accesses */ 21450ce9ee0Sniklas int alpha_unaligned_fix = 1; /* fix up unaligned accesses */ 215881c1eabSart int alpha_unaligned_sigbus = 1; /* SIGBUS on fixed-up accesses */ 216433075b6Spvalchev #ifndef NO_IEEE 217433075b6Spvalchev int alpha_fp_sync_complete = 0; /* fp fixup if sync even without /s */ 218433075b6Spvalchev #endif 21950ce9ee0Sniklas 220aed035abSart /* 221aed035abSart * XXX This should be dynamically sized, but we have the chicken-egg problem! 222aed035abSart * XXX it should also be larger than it is, because not all of the mddt 223aed035abSart * XXX clusters end up being used for VM. 224aed035abSart */ 225aed035abSart phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; /* low size bits overloaded */ 226aed035abSart int mem_cluster_cnt; 227aed035abSart 2283a630e3fSniklas void 229aed035abSart alpha_init(pfn, ptb, bim, bip, biv) 230df930be7Sderaadt u_long pfn; /* first free PFN number */ 231df930be7Sderaadt u_long ptb; /* PFN of current level 1 page table */ 232aed035abSart u_long bim; /* bootinfo magic */ 233aed035abSart u_long bip; /* bootinfo pointer */ 234aed035abSart u_long biv; /* bootinfo version */ 235df930be7Sderaadt { 236aed035abSart extern char kernel_text[], _end[]; 237df930be7Sderaadt struct mddt *mddtp; 238aed035abSart struct mddt_cluster *memc; 239df930be7Sderaadt int i, mddtweird; 240aed035abSart struct vm_physseg *vps; 241aed035abSart vaddr_t kernstart, kernend; 242aed035abSart paddr_t kernstartpfn, kernendpfn, pfn0, pfn1; 243aed035abSart vsize_t size; 244df930be7Sderaadt char *p; 245aed035abSart caddr_t v; 2462a2685f2Sart const char *bootinfo_msg; 247aed035abSart const struct cpuinit *c; 248aed035abSart extern caddr_t esym; 249aed035abSart struct cpu_info *ci; 250aed035abSart cpuid_t cpu_id; 251df930be7Sderaadt 252aed035abSart /* NO OUTPUT ALLOWED UNTIL FURTHER NOTICE */ 253f3914c62Sniklas 254df930be7Sderaadt /* 255aed035abSart * Turn off interrupts (not mchecks) and floating point. 256df930be7Sderaadt * Make sure the instruction and data streams are consistent. 257df930be7Sderaadt */ 258aed035abSart (void)alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH); 25950ce9ee0Sniklas alpha_pal_wrfen(0); 26050ce9ee0Sniklas ALPHA_TBIA(); 26150ce9ee0Sniklas alpha_pal_imb(); 262df930be7Sderaadt 263aed035abSart cpu_id = cpu_number(); 264aed035abSart 265aed035abSart #if defined(MULTIPROCESSOR) 266df930be7Sderaadt /* 267aed035abSart * Set our SysValue to the address of our cpu_info structure. 268aed035abSart * Secondary processors do this in their spinup trampoline. 269df930be7Sderaadt */ 270aed035abSart alpha_pal_wrval((u_long)&cpu_info[cpu_id]); 271aed035abSart #endif 272aed035abSart 273aed035abSart ci = curcpu(); 274aed035abSart ci->ci_cpuid = cpu_id; 275aed035abSart 276aed035abSart /* 277aed035abSart * Get critical system information (if possible, from the 278aed035abSart * information provided by the boot program). 279aed035abSart */ 280aed035abSart bootinfo_msg = NULL; 281aed035abSart if (bim == BOOTINFO_MAGIC) { 282aed035abSart if (biv == 0) { /* backward compat */ 283aed035abSart biv = *(u_long *)bip; 284aed035abSart bip += 8; 285aed035abSart } 286aed035abSart switch (biv) { 287aed035abSart case 1: { 288aed035abSart struct bootinfo_v1 *v1p = (struct bootinfo_v1 *)bip; 289aed035abSart 290aed035abSart bootinfo.ssym = v1p->ssym; 291aed035abSart bootinfo.esym = v1p->esym; 292aed035abSart /* hwrpb may not be provided by boot block in v1 */ 293aed035abSart if (v1p->hwrpb != NULL) { 294aed035abSart bootinfo.hwrpb_phys = 295aed035abSart ((struct rpb *)v1p->hwrpb)->rpb_phys; 296aed035abSart bootinfo.hwrpb_size = v1p->hwrpbsize; 297aed035abSart } else { 298aed035abSart bootinfo.hwrpb_phys = 299aed035abSart ((struct rpb *)HWRPB_ADDR)->rpb_phys; 300aed035abSart bootinfo.hwrpb_size = 301aed035abSart ((struct rpb *)HWRPB_ADDR)->rpb_size; 302aed035abSart } 303aed035abSart bcopy(v1p->boot_flags, bootinfo.boot_flags, 304aed035abSart min(sizeof v1p->boot_flags, 305aed035abSart sizeof bootinfo.boot_flags)); 306aed035abSart bcopy(v1p->booted_kernel, bootinfo.booted_kernel, 307aed035abSart min(sizeof v1p->booted_kernel, 308aed035abSart sizeof bootinfo.booted_kernel)); 309aed035abSart /* booted dev not provided in bootinfo */ 310aed035abSart init_prom_interface((struct rpb *) 311aed035abSart ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys)); 312aed035abSart prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev, 313aed035abSart sizeof bootinfo.booted_dev); 314aed035abSart break; 315aed035abSart } 316aed035abSart default: 317aed035abSart bootinfo_msg = "unknown bootinfo version"; 318aed035abSart goto nobootinfo; 319aed035abSart } 320aed035abSart } else { 321aed035abSart bootinfo_msg = "boot program did not pass bootinfo"; 322aed035abSart nobootinfo: 323aed035abSart bootinfo.ssym = (u_long)_end; 324aed035abSart bootinfo.esym = (u_long)_end; 325aed035abSart bootinfo.hwrpb_phys = ((struct rpb *)HWRPB_ADDR)->rpb_phys; 326aed035abSart bootinfo.hwrpb_size = ((struct rpb *)HWRPB_ADDR)->rpb_size; 327aed035abSart init_prom_interface((struct rpb *)HWRPB_ADDR); 328aed035abSart prom_getenv(PROM_E_BOOTED_OSFLAGS, bootinfo.boot_flags, 329aed035abSart sizeof bootinfo.boot_flags); 330aed035abSart prom_getenv(PROM_E_BOOTED_FILE, bootinfo.booted_kernel, 331aed035abSart sizeof bootinfo.booted_kernel); 332aed035abSart prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev, 333aed035abSart sizeof bootinfo.booted_dev); 334aed035abSart } 335aed035abSart 336aed035abSart esym = (caddr_t)bootinfo.esym; 337aed035abSart /* 338aed035abSart * Initialize the kernel's mapping of the RPB. It's needed for 339aed035abSart * lots of things. 340aed035abSart */ 341aed035abSart hwrpb = (struct rpb *)ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys); 342aed035abSart 343aed035abSart #if defined(DEC_3000_300) || defined(DEC_3000_500) 344aed035abSart if (hwrpb->rpb_type == ST_DEC_3000_300 || 345aed035abSart hwrpb->rpb_type == ST_DEC_3000_500) { 346aed035abSart prom_getenv(PROM_E_SCSIID, dec_3000_scsiid, 347aed035abSart sizeof(dec_3000_scsiid)); 348aed035abSart prom_getenv(PROM_E_SCSIFAST, dec_3000_scsifast, 349aed035abSart sizeof(dec_3000_scsifast)); 350aed035abSart } 351aed035abSart #endif 352df930be7Sderaadt 353df930be7Sderaadt /* 354df930be7Sderaadt * Remember how many cycles there are per microsecond, 355df930be7Sderaadt * so that we can use delay(). Round up, for safety. 356df930be7Sderaadt */ 357df930be7Sderaadt cycles_per_usec = (hwrpb->rpb_cc_freq + 999999) / 1000000; 358df930be7Sderaadt 359df930be7Sderaadt /* 3609e71c994Saaron * Initialize the (temporary) bootstrap console interface, so 361aed035abSart * we can use printf until the VM system starts being setup. 362aed035abSart * The real console is initialized before then. 363df930be7Sderaadt */ 364aed035abSart init_bootstrap_console(); 365aed035abSart 366aed035abSart /* OUTPUT NOW ALLOWED */ 367aed035abSart 368aed035abSart /* delayed from above */ 369aed035abSart if (bootinfo_msg) 370aed035abSart printf("WARNING: %s (0x%lx, 0x%lx, 0x%lx)\n", 371aed035abSart bootinfo_msg, bim, bip, biv); 372aed035abSart 373aed035abSart /* Initialize the trap vectors on the primary processor. */ 374aed035abSart trap_init(); 375df930be7Sderaadt 376df930be7Sderaadt /* 377aed035abSart * Find out what hardware we're on, and do basic initialization. 378df930be7Sderaadt */ 379aed035abSart cputype = hwrpb->rpb_type; 380aed035abSart if (cputype < 0) { 381aed035abSart /* 382aed035abSart * At least some white-box systems have SRM which 383aed035abSart * reports a systype that's the negative of their 384aed035abSart * blue-box counterpart. 385aed035abSart */ 386aed035abSart cputype = -cputype; 387aed035abSart } 388aed035abSart c = platform_lookup(cputype); 389aed035abSart if (c == NULL) { 390aed035abSart platform_not_supported(); 391aed035abSart /* NOTREACHED */ 392aed035abSart } 393aed035abSart (*c->init)(); 394aed035abSart strcpy(cpu_model, platform.model); 39550ce9ee0Sniklas 39650ce9ee0Sniklas /* 3979e71c994Saaron * Initialize the real console, so that the bootstrap console is 398aed035abSart * no longer necessary. 39950ce9ee0Sniklas */ 400aed035abSart (*platform.cons_init)(); 401aed035abSart 402aed035abSart #ifdef DIAGNOSTIC 403aed035abSart /* Paranoid sanity checking */ 404aed035abSart 405aed035abSart /* We should always be running on the primary. */ 406aed035abSart assert(hwrpb->rpb_primary_cpu_id == alpha_pal_whami()); 407aed035abSart 408aed035abSart /* 409aed035abSart * On single-CPU systypes, the primary should always be CPU 0, 410aed035abSart * except on Alpha 8200 systems where the CPU id is related 411aed035abSart * to the VID, which is related to the Turbo Laser node id. 412aed035abSart */ 413aed035abSart if (cputype != ST_DEC_21000) 414aed035abSart assert(hwrpb->rpb_primary_cpu_id == 0); 415aed035abSart #endif 416aed035abSart 417aed035abSart /* NO MORE FIRMWARE ACCESS ALLOWED */ 418aed035abSart #ifdef _PMAP_MAY_USE_PROM_CONSOLE 419aed035abSart /* 420aed035abSart * XXX (unless _PMAP_MAY_USE_PROM_CONSOLE is defined and 421aed035abSart * XXX pmap_uses_prom_console() evaluates to non-zero.) 422aed035abSart */ 423aed035abSart #endif 424aed035abSart 425aed035abSart /* 426aed035abSart * find out this system's page size 427aed035abSart */ 42873b9fe7cSart if ((uvmexp.pagesize = hwrpb->rpb_page_size) != 8192) 42973b9fe7cSart panic("page size %d != 8192?!", uvmexp.pagesize); 430aed035abSart 431aed035abSart uvm_setpagesize(); 432aed035abSart 433aed035abSart /* 434aed035abSart * Find the beginning and end of the kernel (and leave a 435aed035abSart * bit of space before the beginning for the bootstrap 436aed035abSart * stack). 437aed035abSart */ 438aed035abSart kernstart = trunc_page((vaddr_t)kernel_text) - 2 * PAGE_SIZE; 439aed035abSart kernend = (vaddr_t)round_page((vaddr_t)bootinfo.esym); 440aed035abSart 441aed035abSart kernstartpfn = atop(ALPHA_K0SEG_TO_PHYS(kernstart)); 442aed035abSart kernendpfn = atop(ALPHA_K0SEG_TO_PHYS(kernend)); 443df930be7Sderaadt 444df930be7Sderaadt /* 445df930be7Sderaadt * Find out how much memory is available, by looking at 446df930be7Sderaadt * the memory cluster descriptors. This also tries to do 447df930be7Sderaadt * its best to detect things things that have never been seen 448df930be7Sderaadt * before... 449df930be7Sderaadt */ 450df930be7Sderaadt mddtp = (struct mddt *)(((caddr_t)hwrpb) + hwrpb->rpb_memdat_off); 451df930be7Sderaadt 452aed035abSart /* MDDT SANITY CHECKING */ 453df930be7Sderaadt mddtweird = 0; 454aed035abSart if (mddtp->mddt_cluster_cnt < 2) { 455df930be7Sderaadt mddtweird = 1; 456aed035abSart printf("WARNING: weird number of mem clusters: %lu\n", 457aed035abSart mddtp->mddt_cluster_cnt); 458df930be7Sderaadt } 459df930be7Sderaadt 460aed035abSart #if 0 461aed035abSart printf("Memory cluster count: %d\n", mddtp->mddt_cluster_cnt); 462aed035abSart #endif 463df930be7Sderaadt 464aed035abSart for (i = 0; i < mddtp->mddt_cluster_cnt; i++) { 465aed035abSart memc = &mddtp->mddt_clusters[i]; 466aed035abSart #if 0 467aed035abSart printf("MEMC %d: pfn 0x%lx cnt 0x%lx usage 0x%lx\n", i, 468aed035abSart memc->mddt_pfn, memc->mddt_pg_cnt, memc->mddt_usage); 469aed035abSart #endif 470aed035abSart totalphysmem += memc->mddt_pg_cnt; 471aed035abSart if (mem_cluster_cnt < VM_PHYSSEG_MAX) { /* XXX */ 472aed035abSart mem_clusters[mem_cluster_cnt].start = 473aed035abSart ptoa(memc->mddt_pfn); 474aed035abSart mem_clusters[mem_cluster_cnt].size = 475aed035abSart ptoa(memc->mddt_pg_cnt); 476aed035abSart if (memc->mddt_usage & MDDT_mbz || 477aed035abSart memc->mddt_usage & MDDT_NONVOLATILE || /* XXX */ 478aed035abSart memc->mddt_usage & MDDT_PALCODE) 479aed035abSart mem_clusters[mem_cluster_cnt].size |= 480aed035abSart VM_PROT_READ; 481aed035abSart else 482aed035abSart mem_clusters[mem_cluster_cnt].size |= 483aed035abSart VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; 484aed035abSart mem_cluster_cnt++; 485aed035abSart } 486aed035abSart 487aed035abSart if (memc->mddt_usage & MDDT_mbz) { 488aed035abSart mddtweird = 1; 489aed035abSart printf("WARNING: mem cluster %d has weird " 490aed035abSart "usage 0x%lx\n", i, memc->mddt_usage); 491aed035abSart unknownmem += memc->mddt_pg_cnt; 492aed035abSart continue; 493aed035abSart } 494aed035abSart if (memc->mddt_usage & MDDT_NONVOLATILE) { 495aed035abSart /* XXX should handle these... */ 496aed035abSart printf("WARNING: skipping non-volatile mem " 497aed035abSart "cluster %d\n", i); 498aed035abSart unusedmem += memc->mddt_pg_cnt; 499aed035abSart continue; 500aed035abSart } 501aed035abSart if (memc->mddt_usage & MDDT_PALCODE) { 502aed035abSart resvmem += memc->mddt_pg_cnt; 503aed035abSart continue; 504aed035abSart } 505aed035abSart 506aed035abSart /* 507aed035abSart * We have a memory cluster available for system 508aed035abSart * software use. We must determine if this cluster 509aed035abSart * holds the kernel. 510aed035abSart */ 511aed035abSart #ifdef _PMAP_MAY_USE_PROM_CONSOLE 512aed035abSart /* 513aed035abSart * XXX If the kernel uses the PROM console, we only use the 514aed035abSart * XXX memory after the kernel in the first system segment, 515aed035abSart * XXX to avoid clobbering prom mapping, data, etc. 516aed035abSart */ 517aed035abSart if (!pmap_uses_prom_console() || physmem == 0) { 518aed035abSart #endif /* _PMAP_MAY_USE_PROM_CONSOLE */ 519aed035abSart physmem += memc->mddt_pg_cnt; 520aed035abSart pfn0 = memc->mddt_pfn; 521aed035abSart pfn1 = memc->mddt_pfn + memc->mddt_pg_cnt; 522aed035abSart if (pfn0 <= kernstartpfn && kernendpfn <= pfn1) { 523aed035abSart /* 524aed035abSart * Must compute the location of the kernel 525aed035abSart * within the segment. 526aed035abSart */ 527aed035abSart #if 0 528aed035abSart printf("Cluster %d contains kernel\n", i); 529aed035abSart #endif 530aed035abSart #ifdef _PMAP_MAY_USE_PROM_CONSOLE 531aed035abSart if (!pmap_uses_prom_console()) { 532aed035abSart #endif /* _PMAP_MAY_USE_PROM_CONSOLE */ 533aed035abSart if (pfn0 < kernstartpfn) { 534aed035abSart /* 535aed035abSart * There is a chunk before the kernel. 536aed035abSart */ 537aed035abSart #if 0 538aed035abSart printf("Loading chunk before kernel: " 539aed035abSart "0x%lx / 0x%lx\n", pfn0, kernstartpfn); 540aed035abSart #endif 541aed035abSart uvm_page_physload(pfn0, kernstartpfn, 542aed035abSart pfn0, kernstartpfn, VM_FREELIST_DEFAULT); 543aed035abSart } 544aed035abSart #ifdef _PMAP_MAY_USE_PROM_CONSOLE 545aed035abSart } 546aed035abSart #endif /* _PMAP_MAY_USE_PROM_CONSOLE */ 547aed035abSart if (kernendpfn < pfn1) { 548aed035abSart /* 549aed035abSart * There is a chunk after the kernel. 550aed035abSart */ 551aed035abSart #if 0 552aed035abSart printf("Loading chunk after kernel: " 553aed035abSart "0x%lx / 0x%lx\n", kernendpfn, pfn1); 554aed035abSart #endif 555aed035abSart uvm_page_physload(kernendpfn, pfn1, 556aed035abSart kernendpfn, pfn1, VM_FREELIST_DEFAULT); 557aed035abSart } 558aed035abSart } else { 559aed035abSart /* 560aed035abSart * Just load this cluster as one chunk. 561aed035abSart */ 562aed035abSart #if 0 563aed035abSart printf("Loading cluster %d: 0x%lx / 0x%lx\n", i, 564aed035abSart pfn0, pfn1); 565aed035abSart #endif 566aed035abSart uvm_page_physload(pfn0, pfn1, pfn0, pfn1, 567aed035abSart VM_FREELIST_DEFAULT); 568aed035abSart } 569aed035abSart #ifdef _PMAP_MAY_USE_PROM_CONSOLE 570aed035abSart } 571aed035abSart #endif /* _PMAP_MAY_USE_PROM_CONSOLE */ 572aed035abSart } 573aed035abSart 574aed035abSart /* 575aed035abSart * Dump out the MDDT if it looks odd... 576aed035abSart */ 577df930be7Sderaadt if (mddtweird) { 578df930be7Sderaadt printf("\n"); 579df930be7Sderaadt printf("complete memory cluster information:\n"); 580df930be7Sderaadt for (i = 0; i < mddtp->mddt_cluster_cnt; i++) { 581df930be7Sderaadt printf("mddt %d:\n", i); 582df930be7Sderaadt printf("\tpfn %lx\n", 583df930be7Sderaadt mddtp->mddt_clusters[i].mddt_pfn); 584df930be7Sderaadt printf("\tcnt %lx\n", 585df930be7Sderaadt mddtp->mddt_clusters[i].mddt_pg_cnt); 586df930be7Sderaadt printf("\ttest %lx\n", 587df930be7Sderaadt mddtp->mddt_clusters[i].mddt_pg_test); 588df930be7Sderaadt printf("\tbva %lx\n", 589df930be7Sderaadt mddtp->mddt_clusters[i].mddt_v_bitaddr); 590df930be7Sderaadt printf("\tbpa %lx\n", 591df930be7Sderaadt mddtp->mddt_clusters[i].mddt_p_bitaddr); 592df930be7Sderaadt printf("\tbcksum %lx\n", 593df930be7Sderaadt mddtp->mddt_clusters[i].mddt_bit_cksum); 594df930be7Sderaadt printf("\tusage %lx\n", 595df930be7Sderaadt mddtp->mddt_clusters[i].mddt_usage); 596df930be7Sderaadt } 597df930be7Sderaadt printf("\n"); 598df930be7Sderaadt } 599df930be7Sderaadt 600df930be7Sderaadt if (totalphysmem == 0) 601df930be7Sderaadt panic("can't happen: system seems to have no memory!"); 602df930be7Sderaadt maxmem = physmem; 603df930be7Sderaadt #if 0 604df930be7Sderaadt printf("totalphysmem = %d\n", totalphysmem); 605df930be7Sderaadt printf("physmem = %d\n", physmem); 606df930be7Sderaadt printf("resvmem = %d\n", resvmem); 607df930be7Sderaadt printf("unusedmem = %d\n", unusedmem); 608df930be7Sderaadt printf("unknownmem = %d\n", unknownmem); 609df930be7Sderaadt #endif 610df930be7Sderaadt 611df930be7Sderaadt /* 612aed035abSart * Initialize error message buffer (at end of core). 613df930be7Sderaadt */ 614aed035abSart { 615aed035abSart vsize_t sz = (vsize_t)round_page(MSGBUFSIZE); 616aed035abSart vsize_t reqsz = sz; 617df930be7Sderaadt 618aed035abSart vps = &vm_physmem[vm_nphysseg - 1]; 619e1da84e1Salex 620aed035abSart /* shrink so that it'll fit in the last segment */ 621aed035abSart if ((vps->avail_end - vps->avail_start) < atop(sz)) 622aed035abSart sz = ptoa(vps->avail_end - vps->avail_start); 623aed035abSart 624aed035abSart vps->end -= atop(sz); 625aed035abSart vps->avail_end -= atop(sz); 626aed035abSart initmsgbuf((caddr_t) ALPHA_PHYS_TO_K0SEG(ptoa(vps->end)), sz); 627aed035abSart 628aed035abSart /* Remove the last segment if it now has no pages. */ 629aed035abSart if (vps->start == vps->end) 630aed035abSart vm_nphysseg--; 631aed035abSart 632aed035abSart /* warn if the message buffer had to be shrunk */ 633aed035abSart if (sz != reqsz) 634aed035abSart printf("WARNING: %ld bytes not available for msgbuf " 635aed035abSart "in last cluster (%ld used)\n", reqsz, sz); 636aed035abSart 637aed035abSart } 638aed035abSart 639df930be7Sderaadt /* 640df930be7Sderaadt * Init mapping for u page(s) for proc 0 641df930be7Sderaadt */ 642aed035abSart proc0.p_addr = proc0paddr = 643aed035abSart (struct user *)pmap_steal_memory(UPAGES * PAGE_SIZE, NULL, NULL); 644df930be7Sderaadt 645df930be7Sderaadt /* 646aed035abSart * Allocate space for system data structures. These data structures 647aed035abSart * are allocated here instead of cpu_startup() because physical 648aed035abSart * memory is directly addressable. We don't have to map these into 649aed035abSart * virtual address space. 650df930be7Sderaadt */ 651aed035abSart size = (vsize_t)allocsys(NULL); 652aed035abSart v = (caddr_t)pmap_steal_memory(size, NULL, NULL); 653aed035abSart if ((allocsys(v) - v) != size) 654aed035abSart panic("alpha_init: table size inconsistency"); 655df930be7Sderaadt 656df930be7Sderaadt /* 657df930be7Sderaadt * Clear allocated memory. 658df930be7Sderaadt */ 659aed035abSart bzero(v, size); 660df930be7Sderaadt 661df930be7Sderaadt /* 662df930be7Sderaadt * Initialize the virtual memory system, and set the 663df930be7Sderaadt * page table base register in proc 0's PCB. 664df930be7Sderaadt */ 665aed035abSart pmap_bootstrap(ALPHA_PHYS_TO_K0SEG(ptb << PGSHIFT), 666aed035abSart hwrpb->rpb_max_asn, hwrpb->rpb_pcs_cnt); 667df930be7Sderaadt 668df930be7Sderaadt /* 669df930be7Sderaadt * Initialize the rest of proc 0's PCB, and cache its physical 670df930be7Sderaadt * address. 671df930be7Sderaadt */ 672df930be7Sderaadt proc0.p_md.md_pcbpaddr = 673aed035abSart (struct pcb *)ALPHA_K0SEG_TO_PHYS((vaddr_t)&proc0paddr->u_pcb); 674df930be7Sderaadt 675df930be7Sderaadt /* 676df930be7Sderaadt * Set the kernel sp, reserving space for an (empty) trapframe, 677df930be7Sderaadt * and make proc0's trapframe pointer point to it for sanity. 678df930be7Sderaadt */ 67950ce9ee0Sniklas proc0paddr->u_pcb.pcb_hw.apcb_ksp = 680df930be7Sderaadt (u_int64_t)proc0paddr + USPACE - sizeof(struct trapframe); 68174652a67Sniklas proc0.p_md.md_tf = 68274652a67Sniklas (struct trapframe *)proc0paddr->u_pcb.pcb_hw.apcb_ksp; 68350ce9ee0Sniklas 684aed035abSart /* 685aed035abSart * Initialize the primary CPU's idle PCB to proc0's. In a 686aed035abSart * MULTIPROCESSOR configuration, each CPU will later get 687aed035abSart * its own idle PCB when autoconfiguration runs. 688aed035abSart */ 689aed035abSart ci->ci_idle_pcb = &proc0paddr->u_pcb; 690aed035abSart ci->ci_idle_pcb_paddr = (u_long)proc0.p_md.md_pcbpaddr; 691df930be7Sderaadt 692df930be7Sderaadt /* 693df930be7Sderaadt * Look at arguments passed to us and compute boothowto. 694df930be7Sderaadt */ 695417eba8cSderaadt 696417eba8cSderaadt boothowto = RB_SINGLE; 697df930be7Sderaadt #ifdef KADB 698df930be7Sderaadt boothowto |= RB_KDB; 699df930be7Sderaadt #endif 700aed035abSart for (p = bootinfo.boot_flags; p && *p != '\0'; p++) { 701417eba8cSderaadt /* 702417eba8cSderaadt * Note that we'd really like to differentiate case here, 703417eba8cSderaadt * but the Alpha AXP Architecture Reference Manual 704417eba8cSderaadt * says that we shouldn't. 705417eba8cSderaadt */ 706df930be7Sderaadt switch (*p) { 707df930be7Sderaadt case 'a': /* autoboot */ 708417eba8cSderaadt case 'A': 709df930be7Sderaadt boothowto &= ~RB_SINGLE; 710df930be7Sderaadt break; 711df930be7Sderaadt 71212f8bbedSniklas case 'b': /* Enter DDB as soon as the console is initialised */ 71312f8bbedSniklas case 'B': 71412f8bbedSniklas boothowto |= RB_KDB; 71512f8bbedSniklas break; 71612f8bbedSniklas 71750ce9ee0Sniklas case 'c': /* enter user kernel configuration */ 71850ce9ee0Sniklas case 'C': 71950ce9ee0Sniklas boothowto |= RB_CONFIG; 72050ce9ee0Sniklas break; 72150ce9ee0Sniklas 72250ce9ee0Sniklas #ifdef DEBUG 72350ce9ee0Sniklas case 'd': /* crash dump immediately after autoconfig */ 72450ce9ee0Sniklas case 'D': 72550ce9ee0Sniklas boothowto |= RB_DUMP; 72650ce9ee0Sniklas break; 72750ce9ee0Sniklas #endif 72850ce9ee0Sniklas 72950ce9ee0Sniklas case 'h': /* always halt, never reboot */ 73050ce9ee0Sniklas case 'H': 73150ce9ee0Sniklas boothowto |= RB_HALT; 732df930be7Sderaadt break; 733df930be7Sderaadt 734417eba8cSderaadt #if 0 735417eba8cSderaadt case 'm': /* mini root present in memory */ 736417eba8cSderaadt case 'M': 737417eba8cSderaadt boothowto |= RB_MINIROOT; 738417eba8cSderaadt break; 739417eba8cSderaadt #endif 74050ce9ee0Sniklas 74150ce9ee0Sniklas case 'n': /* askname */ 74250ce9ee0Sniklas case 'N': 74350ce9ee0Sniklas boothowto |= RB_ASKNAME; 74450ce9ee0Sniklas break; 745aed035abSart 746aed035abSart case 's': /* single-user (default, supported for sanity) */ 747aed035abSart case 'S': 748aed035abSart boothowto |= RB_SINGLE; 749aed035abSart break; 750aed035abSart 751aed035abSart case '-': 752aed035abSart /* 753aed035abSart * Just ignore this. It's not required, but it's 754aed035abSart * common for it to be passed regardless. 755aed035abSart */ 756aed035abSart break; 757aed035abSart 758aed035abSart default: 759aed035abSart printf("Unrecognized boot flag '%c'.\n", *p); 760aed035abSart break; 761df930be7Sderaadt } 762df930be7Sderaadt } 763df930be7Sderaadt 764aed035abSart 765df930be7Sderaadt /* 766df930be7Sderaadt * Figure out the number of cpus in the box, from RPB fields. 767df930be7Sderaadt * Really. We mean it. 768df930be7Sderaadt */ 769df930be7Sderaadt for (i = 0; i < hwrpb->rpb_pcs_cnt; i++) { 770df930be7Sderaadt struct pcs *pcsp; 771df930be7Sderaadt 772aed035abSart pcsp = LOCATE_PCS(hwrpb, i); 773df930be7Sderaadt if ((pcsp->pcs_flags & PCS_PP) != 0) 774df930be7Sderaadt ncpus++; 775df930be7Sderaadt } 776aed035abSart 777aed035abSart /* 778aed035abSart * Initialize debuggers, and break into them if appropriate. 779aed035abSart */ 780aed035abSart #ifdef DDB 781aed035abSart ddb_init(); 782aed035abSart 783aed035abSart if (boothowto & RB_KDB) 784aed035abSart Debugger(); 785aed035abSart #endif 786aed035abSart #ifdef KGDB 787aed035abSart if (boothowto & RB_KDB) 788aed035abSart kgdb_connect(0); 789aed035abSart #endif 790aed035abSart /* 791aed035abSart * Figure out our clock frequency, from RPB fields. 792aed035abSart */ 793aed035abSart hz = hwrpb->rpb_intr_freq >> 12; 794aed035abSart if (!(60 <= hz && hz <= 10240)) { 795aed035abSart hz = 1024; 796aed035abSart #ifdef DIAGNOSTIC 797aed035abSart printf("WARNING: unbelievable rpb_intr_freq: %ld (%d hz)\n", 798aed035abSart hwrpb->rpb_intr_freq, hz); 799aed035abSart #endif 800aed035abSart } 801aed035abSart } 802aed035abSart 803aed035abSart caddr_t 804aed035abSart allocsys(v) 805aed035abSart caddr_t v; 806aed035abSart { 807aed035abSart /* 808aed035abSart * Allocate space for system data structures. 809aed035abSart * The first available kernel virtual address is in "v". 810aed035abSart * As pages of kernel virtual memory are allocated, "v" is incremented. 811aed035abSart * 812aed035abSart * These data structures are allocated here instead of cpu_startup() 813aed035abSart * because physical memory is directly addressable. We don't have 814aed035abSart * to map these into virtual address space. 815aed035abSart */ 816aed035abSart #define valloc(name, type, num) \ 817aed035abSart (name) = (type *)v; v = (caddr_t)ALIGN((name)+(num)) 818aed035abSart 819aed035abSart #ifdef SYSVSHM 8205c6c8190Sespie shminfo.shmmax = shmmaxpgs; 8215c6c8190Sespie shminfo.shmall = shmmaxpgs; 8225c6c8190Sespie shminfo.shmseg = shmseg; 823aed035abSart valloc(shmsegs, struct shmid_ds, shminfo.shmmni); 824aed035abSart #endif 825aed035abSart #ifdef SYSVSEM 826aed035abSart valloc(sema, struct semid_ds, seminfo.semmni); 827aed035abSart valloc(sem, struct sem, seminfo.semmns); 828aed035abSart /* This is pretty disgusting! */ 829aed035abSart valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int)); 830aed035abSart #endif 831aed035abSart #ifdef SYSVMSG 832aed035abSart valloc(msgpool, char, msginfo.msgmax); 833aed035abSart valloc(msgmaps, struct msgmap, msginfo.msgseg); 834aed035abSart valloc(msghdrs, struct msg, msginfo.msgtql); 835aed035abSart valloc(msqids, struct msqid_ds, msginfo.msgmni); 836aed035abSart #endif 837aed035abSart 838aed035abSart /* 839aed035abSart * Determine how many buffers to allocate. 840aed035abSart * We allocate 10% of memory for buffer space. Insure a 841aed035abSart * minimum of 16 buffers. 842aed035abSart */ 843aed035abSart if (bufpages == 0) 84460535ec9Smaja bufpages = (physmem / (100/bufcachepercent)); 845aed035abSart if (nbuf == 0) { 846aed035abSart nbuf = bufpages; 847aed035abSart if (nbuf < 16) 848aed035abSart nbuf = 16; 849aed035abSart } 850aed035abSart valloc(buf, struct buf, nbuf); 851aed035abSart 852aed035abSart #undef valloc 853aed035abSart 854aed035abSart return v; 855df930be7Sderaadt } 856df930be7Sderaadt 857417eba8cSderaadt void 858df930be7Sderaadt consinit() 859df930be7Sderaadt { 860aed035abSart 861aed035abSart /* 862aed035abSart * Everything related to console initialization is done 863aed035abSart * in alpha_init(). 864aed035abSart */ 865aed035abSart #if defined(DIAGNOSTIC) && defined(_PMAP_MAY_USE_PROM_CONSOLE) 866aed035abSart printf("consinit: %susing prom console\n", 867aed035abSart pmap_uses_prom_console() ? "" : "not "); 86812f8bbedSniklas #endif 869df930be7Sderaadt } 870df930be7Sderaadt 8717ce9e539Sericj #include "pckbc.h" 8727ce9e539Sericj #include "pckbd.h" 8737ce9e539Sericj #if (NPCKBC > 0) && (NPCKBD == 0) 8747ce9e539Sericj 8757ce9e539Sericj #include <dev/ic/pckbcvar.h> 8767ce9e539Sericj 8777ce9e539Sericj /* 8788059aba4Sjason * This is called by the pckbc driver if no pckbd is configured. 8797ce9e539Sericj * On the i386, it is used to glue in the old, deprecated console 8807ce9e539Sericj * code. On the Alpha, it does nothing. 8817ce9e539Sericj */ 8827ce9e539Sericj int 8837ce9e539Sericj pckbc_machdep_cnattach(kbctag, kbcslot) 8847ce9e539Sericj pckbc_tag_t kbctag; 8857ce9e539Sericj pckbc_slot_t kbcslot; 8867ce9e539Sericj { 8877ce9e539Sericj return (ENXIO); 8887ce9e539Sericj } 8897ce9e539Sericj #endif /* NPCKBC > 0 && NPCKBD == 0 */ 8907ce9e539Sericj 891417eba8cSderaadt void 892df930be7Sderaadt cpu_startup() 893df930be7Sderaadt { 894df930be7Sderaadt register unsigned i; 895df930be7Sderaadt int base, residual; 896aed035abSart vaddr_t minaddr, maxaddr; 897aed035abSart vsize_t size; 89850ce9ee0Sniklas #if defined(DEBUG) 899df930be7Sderaadt extern int pmapdebug; 900df930be7Sderaadt int opmapdebug = pmapdebug; 901df930be7Sderaadt 902df930be7Sderaadt pmapdebug = 0; 903df930be7Sderaadt #endif 904df930be7Sderaadt 905df930be7Sderaadt /* 906df930be7Sderaadt * Good {morning,afternoon,evening,night}. 907df930be7Sderaadt */ 908df930be7Sderaadt printf(version); 909df930be7Sderaadt identifycpu(); 9103f4ce3b7Smiod printf("total memory = %ld (%ldK)\n", (long)ptoa(totalphysmem), 9113f4ce3b7Smiod (long)ptoa(totalphysmem) / 1024); 9123f4ce3b7Smiod printf("(%ld reserved for PROM, ", (long)ptoa(resvmem)); 9133f4ce3b7Smiod printf("%ld used by OpenBSD)\n", (long)ptoa(physmem)); 914aed035abSart if (unusedmem) { 9153f4ce3b7Smiod printf("WARNING: unused memory = %ld (%ldK)\n", 9163f4ce3b7Smiod (long)ptoa(unusedmem), (long)ptoa(unusedmem) / 1024); 917aed035abSart } 918aed035abSart if (unknownmem) { 9193f4ce3b7Smiod printf("WARNING: %ld (%ldK) of memory with unknown purpose\n", 9203f4ce3b7Smiod (long)ptoa(unknownmem), (long)ptoa(unknownmem) / 1024); 921aed035abSart } 922df930be7Sderaadt 923df930be7Sderaadt /* 924df930be7Sderaadt * Allocate virtual address space for file I/O buffers. 925df930be7Sderaadt * Note they are different than the array of headers, 'buf', 926df930be7Sderaadt * and usually occupy more virtual memory than physical. 927df930be7Sderaadt */ 928df930be7Sderaadt size = MAXBSIZE * nbuf; 929aed035abSart if (uvm_map(kernel_map, (vaddr_t *) &buffers, round_page(size), 930198a4b3fSart NULL, UVM_UNKNOWN_OFFSET, 0, 931aed035abSart UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, 932738a5b4dSart UVM_ADV_NORMAL, 0))) 933aed035abSart panic("startup: cannot allocate VM for buffers"); 934df930be7Sderaadt base = bufpages / nbuf; 935df930be7Sderaadt residual = bufpages % nbuf; 936df930be7Sderaadt for (i = 0; i < nbuf; i++) { 937aed035abSart vsize_t curbufsize; 938aed035abSart vaddr_t curbuf; 939aed035abSart struct vm_page *pg; 940df930be7Sderaadt 941df930be7Sderaadt /* 942aed035abSart * Each buffer has MAXBSIZE bytes of VM space allocated. Of 943aed035abSart * that MAXBSIZE space, we allocate and map (base+1) pages 944aed035abSart * for the first "residual" buffers, and then we allocate 945aed035abSart * "base" pages for the rest. 946df930be7Sderaadt */ 947aed035abSart curbuf = (vaddr_t) buffers + (i * MAXBSIZE); 948aed035abSart curbufsize = NBPG * ((i < residual) ? (base+1) : base); 949aed035abSart 950aed035abSart while (curbufsize) { 951aed035abSart pg = uvm_pagealloc(NULL, 0, NULL, 0); 952aed035abSart if (pg == NULL) 953aed035abSart panic("cpu_startup: not enough memory for " 954aed035abSart "buffer cache"); 955aed035abSart pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg), 956aed035abSart VM_PROT_READ|VM_PROT_WRITE); 957aed035abSart curbuf += PAGE_SIZE; 958aed035abSart curbufsize -= PAGE_SIZE; 959aed035abSart } 9600e5798cfSart pmap_update(pmap_kernel()); 961df930be7Sderaadt } 962df930be7Sderaadt /* 963df930be7Sderaadt * Allocate a submap for exec arguments. This map effectively 964df930be7Sderaadt * limits the number of processes exec'ing at any time. 965df930be7Sderaadt */ 966aed035abSart exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 967aed035abSart 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); 968df930be7Sderaadt 969df930be7Sderaadt /* 970df930be7Sderaadt * Allocate a submap for physio 971df930be7Sderaadt */ 972aed035abSart phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, 973aed035abSart VM_PHYS_SIZE, 0, FALSE, NULL); 974df930be7Sderaadt 97550ce9ee0Sniklas #if defined(DEBUG) 976df930be7Sderaadt pmapdebug = opmapdebug; 977df930be7Sderaadt #endif 9783f4ce3b7Smiod printf("avail memory = %ld (%ldK)\n", (long)ptoa(uvmexp.free), 9793f4ce3b7Smiod (long)ptoa(uvmexp.free) / 1024); 980aed035abSart #if 0 981aed035abSart { 982aed035abSart extern u_long pmap_pages_stolen; 983aed035abSart 984aed035abSart printf("stolen memory for VM structures = %d\n", pmap_pages_stolen * PAGE_SIZE); 985aed035abSart } 986aed035abSart #endif 9873f4ce3b7Smiod printf("using %ld buffers containing %ld bytes (%ldK) of memory\n", 9883f4ce3b7Smiod (long)nbuf, (long)bufpages * NBPG, (long)bufpages * (NBPG / 1024)); 989df930be7Sderaadt 990df930be7Sderaadt /* 991df930be7Sderaadt * Set up buffers, so they can be used to read disk labels. 992df930be7Sderaadt */ 993df930be7Sderaadt bufinit(); 994df930be7Sderaadt 995df930be7Sderaadt /* 996df930be7Sderaadt * Configure the system. 997df930be7Sderaadt */ 99841033391Sderaadt if (boothowto & RB_CONFIG) { 99941033391Sderaadt #ifdef BOOT_CONFIG 100041033391Sderaadt user_config(); 100141033391Sderaadt #else 100241033391Sderaadt printf("kernel does not support -c; continuing..\n"); 100341033391Sderaadt #endif 100441033391Sderaadt } 100550ce9ee0Sniklas 100650ce9ee0Sniklas /* 1007aed035abSart * Set up the HWPCB so that it's safe to configure secondary 1008aed035abSart * CPUs. 100950ce9ee0Sniklas */ 1010aed035abSart hwrpb_primary_init(); 1011aed035abSart } 1012aed035abSart 1013aed035abSart /* 1014aed035abSart * Retrieve the platform name from the DSR. 1015aed035abSart */ 1016aed035abSart const char * 1017aed035abSart alpha_dsr_sysname() 1018aed035abSart { 1019aed035abSart struct dsrdb *dsr; 1020aed035abSart const char *sysname; 1021aed035abSart 1022aed035abSart /* 1023aed035abSart * DSR does not exist on early HWRPB versions. 1024aed035abSart */ 1025aed035abSart if (hwrpb->rpb_version < HWRPB_DSRDB_MINVERS) 1026aed035abSart return (NULL); 1027aed035abSart 1028aed035abSart dsr = (struct dsrdb *)(((caddr_t)hwrpb) + hwrpb->rpb_dsrdb_off); 1029aed035abSart sysname = (const char *)((caddr_t)dsr + (dsr->dsr_sysname_off + 1030aed035abSart sizeof(u_int64_t))); 1031aed035abSart return (sysname); 1032aed035abSart } 1033aed035abSart 1034aed035abSart /* 1035aed035abSart * Lookup the system specified system variation in the provided table, 1036aed035abSart * returning the model string on match. 1037aed035abSart */ 1038aed035abSart const char * 1039aed035abSart alpha_variation_name(variation, avtp) 1040aed035abSart u_int64_t variation; 1041aed035abSart const struct alpha_variation_table *avtp; 1042aed035abSart { 1043aed035abSart int i; 1044aed035abSart 1045aed035abSart for (i = 0; avtp[i].avt_model != NULL; i++) 1046aed035abSart if (avtp[i].avt_variation == variation) 1047aed035abSart return (avtp[i].avt_model); 1048aed035abSart return (NULL); 1049aed035abSart } 1050aed035abSart 1051aed035abSart /* 1052aed035abSart * Generate a default platform name based for unknown system variations. 1053aed035abSart */ 1054aed035abSart const char * 1055aed035abSart alpha_unknown_sysname() 1056aed035abSart { 1057aed035abSart static char s[128]; /* safe size */ 1058aed035abSart 1059aed035abSart sprintf(s, "%s family, unknown model variation 0x%lx", 1060aed035abSart platform.family, hwrpb->rpb_variation & SV_ST_MASK); 1061aed035abSart return ((const char *)s); 1062df930be7Sderaadt } 1063df930be7Sderaadt 106450ce9ee0Sniklas void 1065df930be7Sderaadt identifycpu() 1066df930be7Sderaadt { 1067aed035abSart char *s; 1068df930be7Sderaadt 1069df930be7Sderaadt /* 1070df930be7Sderaadt * print out CPU identification information. 1071df930be7Sderaadt */ 1072aed035abSart printf("%s", cpu_model); 1073aed035abSart for(s = cpu_model; *s; ++s) 1074aed035abSart if(strncasecmp(s, "MHz", 3) == 0) 1075aed035abSart goto skipMHz; 1076aed035abSart printf(", %ldMHz", hwrpb->rpb_cc_freq / 1000000); 1077aed035abSart skipMHz: 1078aed035abSart printf("\n"); 107950ce9ee0Sniklas printf("%ld byte page size, %d processor%s.\n", 1080df930be7Sderaadt hwrpb->rpb_page_size, ncpus, ncpus == 1 ? "" : "s"); 1081df930be7Sderaadt #if 0 1082df930be7Sderaadt /* this isn't defined for any systems that we run on? */ 1083df930be7Sderaadt printf("serial number 0x%lx 0x%lx\n", 1084df930be7Sderaadt ((long *)hwrpb->rpb_ssn)[0], ((long *)hwrpb->rpb_ssn)[1]); 1085df930be7Sderaadt 1086df930be7Sderaadt /* and these aren't particularly useful! */ 1087df930be7Sderaadt printf("variation: 0x%lx, revision 0x%lx\n", 1088df930be7Sderaadt hwrpb->rpb_variation, *(long *)hwrpb->rpb_revision); 1089df930be7Sderaadt #endif 1090df930be7Sderaadt } 1091df930be7Sderaadt 1092df930be7Sderaadt int waittime = -1; 1093df930be7Sderaadt struct pcb dumppcb; 1094df930be7Sderaadt 1095417eba8cSderaadt void 1096aed035abSart boot(howto) 1097df930be7Sderaadt int howto; 1098df930be7Sderaadt { 1099aed035abSart #if defined(MULTIPROCESSOR) 1100aed035abSart #if 0 /* XXX See below. */ 1101aed035abSart u_long cpu_id; 1102aed035abSart #endif 1103aed035abSart #endif 1104aed035abSart 1105aed035abSart #if defined(MULTIPROCESSOR) 1106aed035abSart /* We must be running on the primary CPU. */ 1107aed035abSart if (alpha_pal_whami() != hwrpb->rpb_primary_cpu_id) 1108aed035abSart panic("cpu_reboot: not on primary CPU!"); 1109aed035abSart #endif 1110aed035abSart 1111df930be7Sderaadt /* If system is cold, just halt. */ 1112df930be7Sderaadt if (cold) { 1113df930be7Sderaadt howto |= RB_HALT; 1114df930be7Sderaadt goto haltsys; 1115df930be7Sderaadt } 1116df930be7Sderaadt 111750ce9ee0Sniklas /* If "always halt" was specified as a boot flag, obey. */ 111850ce9ee0Sniklas if ((boothowto & RB_HALT) != 0) 111950ce9ee0Sniklas howto |= RB_HALT; 112050ce9ee0Sniklas 1121df930be7Sderaadt boothowto = howto; 1122df930be7Sderaadt if ((howto & RB_NOSYNC) == 0 && waittime < 0) { 1123df930be7Sderaadt waittime = 0; 1124df930be7Sderaadt vfs_shutdown(); 1125df930be7Sderaadt /* 1126df930be7Sderaadt * If we've been adjusting the clock, the todr 1127aed035abSart * will be out of synch; adjust it now. 1128df930be7Sderaadt */ 1129df930be7Sderaadt resettodr(); 1130df930be7Sderaadt } 1131df930be7Sderaadt 1132df930be7Sderaadt /* Disable interrupts. */ 1133df930be7Sderaadt splhigh(); 1134df930be7Sderaadt 1135df930be7Sderaadt /* If rebooting and a dump is requested do it. */ 113650ce9ee0Sniklas if (howto & RB_DUMP) 1137df930be7Sderaadt dumpsys(); 1138df930be7Sderaadt 113934fbf6deSderaadt haltsys: 114034fbf6deSderaadt 1141df930be7Sderaadt /* run any shutdown hooks */ 1142df930be7Sderaadt doshutdownhooks(); 1143df930be7Sderaadt 1144aed035abSart #if defined(MULTIPROCESSOR) 1145aed035abSart #if 0 /* XXX doesn't work when called from here?! */ 1146aed035abSart /* Kill off any secondary CPUs. */ 1147aed035abSart for (cpu_id = 0; cpu_id < hwrpb->rpb_pcs_cnt; cpu_id++) { 1148aed035abSart if (cpu_id == hwrpb->rpb_primary_cpu_id || 1149aed035abSart cpu_info[cpu_id].ci_softc == NULL) 1150aed035abSart continue; 1151aed035abSart cpu_halt_secondary(cpu_id); 1152aed035abSart } 1153aed035abSart #endif 1154aed035abSart #endif 1155aed035abSart 1156df930be7Sderaadt #ifdef BOOTKEY 1157df930be7Sderaadt printf("hit any key to %s...\n", howto & RB_HALT ? "halt" : "reboot"); 1158aed035abSart cnpollc(1); /* for proper keyboard command handling */ 1159df930be7Sderaadt cngetc(); 1160aed035abSart cnpollc(0); 1161df930be7Sderaadt printf("\n"); 1162df930be7Sderaadt #endif 1163df930be7Sderaadt 1164aed035abSart /* Finally, powerdown/halt/reboot the system. */ 1165aed035abSart if ((howto & RB_POWERDOWN) == RB_POWERDOWN && 1166aed035abSart platform.powerdown != NULL) { 1167aed035abSart (*platform.powerdown)(); 1168aed035abSart printf("WARNING: powerdown failed!\n"); 1169aed035abSart } 1170df930be7Sderaadt printf("%s\n\n", howto & RB_HALT ? "halted." : "rebooting..."); 1171df930be7Sderaadt prom_halt(howto & RB_HALT); 1172df930be7Sderaadt /*NOTREACHED*/ 1173df930be7Sderaadt } 1174df930be7Sderaadt 1175df930be7Sderaadt /* 1176df930be7Sderaadt * These variables are needed by /sbin/savecore 1177df930be7Sderaadt */ 1178df930be7Sderaadt u_long dumpmag = 0x8fca0101; /* magic number */ 1179df930be7Sderaadt int dumpsize = 0; /* pages */ 1180df930be7Sderaadt long dumplo = 0; /* blocks */ 1181df930be7Sderaadt 1182df930be7Sderaadt /* 118350ce9ee0Sniklas * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers. 118450ce9ee0Sniklas */ 118550ce9ee0Sniklas int 118650ce9ee0Sniklas cpu_dumpsize() 118750ce9ee0Sniklas { 118850ce9ee0Sniklas int size; 118950ce9ee0Sniklas 1190aed035abSart size = ALIGN(sizeof(kcore_seg_t)) + ALIGN(sizeof(cpu_kcore_hdr_t)) + 1191aed035abSart ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t)); 119250ce9ee0Sniklas if (roundup(size, dbtob(1)) != dbtob(1)) 119350ce9ee0Sniklas return -1; 119450ce9ee0Sniklas 119550ce9ee0Sniklas return (1); 119650ce9ee0Sniklas } 119750ce9ee0Sniklas 119850ce9ee0Sniklas /* 1199aed035abSart * cpu_dump_mempagecnt: calculate size of RAM (in pages) to be dumped. 1200aed035abSart */ 1201aed035abSart u_long 1202aed035abSart cpu_dump_mempagecnt() 1203aed035abSart { 1204aed035abSart u_long i, n; 1205aed035abSart 1206aed035abSart n = 0; 1207aed035abSart for (i = 0; i < mem_cluster_cnt; i++) 1208aed035abSart n += atop(mem_clusters[i].size); 1209aed035abSart return (n); 1210aed035abSart } 1211aed035abSart 1212aed035abSart /* 121350ce9ee0Sniklas * cpu_dump: dump machine-dependent kernel core dump headers. 121450ce9ee0Sniklas */ 121550ce9ee0Sniklas int 121650ce9ee0Sniklas cpu_dump() 121750ce9ee0Sniklas { 1218c4071fd1Smillert int (*dump)(dev_t, daddr_t, caddr_t, size_t); 1219aed035abSart char buf[dbtob(1)]; 122050ce9ee0Sniklas kcore_seg_t *segp; 122150ce9ee0Sniklas cpu_kcore_hdr_t *cpuhdrp; 1222aed035abSart phys_ram_seg_t *memsegp; 1223aed035abSart int i; 122450ce9ee0Sniklas 122550ce9ee0Sniklas dump = bdevsw[major(dumpdev)].d_dump; 122650ce9ee0Sniklas 1227aed035abSart bzero(buf, sizeof buf); 122850ce9ee0Sniklas segp = (kcore_seg_t *)buf; 1229aed035abSart cpuhdrp = (cpu_kcore_hdr_t *)&buf[ALIGN(sizeof(*segp))]; 1230aed035abSart memsegp = (phys_ram_seg_t *)&buf[ALIGN(sizeof(*segp)) + 1231aed035abSart ALIGN(sizeof(*cpuhdrp))]; 123250ce9ee0Sniklas 123350ce9ee0Sniklas /* 123450ce9ee0Sniklas * Generate a segment header. 123550ce9ee0Sniklas */ 123650ce9ee0Sniklas CORE_SETMAGIC(*segp, KCORE_MAGIC, MID_MACHINE, CORE_CPU); 123750ce9ee0Sniklas segp->c_size = dbtob(1) - ALIGN(sizeof(*segp)); 123850ce9ee0Sniklas 123950ce9ee0Sniklas /* 1240aed035abSart * Add the machine-dependent header info. 124150ce9ee0Sniklas */ 1242aed035abSart cpuhdrp->lev1map_pa = ALPHA_K0SEG_TO_PHYS((vaddr_t)kernel_lev1map); 124350ce9ee0Sniklas cpuhdrp->page_size = PAGE_SIZE; 1244aed035abSart cpuhdrp->nmemsegs = mem_cluster_cnt; 1245aed035abSart 1246aed035abSart /* 1247aed035abSart * Fill in the memory segment descriptors. 1248aed035abSart */ 1249aed035abSart for (i = 0; i < mem_cluster_cnt; i++) { 1250aed035abSart memsegp[i].start = mem_clusters[i].start; 1251aed035abSart memsegp[i].size = mem_clusters[i].size & ~PAGE_MASK; 1252aed035abSart } 125350ce9ee0Sniklas 125450ce9ee0Sniklas return (dump(dumpdev, dumplo, (caddr_t)buf, dbtob(1))); 125550ce9ee0Sniklas } 125650ce9ee0Sniklas 125750ce9ee0Sniklas /* 1258aed035abSart * This is called by main to set dumplo and dumpsize. 1259aed035abSart * Dumps always skip the first NBPG of disk space 1260df930be7Sderaadt * in case there might be a disk label stored there. 1261df930be7Sderaadt * If there is extra space, put dump at the end to 1262df930be7Sderaadt * reduce the chance that swapping trashes it. 1263df930be7Sderaadt */ 1264df930be7Sderaadt void 1265df930be7Sderaadt dumpconf() 1266df930be7Sderaadt { 126750ce9ee0Sniklas int nblks, dumpblks; /* size of dump area */ 1268df930be7Sderaadt int maj; 1269df930be7Sderaadt 1270df930be7Sderaadt if (dumpdev == NODEV) 127150ce9ee0Sniklas goto bad; 1272df930be7Sderaadt maj = major(dumpdev); 1273df930be7Sderaadt if (maj < 0 || maj >= nblkdev) 1274df930be7Sderaadt panic("dumpconf: bad dumpdev=0x%x", dumpdev); 1275df930be7Sderaadt if (bdevsw[maj].d_psize == NULL) 127650ce9ee0Sniklas goto bad; 1277df930be7Sderaadt nblks = (*bdevsw[maj].d_psize)(dumpdev); 1278df930be7Sderaadt if (nblks <= ctod(1)) 127950ce9ee0Sniklas goto bad; 128050ce9ee0Sniklas 128150ce9ee0Sniklas dumpblks = cpu_dumpsize(); 128250ce9ee0Sniklas if (dumpblks < 0) 128350ce9ee0Sniklas goto bad; 1284aed035abSart dumpblks += ctod(cpu_dump_mempagecnt()); 128550ce9ee0Sniklas 128650ce9ee0Sniklas /* If dump won't fit (incl. room for possible label), punt. */ 128750ce9ee0Sniklas if (dumpblks > (nblks - ctod(1))) 128850ce9ee0Sniklas goto bad; 128950ce9ee0Sniklas 129050ce9ee0Sniklas /* Put dump at end of partition */ 129150ce9ee0Sniklas dumplo = nblks - dumpblks; 129250ce9ee0Sniklas 129350ce9ee0Sniklas /* dumpsize is in page units, and doesn't include headers. */ 1294aed035abSart dumpsize = cpu_dump_mempagecnt(); 1295df930be7Sderaadt return; 1296df930be7Sderaadt 129750ce9ee0Sniklas bad: 129850ce9ee0Sniklas dumpsize = 0; 129950ce9ee0Sniklas return; 1300df930be7Sderaadt } 1301df930be7Sderaadt 1302df930be7Sderaadt /* 130350ce9ee0Sniklas * Dump the kernel's image to the swap partition. 1304df930be7Sderaadt */ 130550ce9ee0Sniklas #define BYTES_PER_DUMP NBPG 130650ce9ee0Sniklas 1307df930be7Sderaadt void 1308df930be7Sderaadt dumpsys() 1309df930be7Sderaadt { 1310aed035abSart u_long totalbytesleft, bytes, i, n, memcl; 1311aed035abSart u_long maddr; 1312aed035abSart int psize; 131350ce9ee0Sniklas daddr_t blkno; 1314c4071fd1Smillert int (*dump)(dev_t, daddr_t, caddr_t, size_t); 131550ce9ee0Sniklas int error; 1316067cbd75Sderaadt extern int msgbufmapped; 1317df930be7Sderaadt 131850ce9ee0Sniklas /* Save registers. */ 131950ce9ee0Sniklas savectx(&dumppcb); 132050ce9ee0Sniklas 132150ce9ee0Sniklas msgbufmapped = 0; /* don't record dump msgs in msgbuf */ 1322df930be7Sderaadt if (dumpdev == NODEV) 1323df930be7Sderaadt return; 132450ce9ee0Sniklas 132550ce9ee0Sniklas /* 132650ce9ee0Sniklas * For dumps during autoconfiguration, 132750ce9ee0Sniklas * if dump device has already configured... 132850ce9ee0Sniklas */ 1329df930be7Sderaadt if (dumpsize == 0) 133050ce9ee0Sniklas dumpconf(); 133150ce9ee0Sniklas if (dumplo <= 0) { 1332aed035abSart printf("\ndump to dev %u,%u not possible\n", major(dumpdev), 1333aed035abSart minor(dumpdev)); 1334df930be7Sderaadt return; 1335df930be7Sderaadt } 1336aed035abSart printf("\ndumping to dev %u,%u offset %ld\n", major(dumpdev), 1337aed035abSart minor(dumpdev), dumplo); 1338df930be7Sderaadt 133950ce9ee0Sniklas psize = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); 1340df930be7Sderaadt printf("dump "); 134150ce9ee0Sniklas if (psize == -1) { 134250ce9ee0Sniklas printf("area unavailable\n"); 134350ce9ee0Sniklas return; 134450ce9ee0Sniklas } 134550ce9ee0Sniklas 134650ce9ee0Sniklas /* XXX should purge all outstanding keystrokes. */ 134750ce9ee0Sniklas 134850ce9ee0Sniklas if ((error = cpu_dump()) != 0) 134950ce9ee0Sniklas goto err; 135050ce9ee0Sniklas 1351aed035abSart totalbytesleft = ptoa(cpu_dump_mempagecnt()); 135250ce9ee0Sniklas blkno = dumplo + cpu_dumpsize(); 135350ce9ee0Sniklas dump = bdevsw[major(dumpdev)].d_dump; 135450ce9ee0Sniklas error = 0; 1355aed035abSart 1356aed035abSart for (memcl = 0; memcl < mem_cluster_cnt; memcl++) { 1357aed035abSart maddr = mem_clusters[memcl].start; 1358aed035abSart bytes = mem_clusters[memcl].size & ~PAGE_MASK; 1359aed035abSart 1360aed035abSart for (i = 0; i < bytes; i += n, totalbytesleft -= n) { 136150ce9ee0Sniklas 136250ce9ee0Sniklas /* Print out how many MBs we to go. */ 1363aed035abSart if ((totalbytesleft % (1024*1024)) == 0) 1364aed035abSart printf("%ld ", totalbytesleft / (1024 * 1024)); 136550ce9ee0Sniklas 136650ce9ee0Sniklas /* Limit size for next transfer. */ 1367aed035abSart n = bytes - i; 136850ce9ee0Sniklas if (n > BYTES_PER_DUMP) 136950ce9ee0Sniklas n = BYTES_PER_DUMP; 137050ce9ee0Sniklas 137150ce9ee0Sniklas error = (*dump)(dumpdev, blkno, 137250ce9ee0Sniklas (caddr_t)ALPHA_PHYS_TO_K0SEG(maddr), n); 137350ce9ee0Sniklas if (error) 1374aed035abSart goto err; 137550ce9ee0Sniklas maddr += n; 137650ce9ee0Sniklas blkno += btodb(n); /* XXX? */ 137750ce9ee0Sniklas 137850ce9ee0Sniklas /* XXX should look for keystrokes, to cancel. */ 137950ce9ee0Sniklas } 1380aed035abSart } 138150ce9ee0Sniklas 138250ce9ee0Sniklas err: 138350ce9ee0Sniklas switch (error) { 1384df930be7Sderaadt 1385df930be7Sderaadt case ENXIO: 1386df930be7Sderaadt printf("device bad\n"); 1387df930be7Sderaadt break; 1388df930be7Sderaadt 1389df930be7Sderaadt case EFAULT: 1390df930be7Sderaadt printf("device not ready\n"); 1391df930be7Sderaadt break; 1392df930be7Sderaadt 1393df930be7Sderaadt case EINVAL: 1394df930be7Sderaadt printf("area improper\n"); 1395df930be7Sderaadt break; 1396df930be7Sderaadt 1397df930be7Sderaadt case EIO: 1398df930be7Sderaadt printf("i/o error\n"); 1399df930be7Sderaadt break; 1400df930be7Sderaadt 1401df930be7Sderaadt case EINTR: 1402df930be7Sderaadt printf("aborted from console\n"); 1403df930be7Sderaadt break; 1404df930be7Sderaadt 140550ce9ee0Sniklas case 0: 1406df930be7Sderaadt printf("succeeded\n"); 1407df930be7Sderaadt break; 140850ce9ee0Sniklas 140950ce9ee0Sniklas default: 141050ce9ee0Sniklas printf("error %d\n", error); 141150ce9ee0Sniklas break; 1412df930be7Sderaadt } 1413df930be7Sderaadt printf("\n\n"); 1414df930be7Sderaadt delay(1000); 1415df930be7Sderaadt } 1416df930be7Sderaadt 1417df930be7Sderaadt void 1418df930be7Sderaadt frametoreg(framep, regp) 1419df930be7Sderaadt struct trapframe *framep; 1420df930be7Sderaadt struct reg *regp; 1421df930be7Sderaadt { 1422df930be7Sderaadt 1423df930be7Sderaadt regp->r_regs[R_V0] = framep->tf_regs[FRAME_V0]; 1424df930be7Sderaadt regp->r_regs[R_T0] = framep->tf_regs[FRAME_T0]; 1425df930be7Sderaadt regp->r_regs[R_T1] = framep->tf_regs[FRAME_T1]; 1426df930be7Sderaadt regp->r_regs[R_T2] = framep->tf_regs[FRAME_T2]; 1427df930be7Sderaadt regp->r_regs[R_T3] = framep->tf_regs[FRAME_T3]; 1428df930be7Sderaadt regp->r_regs[R_T4] = framep->tf_regs[FRAME_T4]; 1429df930be7Sderaadt regp->r_regs[R_T5] = framep->tf_regs[FRAME_T5]; 1430df930be7Sderaadt regp->r_regs[R_T6] = framep->tf_regs[FRAME_T6]; 1431df930be7Sderaadt regp->r_regs[R_T7] = framep->tf_regs[FRAME_T7]; 1432df930be7Sderaadt regp->r_regs[R_S0] = framep->tf_regs[FRAME_S0]; 1433df930be7Sderaadt regp->r_regs[R_S1] = framep->tf_regs[FRAME_S1]; 1434df930be7Sderaadt regp->r_regs[R_S2] = framep->tf_regs[FRAME_S2]; 1435df930be7Sderaadt regp->r_regs[R_S3] = framep->tf_regs[FRAME_S3]; 1436df930be7Sderaadt regp->r_regs[R_S4] = framep->tf_regs[FRAME_S4]; 1437df930be7Sderaadt regp->r_regs[R_S5] = framep->tf_regs[FRAME_S5]; 1438df930be7Sderaadt regp->r_regs[R_S6] = framep->tf_regs[FRAME_S6]; 143950ce9ee0Sniklas regp->r_regs[R_A0] = framep->tf_regs[FRAME_A0]; 144050ce9ee0Sniklas regp->r_regs[R_A1] = framep->tf_regs[FRAME_A1]; 144150ce9ee0Sniklas regp->r_regs[R_A2] = framep->tf_regs[FRAME_A2]; 1442df930be7Sderaadt regp->r_regs[R_A3] = framep->tf_regs[FRAME_A3]; 1443df930be7Sderaadt regp->r_regs[R_A4] = framep->tf_regs[FRAME_A4]; 1444df930be7Sderaadt regp->r_regs[R_A5] = framep->tf_regs[FRAME_A5]; 1445df930be7Sderaadt regp->r_regs[R_T8] = framep->tf_regs[FRAME_T8]; 1446df930be7Sderaadt regp->r_regs[R_T9] = framep->tf_regs[FRAME_T9]; 1447df930be7Sderaadt regp->r_regs[R_T10] = framep->tf_regs[FRAME_T10]; 1448df930be7Sderaadt regp->r_regs[R_T11] = framep->tf_regs[FRAME_T11]; 1449df930be7Sderaadt regp->r_regs[R_RA] = framep->tf_regs[FRAME_RA]; 1450df930be7Sderaadt regp->r_regs[R_T12] = framep->tf_regs[FRAME_T12]; 1451df930be7Sderaadt regp->r_regs[R_AT] = framep->tf_regs[FRAME_AT]; 145250ce9ee0Sniklas regp->r_regs[R_GP] = framep->tf_regs[FRAME_GP]; 145350ce9ee0Sniklas /* regp->r_regs[R_SP] = framep->tf_regs[FRAME_SP]; XXX */ 1454df930be7Sderaadt regp->r_regs[R_ZERO] = 0; 1455df930be7Sderaadt } 1456df930be7Sderaadt 1457df930be7Sderaadt void 1458df930be7Sderaadt regtoframe(regp, framep) 1459df930be7Sderaadt struct reg *regp; 1460df930be7Sderaadt struct trapframe *framep; 1461df930be7Sderaadt { 1462df930be7Sderaadt 1463df930be7Sderaadt framep->tf_regs[FRAME_V0] = regp->r_regs[R_V0]; 1464df930be7Sderaadt framep->tf_regs[FRAME_T0] = regp->r_regs[R_T0]; 1465df930be7Sderaadt framep->tf_regs[FRAME_T1] = regp->r_regs[R_T1]; 1466df930be7Sderaadt framep->tf_regs[FRAME_T2] = regp->r_regs[R_T2]; 1467df930be7Sderaadt framep->tf_regs[FRAME_T3] = regp->r_regs[R_T3]; 1468df930be7Sderaadt framep->tf_regs[FRAME_T4] = regp->r_regs[R_T4]; 1469df930be7Sderaadt framep->tf_regs[FRAME_T5] = regp->r_regs[R_T5]; 1470df930be7Sderaadt framep->tf_regs[FRAME_T6] = regp->r_regs[R_T6]; 1471df930be7Sderaadt framep->tf_regs[FRAME_T7] = regp->r_regs[R_T7]; 1472df930be7Sderaadt framep->tf_regs[FRAME_S0] = regp->r_regs[R_S0]; 1473df930be7Sderaadt framep->tf_regs[FRAME_S1] = regp->r_regs[R_S1]; 1474df930be7Sderaadt framep->tf_regs[FRAME_S2] = regp->r_regs[R_S2]; 1475df930be7Sderaadt framep->tf_regs[FRAME_S3] = regp->r_regs[R_S3]; 1476df930be7Sderaadt framep->tf_regs[FRAME_S4] = regp->r_regs[R_S4]; 1477df930be7Sderaadt framep->tf_regs[FRAME_S5] = regp->r_regs[R_S5]; 1478df930be7Sderaadt framep->tf_regs[FRAME_S6] = regp->r_regs[R_S6]; 147950ce9ee0Sniklas framep->tf_regs[FRAME_A0] = regp->r_regs[R_A0]; 148050ce9ee0Sniklas framep->tf_regs[FRAME_A1] = regp->r_regs[R_A1]; 148150ce9ee0Sniklas framep->tf_regs[FRAME_A2] = regp->r_regs[R_A2]; 1482df930be7Sderaadt framep->tf_regs[FRAME_A3] = regp->r_regs[R_A3]; 1483df930be7Sderaadt framep->tf_regs[FRAME_A4] = regp->r_regs[R_A4]; 1484df930be7Sderaadt framep->tf_regs[FRAME_A5] = regp->r_regs[R_A5]; 1485df930be7Sderaadt framep->tf_regs[FRAME_T8] = regp->r_regs[R_T8]; 1486df930be7Sderaadt framep->tf_regs[FRAME_T9] = regp->r_regs[R_T9]; 1487df930be7Sderaadt framep->tf_regs[FRAME_T10] = regp->r_regs[R_T10]; 1488df930be7Sderaadt framep->tf_regs[FRAME_T11] = regp->r_regs[R_T11]; 1489df930be7Sderaadt framep->tf_regs[FRAME_RA] = regp->r_regs[R_RA]; 1490df930be7Sderaadt framep->tf_regs[FRAME_T12] = regp->r_regs[R_T12]; 1491df930be7Sderaadt framep->tf_regs[FRAME_AT] = regp->r_regs[R_AT]; 149250ce9ee0Sniklas framep->tf_regs[FRAME_GP] = regp->r_regs[R_GP]; 149350ce9ee0Sniklas /* framep->tf_regs[FRAME_SP] = regp->r_regs[R_SP]; XXX */ 1494df930be7Sderaadt /* ??? = regp->r_regs[R_ZERO]; */ 1495df930be7Sderaadt } 1496df930be7Sderaadt 1497df930be7Sderaadt void 1498df930be7Sderaadt printregs(regp) 1499df930be7Sderaadt struct reg *regp; 1500df930be7Sderaadt { 1501df930be7Sderaadt int i; 1502df930be7Sderaadt 1503df930be7Sderaadt for (i = 0; i < 32; i++) 1504df930be7Sderaadt printf("R%d:\t0x%016lx%s", i, regp->r_regs[i], 1505df930be7Sderaadt i & 1 ? "\n" : "\t"); 1506df930be7Sderaadt } 1507df930be7Sderaadt 1508df930be7Sderaadt void 1509df930be7Sderaadt regdump(framep) 1510df930be7Sderaadt struct trapframe *framep; 1511df930be7Sderaadt { 1512df930be7Sderaadt struct reg reg; 1513df930be7Sderaadt 1514df930be7Sderaadt frametoreg(framep, ®); 151550ce9ee0Sniklas reg.r_regs[R_SP] = alpha_pal_rdusp(); 151650ce9ee0Sniklas 1517df930be7Sderaadt printf("REGISTERS:\n"); 1518df930be7Sderaadt printregs(®); 1519df930be7Sderaadt } 1520df930be7Sderaadt 1521df930be7Sderaadt #ifdef DEBUG 1522df930be7Sderaadt int sigdebug = 0; 1523df930be7Sderaadt int sigpid = 0; 1524df930be7Sderaadt #define SDB_FOLLOW 0x01 1525df930be7Sderaadt #define SDB_KSTACK 0x02 1526df930be7Sderaadt #endif 1527df930be7Sderaadt 1528df930be7Sderaadt /* 1529df930be7Sderaadt * Send an interrupt to process. 1530df930be7Sderaadt */ 1531df930be7Sderaadt void 15325e1760a6Sderaadt sendsig(catcher, sig, mask, code, type, val) 1533df930be7Sderaadt sig_t catcher; 1534df930be7Sderaadt int sig, mask; 1535df930be7Sderaadt u_long code; 15365e1760a6Sderaadt int type; 15375e1760a6Sderaadt union sigval val; 1538df930be7Sderaadt { 1539df930be7Sderaadt struct proc *p = curproc; 1540df930be7Sderaadt struct sigcontext *scp, ksc; 1541df930be7Sderaadt struct trapframe *frame; 1542df930be7Sderaadt struct sigacts *psp = p->p_sigacts; 15432bf9c155Sderaadt int oonstack, fsize, rndfsize, kscsize; 15442bf9c155Sderaadt siginfo_t *sip, ksi; 1545df930be7Sderaadt 1546df930be7Sderaadt frame = p->p_md.md_tf; 1547df930be7Sderaadt oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; 1548df930be7Sderaadt fsize = sizeof ksc; 1549df930be7Sderaadt rndfsize = ((fsize + 15) / 16) * 16; 15502bf9c155Sderaadt kscsize = rndfsize; 15512bf9c155Sderaadt if (psp->ps_siginfo & sigmask(sig)) { 15522bf9c155Sderaadt fsize += sizeof ksi; 15532bf9c155Sderaadt rndfsize = ((fsize + 15) / 16) * 16; 15542bf9c155Sderaadt } 155574652a67Sniklas 1556df930be7Sderaadt /* 1557df930be7Sderaadt * Allocate and validate space for the signal handler 1558df930be7Sderaadt * context. Note that if the stack is in P0 space, the 1559aed035abSart * call to uvm_grow() is a nop, and the useracc() check 1560df930be7Sderaadt * will fail if the process has not already allocated 1561df930be7Sderaadt * the space with a `brk'. 1562df930be7Sderaadt */ 1563df930be7Sderaadt if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && 1564df930be7Sderaadt (psp->ps_sigonstack & sigmask(sig))) { 15658bc2093aSderaadt scp = (struct sigcontext *)(psp->ps_sigstk.ss_sp + 1566df930be7Sderaadt psp->ps_sigstk.ss_size - rndfsize); 1567df930be7Sderaadt psp->ps_sigstk.ss_flags |= SS_ONSTACK; 1568df930be7Sderaadt } else 156950ce9ee0Sniklas scp = (struct sigcontext *)(alpha_pal_rdusp() - rndfsize); 1570df930be7Sderaadt if ((u_long)scp <= USRSTACK - ctob(p->p_vmspace->vm_ssize)) 1571aed035abSart (void)uvm_grow(p, (u_long)scp); 1572df930be7Sderaadt #ifdef DEBUG 1573df930be7Sderaadt if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 157450ce9ee0Sniklas printf("sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, 1575df930be7Sderaadt sig, &oonstack, scp); 1576df930be7Sderaadt #endif 1577aed035abSart if (uvm_useracc((caddr_t)scp, fsize, B_WRITE) == 0) { 1578df930be7Sderaadt #ifdef DEBUG 1579df930be7Sderaadt if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 1580aed035abSart printf("sendsig(%d): uvm_useracc failed on sig %d\n", 1581df930be7Sderaadt p->p_pid, sig); 1582df930be7Sderaadt #endif 1583df930be7Sderaadt /* 1584df930be7Sderaadt * Process has trashed its stack; give it an illegal 1585df930be7Sderaadt * instruction to halt it in its tracks. 1586df930be7Sderaadt */ 1587df930be7Sderaadt SIGACTION(p, SIGILL) = SIG_DFL; 1588df930be7Sderaadt sig = sigmask(SIGILL); 1589df930be7Sderaadt p->p_sigignore &= ~sig; 1590df930be7Sderaadt p->p_sigcatch &= ~sig; 1591df930be7Sderaadt p->p_sigmask &= ~sig; 1592df930be7Sderaadt psignal(p, SIGILL); 1593df930be7Sderaadt return; 1594df930be7Sderaadt } 1595df930be7Sderaadt 1596df930be7Sderaadt /* 1597df930be7Sderaadt * Build the signal context to be used by sigreturn. 1598df930be7Sderaadt */ 1599df930be7Sderaadt ksc.sc_onstack = oonstack; 1600df930be7Sderaadt ksc.sc_mask = mask; 160150ce9ee0Sniklas ksc.sc_pc = frame->tf_regs[FRAME_PC]; 160250ce9ee0Sniklas ksc.sc_ps = frame->tf_regs[FRAME_PS]; 1603df930be7Sderaadt 1604df930be7Sderaadt /* copy the registers. */ 1605df930be7Sderaadt frametoreg(frame, (struct reg *)ksc.sc_regs); 1606df930be7Sderaadt ksc.sc_regs[R_ZERO] = 0xACEDBADE; /* magic number */ 160750ce9ee0Sniklas ksc.sc_regs[R_SP] = alpha_pal_rdusp(); 1608df930be7Sderaadt 1609df930be7Sderaadt /* save the floating-point state, if necessary, then copy it. */ 1610433075b6Spvalchev if (p->p_addr->u_pcb.pcb_fpcpu != NULL) 1611433075b6Spvalchev fpusave_proc(p, 1); 1612df930be7Sderaadt ksc.sc_ownedfp = p->p_md.md_flags & MDP_FPUSED; 1613433075b6Spvalchev memcpy((struct fpreg *)ksc.sc_fpregs, &p->p_addr->u_pcb.pcb_fp, 1614df930be7Sderaadt sizeof(struct fpreg)); 1615433075b6Spvalchev #ifndef NO_IEEE 1616433075b6Spvalchev ksc.sc_fp_control = alpha_read_fp_c(p); 1617433075b6Spvalchev #else 1618433075b6Spvalchev ksc.sc_fp_control = 0; 1619433075b6Spvalchev #endif 1620433075b6Spvalchev memset(ksc.sc_reserved, 0, sizeof ksc.sc_reserved); /* XXX */ 1621433075b6Spvalchev memset(ksc.sc_xxx, 0, sizeof ksc.sc_xxx); /* XXX */ 1622df930be7Sderaadt 1623df930be7Sderaadt #ifdef COMPAT_OSF1 1624df930be7Sderaadt /* 1625df930be7Sderaadt * XXX Create an OSF/1-style sigcontext and associated goo. 1626df930be7Sderaadt */ 1627df930be7Sderaadt #endif 1628df930be7Sderaadt 16292bf9c155Sderaadt if (psp->ps_siginfo & sigmask(sig)) { 16302bf9c155Sderaadt initsiginfo(&ksi, sig, code, type, val); 16312bf9c155Sderaadt sip = (void *)scp + kscsize; 16322bf9c155Sderaadt (void) copyout((caddr_t)&ksi, (caddr_t)sip, fsize - kscsize); 16332bf9c155Sderaadt } 16342bf9c155Sderaadt 1635df930be7Sderaadt /* 1636df930be7Sderaadt * copy the frame out to userland. 1637df930be7Sderaadt */ 16382bf9c155Sderaadt (void) copyout((caddr_t)&ksc, (caddr_t)scp, kscsize); 1639df930be7Sderaadt #ifdef DEBUG 1640df930be7Sderaadt if (sigdebug & SDB_FOLLOW) 164150ce9ee0Sniklas printf("sendsig(%d): sig %d scp %p code %lx\n", p->p_pid, sig, 1642df930be7Sderaadt scp, code); 1643df930be7Sderaadt #endif 1644df930be7Sderaadt 1645df930be7Sderaadt /* 1646df930be7Sderaadt * Set up the registers to return to sigcode. 1647df930be7Sderaadt */ 16484a5480feSart frame->tf_regs[FRAME_PC] = p->p_sigcode; 164950ce9ee0Sniklas frame->tf_regs[FRAME_A0] = sig; 16502bf9c155Sderaadt frame->tf_regs[FRAME_A1] = (psp->ps_siginfo & sigmask(sig)) ? 16512bf9c155Sderaadt (u_int64_t)sip : NULL; 165250ce9ee0Sniklas frame->tf_regs[FRAME_A2] = (u_int64_t)scp; 1653df930be7Sderaadt frame->tf_regs[FRAME_T12] = (u_int64_t)catcher; /* t12 is pv */ 165450ce9ee0Sniklas alpha_pal_wrusp((unsigned long)scp); 1655df930be7Sderaadt 1656df930be7Sderaadt #ifdef DEBUG 1657df930be7Sderaadt if (sigdebug & SDB_FOLLOW) 1658df930be7Sderaadt printf("sendsig(%d): pc %lx, catcher %lx\n", p->p_pid, 165950ce9ee0Sniklas frame->tf_regs[FRAME_PC], frame->tf_regs[FRAME_A3]); 1660df930be7Sderaadt if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) 1661df930be7Sderaadt printf("sendsig(%d): sig %d returns\n", 1662df930be7Sderaadt p->p_pid, sig); 1663df930be7Sderaadt #endif 1664df930be7Sderaadt } 1665df930be7Sderaadt 1666df930be7Sderaadt /* 1667df930be7Sderaadt * System call to cleanup state after a signal 1668df930be7Sderaadt * has been taken. Reset signal mask and 1669df930be7Sderaadt * stack state from context left by sendsig (above). 1670df930be7Sderaadt * Return to previous pc and psl as specified by 1671df930be7Sderaadt * context left by sendsig. Check carefully to 1672df930be7Sderaadt * make sure that the user has not modified the 1673125cd19fSderaadt * psl to gain improper privileges or to cause 1674df930be7Sderaadt * a machine fault. 1675df930be7Sderaadt */ 1676df930be7Sderaadt /* ARGSUSED */ 1677df930be7Sderaadt int 1678df930be7Sderaadt sys_sigreturn(p, v, retval) 1679df930be7Sderaadt struct proc *p; 1680df930be7Sderaadt void *v; 1681df930be7Sderaadt register_t *retval; 1682df930be7Sderaadt { 1683df930be7Sderaadt struct sys_sigreturn_args /* { 1684df930be7Sderaadt syscallarg(struct sigcontext *) sigcntxp; 1685df930be7Sderaadt } */ *uap = v; 1686df930be7Sderaadt struct sigcontext *scp, ksc; 1687df930be7Sderaadt 1688df930be7Sderaadt scp = SCARG(uap, sigcntxp); 1689df930be7Sderaadt #ifdef DEBUG 1690df930be7Sderaadt if (sigdebug & SDB_FOLLOW) 169150ce9ee0Sniklas printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); 1692df930be7Sderaadt #endif 1693df930be7Sderaadt 1694df930be7Sderaadt if (ALIGN(scp) != (u_int64_t)scp) 1695df930be7Sderaadt return (EINVAL); 1696df930be7Sderaadt 1697df930be7Sderaadt /* 1698df930be7Sderaadt * Test and fetch the context structure. 1699df930be7Sderaadt * We grab it all at once for speed. 1700df930be7Sderaadt */ 1701aed035abSart if (uvm_useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 || 1702df930be7Sderaadt copyin((caddr_t)scp, (caddr_t)&ksc, sizeof ksc)) 1703df930be7Sderaadt return (EINVAL); 1704df930be7Sderaadt 1705df930be7Sderaadt if (ksc.sc_regs[R_ZERO] != 0xACEDBADE) /* magic number */ 1706df930be7Sderaadt return (EINVAL); 1707df930be7Sderaadt /* 1708df930be7Sderaadt * Restore the user-supplied information 1709df930be7Sderaadt */ 1710df930be7Sderaadt if (ksc.sc_onstack) 1711df930be7Sderaadt p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; 1712df930be7Sderaadt else 1713df930be7Sderaadt p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; 1714df930be7Sderaadt p->p_sigmask = ksc.sc_mask &~ sigcantmask; 1715df930be7Sderaadt 171650ce9ee0Sniklas p->p_md.md_tf->tf_regs[FRAME_PC] = ksc.sc_pc; 171750ce9ee0Sniklas p->p_md.md_tf->tf_regs[FRAME_PS] = 171850ce9ee0Sniklas (ksc.sc_ps | ALPHA_PSL_USERSET) & ~ALPHA_PSL_USERCLR; 1719df930be7Sderaadt 1720df930be7Sderaadt regtoframe((struct reg *)ksc.sc_regs, p->p_md.md_tf); 172150ce9ee0Sniklas alpha_pal_wrusp(ksc.sc_regs[R_SP]); 1722df930be7Sderaadt 1723df930be7Sderaadt /* XXX ksc.sc_ownedfp ? */ 1724433075b6Spvalchev if (p->p_addr->u_pcb.pcb_fpcpu != NULL) 1725433075b6Spvalchev fpusave_proc(p, 0); 1726433075b6Spvalchev memcpy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)ksc.sc_fpregs, 1727df930be7Sderaadt sizeof(struct fpreg)); 1728433075b6Spvalchev #ifndef NO_IEEE 1729433075b6Spvalchev p->p_addr->u_pcb.pcb_fp.fpr_cr = ksc.sc_fpcr; 1730433075b6Spvalchev p->p_md.md_flags = ksc.sc_fp_control & MDP_FP_C; 1731433075b6Spvalchev #endif 1732df930be7Sderaadt 1733df930be7Sderaadt #ifdef DEBUG 1734df930be7Sderaadt if (sigdebug & SDB_FOLLOW) 1735df930be7Sderaadt printf("sigreturn(%d): returns\n", p->p_pid); 1736df930be7Sderaadt #endif 1737df930be7Sderaadt return (EJUSTRETURN); 1738df930be7Sderaadt } 1739df930be7Sderaadt 1740df930be7Sderaadt /* 1741df930be7Sderaadt * machine dependent system variables. 1742df930be7Sderaadt */ 174350ce9ee0Sniklas int 1744df930be7Sderaadt cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) 1745df930be7Sderaadt int *name; 1746df930be7Sderaadt u_int namelen; 1747df930be7Sderaadt void *oldp; 1748df930be7Sderaadt size_t *oldlenp; 1749df930be7Sderaadt void *newp; 1750df930be7Sderaadt size_t newlen; 1751df930be7Sderaadt struct proc *p; 1752df930be7Sderaadt { 1753df930be7Sderaadt dev_t consdev; 1754df930be7Sderaadt 175545e5a1a0Sart if (name[0] != CPU_CHIPSET && namelen != 1) 1756df930be7Sderaadt return (ENOTDIR); /* overloaded */ 1757df930be7Sderaadt 1758df930be7Sderaadt switch (name[0]) { 1759df930be7Sderaadt case CPU_CONSDEV: 1760df930be7Sderaadt if (cn_tab != NULL) 1761df930be7Sderaadt consdev = cn_tab->cn_dev; 1762df930be7Sderaadt else 1763df930be7Sderaadt consdev = NODEV; 1764df930be7Sderaadt return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, 1765df930be7Sderaadt sizeof consdev)); 1766417eba8cSderaadt 1767417eba8cSderaadt case CPU_ROOT_DEVICE: 1768aed035abSart return (sysctl_rdstring(oldp, oldlenp, newp, 1769aed035abSart root_device)); 1770417eba8cSderaadt 177150ce9ee0Sniklas case CPU_UNALIGNED_PRINT: 177250ce9ee0Sniklas return (sysctl_int(oldp, oldlenp, newp, newlen, 177350ce9ee0Sniklas &alpha_unaligned_print)); 177450ce9ee0Sniklas 177550ce9ee0Sniklas case CPU_UNALIGNED_FIX: 177650ce9ee0Sniklas return (sysctl_int(oldp, oldlenp, newp, newlen, 177750ce9ee0Sniklas &alpha_unaligned_fix)); 177850ce9ee0Sniklas 177950ce9ee0Sniklas case CPU_UNALIGNED_SIGBUS: 178050ce9ee0Sniklas return (sysctl_int(oldp, oldlenp, newp, newlen, 178150ce9ee0Sniklas &alpha_unaligned_sigbus)); 178250ce9ee0Sniklas 17833a630e3fSniklas case CPU_BOOTED_KERNEL: 1784aed035abSart return (sysctl_rdstring(oldp, oldlenp, newp, 1785aed035abSart bootinfo.booted_kernel)); 17863a630e3fSniklas 178745e5a1a0Sart case CPU_CHIPSET: 178845e5a1a0Sart return (alpha_sysctl_chipset(name + 1, namelen - 1, oldp, 178945e5a1a0Sart oldlenp)); 1790433075b6Spvalchev 1791433075b6Spvalchev #ifndef NO_IEEE 1792433075b6Spvalchev case CPU_FP_SYNC_COMPLETE: 1793433075b6Spvalchev return (sysctl_int(oldp, oldlenp, newp, newlen, 1794433075b6Spvalchev &alpha_fp_sync_complete)); 1795433075b6Spvalchev #endif 1796*27626149Smatthieu case CPU_ALLOWAPERTURE: 1797*27626149Smatthieu #ifdef APERTURE 1798*27626149Smatthieu if (securelevel > 0) 1799*27626149Smatthieu return (sysctl_rdint(oldp, oldlenp, newp, 1800*27626149Smatthieu allowaperture)); 1801*27626149Smatthieu else 1802*27626149Smatthieu return (sysctl_int(oldp, oldlenp, newp, newlen, 1803*27626149Smatthieu &allowaperture)); 1804*27626149Smatthieu #else 1805*27626149Smatthieu return (sysctl_rdint(oldp, oldlenp, newp, 0)); 1806*27626149Smatthieu #endif 1807df930be7Sderaadt default: 1808df930be7Sderaadt return (EOPNOTSUPP); 1809df930be7Sderaadt } 1810df930be7Sderaadt /* NOTREACHED */ 1811df930be7Sderaadt } 1812df930be7Sderaadt 1813df930be7Sderaadt /* 1814df930be7Sderaadt * Set registers on exec. 1815df930be7Sderaadt */ 1816df930be7Sderaadt void 1817df930be7Sderaadt setregs(p, pack, stack, retval) 1818df930be7Sderaadt register struct proc *p; 1819df930be7Sderaadt struct exec_package *pack; 1820df930be7Sderaadt u_long stack; 1821df930be7Sderaadt register_t *retval; 1822df930be7Sderaadt { 1823df930be7Sderaadt struct trapframe *tfp = p->p_md.md_tf; 18243a630e3fSniklas #ifdef DEBUG 18253a630e3fSniklas int i; 18263a630e3fSniklas #endif 1827df930be7Sderaadt 1828df930be7Sderaadt #ifdef DEBUG 182950ce9ee0Sniklas /* 183050ce9ee0Sniklas * Crash and dump, if the user requested it. 183150ce9ee0Sniklas */ 183250ce9ee0Sniklas if (boothowto & RB_DUMP) 183350ce9ee0Sniklas panic("crash requested by boot flags"); 183450ce9ee0Sniklas #endif 183550ce9ee0Sniklas 183650ce9ee0Sniklas #ifdef DEBUG 183750ce9ee0Sniklas for (i = 0; i < FRAME_SIZE; i++) 1838df930be7Sderaadt tfp->tf_regs[i] = 0xbabefacedeadbeef; 1839df930be7Sderaadt #else 184050ce9ee0Sniklas bzero(tfp->tf_regs, FRAME_SIZE * sizeof tfp->tf_regs[0]); 1841df930be7Sderaadt #endif 1842df930be7Sderaadt bzero(&p->p_addr->u_pcb.pcb_fp, sizeof p->p_addr->u_pcb.pcb_fp); 184350ce9ee0Sniklas alpha_pal_wrusp(stack); 184450ce9ee0Sniklas tfp->tf_regs[FRAME_PS] = ALPHA_PSL_USERSET; 184550ce9ee0Sniklas tfp->tf_regs[FRAME_PC] = pack->ep_entry & ~3; 1846df930be7Sderaadt 184750ce9ee0Sniklas tfp->tf_regs[FRAME_A0] = stack; 184850ce9ee0Sniklas /* a1 and a2 already zeroed */ 184950ce9ee0Sniklas tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC]; /* a.k.a. PV */ 185050ce9ee0Sniklas 185150ce9ee0Sniklas p->p_md.md_flags &= ~MDP_FPUSED; 1852433075b6Spvalchev #ifndef NO_IEEE 1853433075b6Spvalchev if (__predict_true((p->p_md.md_flags & IEEE_INHERIT) == 0)) { 1854433075b6Spvalchev p->p_md.md_flags &= ~MDP_FP_C; 1855433075b6Spvalchev p->p_addr->u_pcb.pcb_fp.fpr_cr = FPCR_DYN(FP_RN); 1856433075b6Spvalchev } 1857433075b6Spvalchev #endif 1858433075b6Spvalchev if (p->p_addr->u_pcb.pcb_fpcpu != NULL) 1859433075b6Spvalchev fpusave_proc(p, 0); 1860433075b6Spvalchev } 1861df930be7Sderaadt 1862433075b6Spvalchev /* 1863433075b6Spvalchev * Release the FPU. 1864433075b6Spvalchev */ 1865433075b6Spvalchev void 1866433075b6Spvalchev fpusave_cpu(struct cpu_info *ci, int save) 1867433075b6Spvalchev { 1868433075b6Spvalchev struct proc *p; 1869433075b6Spvalchev #if defined(MULTIPROCESSOR) 1870433075b6Spvalchev int s; 1871433075b6Spvalchev #endif 1872433075b6Spvalchev 1873433075b6Spvalchev KDASSERT(ci == curcpu()); 1874433075b6Spvalchev 1875433075b6Spvalchev #if defined(MULTIPROCESSOR) 1876433075b6Spvalchev atomic_setbits_ulong(&ci->ci_flags, CPUF_FPUSAVE); 1877433075b6Spvalchev #endif 1878433075b6Spvalchev 1879433075b6Spvalchev p = ci->ci_fpcurproc; 1880433075b6Spvalchev if (p == NULL) 1881433075b6Spvalchev goto out; 1882433075b6Spvalchev 1883433075b6Spvalchev if (save) { 1884433075b6Spvalchev alpha_pal_wrfen(1); 1885433075b6Spvalchev savefpstate(&p->p_addr->u_pcb.pcb_fp); 1886433075b6Spvalchev } 1887433075b6Spvalchev 1888433075b6Spvalchev alpha_pal_wrfen(0); 1889433075b6Spvalchev 1890433075b6Spvalchev p->p_addr->u_pcb.pcb_fpcpu = NULL; 1891433075b6Spvalchev ci->ci_fpcurproc = NULL; 1892433075b6Spvalchev 1893433075b6Spvalchev out: 1894433075b6Spvalchev #if defined(MULTIPROCESSOR) 1895433075b6Spvalchev atomic_clearbits_ulong(&ci->ci_flags, CPUF_FPUSAVE); 1896433075b6Spvalchev #endif 1897433075b6Spvalchev return; 1898433075b6Spvalchev } 1899433075b6Spvalchev 1900433075b6Spvalchev /* 1901433075b6Spvalchev * Synchronize FP state for this process. 1902433075b6Spvalchev */ 1903433075b6Spvalchev void 1904433075b6Spvalchev fpusave_proc(struct proc *p, int save) 1905433075b6Spvalchev { 1906433075b6Spvalchev struct cpu_info *ci = curcpu(); 1907433075b6Spvalchev struct cpu_info *oci; 1908433075b6Spvalchev #if defined(MULTIPROCESSOR) 1909433075b6Spvalchev u_long ipi = save ? ALPHA_IPI_SYNCH_FPU : ALPHA_IPI_DISCARD_FPU; 1910433075b6Spvalchev int s, spincount; 1911433075b6Spvalchev #endif 1912433075b6Spvalchev 1913433075b6Spvalchev KDASSERT(p->p_addr != NULL); 1914433075b6Spvalchev KDASSERT(p->p_flag & P_INMEM); 1915433075b6Spvalchev 1916433075b6Spvalchev oci = p->p_addr->u_pcb.pcb_fpcpu; 1917433075b6Spvalchev if (oci == NULL) { 1918433075b6Spvalchev return; 1919433075b6Spvalchev } 1920433075b6Spvalchev 1921433075b6Spvalchev #if defined(MULTIPROCESSOR) 1922433075b6Spvalchev if (oci == ci) { 1923433075b6Spvalchev KASSERT(ci->ci_fpcurproc == p); 1924433075b6Spvalchev fpusave_cpu(ci, save); 1925433075b6Spvalchev return; 1926433075b6Spvalchev } 1927433075b6Spvalchev 1928433075b6Spvalchev KASSERT(oci->ci_fpcurproc == p); 1929433075b6Spvalchev alpha_send_ipi(oci->ci_cpuid, ipi); 1930433075b6Spvalchev 1931433075b6Spvalchev spincount = 0; 1932433075b6Spvalchev while (p->p_addr->u_pcb.pcb_fpcpu != NULL) { 1933433075b6Spvalchev spincount++; 1934433075b6Spvalchev delay(1000); /* XXX */ 1935433075b6Spvalchev if (spincount > 10000) 1936433075b6Spvalchev panic("fpsave ipi didn't"); 1937433075b6Spvalchev } 1938433075b6Spvalchev #else 1939433075b6Spvalchev KASSERT(ci->ci_fpcurproc == p); 1940433075b6Spvalchev fpusave_cpu(ci, save); 1941433075b6Spvalchev #endif /* MULTIPROCESSOR */ 1942df930be7Sderaadt } 1943df930be7Sderaadt 1944df930be7Sderaadt int 1945df930be7Sderaadt spl0() 1946df930be7Sderaadt { 1947df930be7Sderaadt 1948aed035abSart if (ssir) { 1949aed035abSart (void) alpha_pal_swpipl(ALPHA_PSL_IPL_SOFT); 19502a2685f2Sart softintr_dispatch(); 1951aed035abSart } 1952df930be7Sderaadt 195350ce9ee0Sniklas return (alpha_pal_swpipl(ALPHA_PSL_IPL_0)); 1954df930be7Sderaadt } 1955df930be7Sderaadt 1956df930be7Sderaadt /* 1957df930be7Sderaadt * The following primitives manipulate the run queues. _whichqs tells which 1958df930be7Sderaadt * of the 32 queues _qs have processes in them. Setrunqueue puts processes 1959e464495eSniklas * into queues, Remrunqueue removes them from queues. The running process is 1960e464495eSniklas * on no queue, other processes are on a queue related to p->p_priority, 1961e464495eSniklas * divided by 4 actually to shrink the 0-127 range of priorities into the 32 1962e464495eSniklas * available queues. 1963df930be7Sderaadt */ 1964df930be7Sderaadt /* 1965df930be7Sderaadt * setrunqueue(p) 1966df930be7Sderaadt * proc *p; 1967df930be7Sderaadt * 1968df930be7Sderaadt * Call should be made at splclock(), and p->p_stat should be SRUN. 1969df930be7Sderaadt */ 1970df930be7Sderaadt 19712a2685f2Sart /* XXXART - grmble */ 19722a2685f2Sart #define sched_qs qs 19732a2685f2Sart #define sched_whichqs whichqs 19742a2685f2Sart 1975df930be7Sderaadt void 1976df930be7Sderaadt setrunqueue(p) 1977df930be7Sderaadt struct proc *p; 1978df930be7Sderaadt { 1979df930be7Sderaadt int bit; 1980df930be7Sderaadt 1981df930be7Sderaadt /* firewall: p->p_back must be NULL */ 1982df930be7Sderaadt if (p->p_back != NULL) 1983df930be7Sderaadt panic("setrunqueue"); 1984df930be7Sderaadt 1985df930be7Sderaadt bit = p->p_priority >> 2; 19862a2685f2Sart sched_whichqs |= (1 << bit); 19872a2685f2Sart p->p_forw = (struct proc *)&sched_qs[bit]; 19882a2685f2Sart p->p_back = sched_qs[bit].ph_rlink; 1989df930be7Sderaadt p->p_back->p_forw = p; 19902a2685f2Sart sched_qs[bit].ph_rlink = p; 1991df930be7Sderaadt } 1992df930be7Sderaadt 1993df930be7Sderaadt /* 1994e464495eSniklas * remrunqueue(p) 1995df930be7Sderaadt * 1996df930be7Sderaadt * Call should be made at splclock(). 1997df930be7Sderaadt */ 1998df930be7Sderaadt void 1999d3cbbad5Skstailey remrunqueue(p) 2000df930be7Sderaadt struct proc *p; 2001df930be7Sderaadt { 2002df930be7Sderaadt int bit; 2003df930be7Sderaadt 2004df930be7Sderaadt bit = p->p_priority >> 2; 20052a2685f2Sart if ((sched_whichqs & (1 << bit)) == 0) 2006d3cbbad5Skstailey panic("remrunqueue"); 2007df930be7Sderaadt 2008df930be7Sderaadt p->p_back->p_forw = p->p_forw; 2009df930be7Sderaadt p->p_forw->p_back = p->p_back; 2010df930be7Sderaadt p->p_back = NULL; /* for firewall checking. */ 2011df930be7Sderaadt 20122a2685f2Sart if ((struct proc *)&sched_qs[bit] == sched_qs[bit].ph_link) 20132a2685f2Sart sched_whichqs &= ~(1 << bit); 2014df930be7Sderaadt } 2015df930be7Sderaadt 2016df930be7Sderaadt /* 2017df930be7Sderaadt * Return the best possible estimate of the time in the timeval 2018df930be7Sderaadt * to which tvp points. Unfortunately, we can't read the hardware registers. 2019df930be7Sderaadt * We guarantee that the time will be greater than the value obtained by a 2020df930be7Sderaadt * previous call. 2021df930be7Sderaadt */ 2022df930be7Sderaadt void 2023df930be7Sderaadt microtime(tvp) 2024df930be7Sderaadt register struct timeval *tvp; 2025df930be7Sderaadt { 2026df930be7Sderaadt int s = splclock(); 2027df930be7Sderaadt static struct timeval lasttime; 2028df930be7Sderaadt 2029df930be7Sderaadt *tvp = time; 2030df930be7Sderaadt #ifdef notdef 2031df930be7Sderaadt tvp->tv_usec += clkread(); 20324c891e15Spjanzen while (tvp->tv_usec >= 1000000) { 2033df930be7Sderaadt tvp->tv_sec++; 2034df930be7Sderaadt tvp->tv_usec -= 1000000; 2035df930be7Sderaadt } 2036df930be7Sderaadt #endif 2037df930be7Sderaadt if (tvp->tv_sec == lasttime.tv_sec && 2038df930be7Sderaadt tvp->tv_usec <= lasttime.tv_usec && 20394c891e15Spjanzen (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) { 2040df930be7Sderaadt tvp->tv_sec++; 2041df930be7Sderaadt tvp->tv_usec -= 1000000; 2042df930be7Sderaadt } 2043df930be7Sderaadt lasttime = *tvp; 2044df930be7Sderaadt splx(s); 2045df930be7Sderaadt } 2046df930be7Sderaadt 2047417eba8cSderaadt /* 2048417eba8cSderaadt * Wait "n" microseconds. 2049417eba8cSderaadt */ 205050ce9ee0Sniklas void 2051417eba8cSderaadt delay(n) 205250ce9ee0Sniklas unsigned long n; 2053417eba8cSderaadt { 2054417eba8cSderaadt long N = cycles_per_usec * (n); 2055417eba8cSderaadt 2056aed035abSart /* 2057aed035abSart * XXX Should be written to use RPCC? 2058aed035abSart */ 2059aed035abSart 2060aed035abSart __asm __volatile( 2061aed035abSart "# The 2 corresponds to the insn count\n" 2062aed035abSart "1: subq %2, %1, %0 \n" 2063aed035abSart " bgt %0, 1b" 2064aed035abSart : "=r" (N) 2065aed035abSart : "i" (2), "0" (N)); 2066417eba8cSderaadt } 2067417eba8cSderaadt 2068df930be7Sderaadt #if defined(COMPAT_OSF1) || 1 /* XXX */ 2069c4071fd1Smillert void cpu_exec_ecoff_setregs(struct proc *, struct exec_package *, 2070c4071fd1Smillert u_long, register_t *); 20713a630e3fSniklas 2072df930be7Sderaadt void 2073417eba8cSderaadt cpu_exec_ecoff_setregs(p, epp, stack, retval) 2074df930be7Sderaadt struct proc *p; 2075417eba8cSderaadt struct exec_package *epp; 2076df930be7Sderaadt u_long stack; 2077df930be7Sderaadt register_t *retval; 2078df930be7Sderaadt { 2079417eba8cSderaadt struct ecoff_exechdr *execp = (struct ecoff_exechdr *)epp->ep_hdr; 2080df930be7Sderaadt 2081417eba8cSderaadt setregs(p, epp, stack, retval); 208250ce9ee0Sniklas p->p_md.md_tf->tf_regs[FRAME_GP] = execp->a.gp_value; 2083df930be7Sderaadt } 2084df930be7Sderaadt 2085df930be7Sderaadt /* 2086df930be7Sderaadt * cpu_exec_ecoff_hook(): 2087df930be7Sderaadt * cpu-dependent ECOFF format hook for execve(). 2088df930be7Sderaadt * 2089df930be7Sderaadt * Do any machine-dependent diddling of the exec package when doing ECOFF. 2090df930be7Sderaadt * 2091df930be7Sderaadt */ 2092df930be7Sderaadt int 2093417eba8cSderaadt cpu_exec_ecoff_hook(p, epp) 2094df930be7Sderaadt struct proc *p; 2095df930be7Sderaadt struct exec_package *epp; 2096df930be7Sderaadt { 2097417eba8cSderaadt struct ecoff_exechdr *execp = (struct ecoff_exechdr *)epp->ep_hdr; 2098c3114d5bSericj extern struct emul emul_native; 2099aed035abSart int error; 21004e8700e2Sericj extern int osf1_exec_ecoff_hook(struct proc *, struct exec_package *); 2101df930be7Sderaadt 2102417eba8cSderaadt switch (execp->f.f_magic) { 2103df930be7Sderaadt #ifdef COMPAT_OSF1 2104df930be7Sderaadt case ECOFF_MAGIC_ALPHA: 21054e8700e2Sericj error = osf1_exec_ecoff_hook(p, epp); 2106df930be7Sderaadt break; 2107df930be7Sderaadt #endif 2108df930be7Sderaadt 210950ce9ee0Sniklas case ECOFF_MAGIC_NATIVE_ALPHA: 2110a2f8ce8dSderaadt epp->ep_emul = &emul_native; 2111aed035abSart error = 0; 2112df930be7Sderaadt break; 2113df930be7Sderaadt 2114df930be7Sderaadt default: 2115aed035abSart error = ENOEXEC; 2116df930be7Sderaadt } 2117aed035abSart return (error); 2118df930be7Sderaadt } 2119df930be7Sderaadt #endif 2120e464495eSniklas 2121aed035abSart int 2122aed035abSart alpha_pa_access(pa) 2123aed035abSart u_long pa; 2124aed035abSart { 2125aed035abSart int i; 2126aed035abSart 2127aed035abSart for (i = 0; i < mem_cluster_cnt; i++) { 2128aed035abSart if (pa < mem_clusters[i].start) 2129aed035abSart continue; 2130aed035abSart if ((pa - mem_clusters[i].start) >= 2131aed035abSart (mem_clusters[i].size & ~PAGE_MASK)) 2132aed035abSart continue; 2133aed035abSart return (mem_clusters[i].size & PAGE_MASK); /* prot */ 2134aed035abSart } 2135aed035abSart 2136aed035abSart /* 2137aed035abSart * Address is not a memory address. If we're secure, disallow 2138aed035abSart * access. Otherwise, grant read/write. 2139aed035abSart */ 2140aed035abSart if (securelevel > 0) 2141aed035abSart return (VM_PROT_NONE); 2142aed035abSart else 2143aed035abSart return (VM_PROT_READ | VM_PROT_WRITE); 2144aed035abSart } 2145aed035abSart 2146e464495eSniklas /* XXX XXX BEGIN XXX XXX */ 2147aed035abSart paddr_t alpha_XXX_dmamap_or; /* XXX */ 2148e464495eSniklas /* XXX */ 2149aed035abSart paddr_t /* XXX */ 2150e464495eSniklas alpha_XXX_dmamap(v) /* XXX */ 2151aed035abSart vaddr_t v; /* XXX */ 2152e464495eSniklas { /* XXX */ 2153e464495eSniklas /* XXX */ 2154e464495eSniklas return (vtophys(v) | alpha_XXX_dmamap_or); /* XXX */ 2155e464495eSniklas } /* XXX */ 2156e464495eSniklas /* XXX XXX END XXX XXX */ 2157aed035abSart 2158aed035abSart char * 2159aed035abSart dot_conv(x) 2160aed035abSart unsigned long x; 2161aed035abSart { 2162aed035abSart int i; 2163aed035abSart char *xc; 2164aed035abSart static int next; 2165aed035abSart static char space[2][20]; 2166aed035abSart 2167aed035abSart xc = space[next ^= 1] + sizeof space[0]; 2168aed035abSart *--xc = '\0'; 2169aed035abSart for (i = 0;; ++i) { 2170aed035abSart if (i && (i & 3) == 0) 2171aed035abSart *--xc = '.'; 2172aed035abSart *--xc = "0123456789abcdef"[x & 0xf]; 2173aed035abSart x >>= 4; 2174aed035abSart if (x == 0) 2175aed035abSart break; 2176aed035abSart } 2177aed035abSart return xc; 2178aed035abSart } 2179