Index: head/sys/alpha/alpha/machdep.c =================================================================== --- head/sys/alpha/alpha/machdep.c (revision 82392) +++ head/sys/alpha/alpha/machdep.c (revision 82393) @@ -1,2190 +1,2193 @@ /*- * Copyright (c) 1998 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center and by Chris G. Demetriou. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #include "opt_compat.h" #include "opt_ddb.h" #include "opt_simos.h" #include "opt_msgbuf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include u_int64_t cycles_per_usec; u_int32_t cycles_per_sec; int cold = 1; struct platform platform; alpha_chipset_t chipset; struct bootinfo_kernel bootinfo; struct mtx sched_lock; struct mtx Giant; struct user *proc0paddr; char machine[] = "alpha"; SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); static char cpu_model[128]; SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); #ifdef DDB /* start and end of kernel symbol table */ void *ksym_start, *ksym_end; #endif int alpha_unaligned_print = 1; /* warn about unaligned accesses */ int alpha_unaligned_fix = 1; /* fix up unaligned accesses */ int alpha_unaligned_sigbus = 0; /* don't SIGBUS on fixed-up accesses */ SYSCTL_INT(_machdep, CPU_UNALIGNED_PRINT, unaligned_print, CTLFLAG_RW, &alpha_unaligned_print, 0, ""); SYSCTL_INT(_machdep, CPU_UNALIGNED_FIX, unaligned_fix, CTLFLAG_RW, &alpha_unaligned_fix, 0, ""); SYSCTL_INT(_machdep, CPU_UNALIGNED_SIGBUS, unaligned_sigbus, CTLFLAG_RW, &alpha_unaligned_sigbus, 0, ""); static void cpu_startup __P((void *)); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL) struct msgbuf *msgbufp=0; int Maxmem = 0; long dumplo; int totalphysmem; /* total amount of physical memory in system */ int physmem; /* physical memory used by NetBSD + some rsvd */ int resvmem; /* amount of memory reserved for PROM */ int unusedmem; /* amount of memory for OS that we don't use */ int unknownmem; /* amount of memory with an unknown use */ int ncpus; /* number of cpus */ vm_offset_t phys_avail[10]; static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, alpha_ptob(physmem), req); return (error); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "I", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, alpha_ptob(physmem - cnt.v_wire_count), req); return (error); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "I", ""); SYSCTL_INT(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, ""); /* must be 2 less so 0 0 can signal end of chunks */ #define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2) void osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code); static void identifycpu __P((void)); struct kva_md_info kmi; /* * Hooked into the shutdown chain; if the system is to be halted, * unconditionally drop back to the SRM console. */ static void alpha_srm_shutdown(void *junk, int howto) { if (howto & RB_HALT) { cpu_halt(); } } static void cpu_startup(dummy) void *dummy; { /* * Good {morning,afternoon,evening,night}. */ identifycpu(); /* startrtclock(); */ #ifdef PERFMON perfmon_init(); #endif printf("real memory = %ld (%ldK bytes)\n", alpha_ptob(Maxmem), alpha_ptob(Maxmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { int size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08lx - 0x%08lx, %d bytes (%d pages)\n", phys_avail[indx], phys_avail[indx + 1] - 1, size1, size1 / PAGE_SIZE); } } vm_ksubmap_init(&kmi); #if 0 /* * Calculate callout wheel size */ for (callwheelsize = 1, callwheelbits = 0; callwheelsize < ncallout; callwheelsize <<= 1, ++callwheelbits) ; callwheelmask = callwheelsize - 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(callout, struct callout, ncallout); valloc(callwheel, struct callout_tailq, callwheelsize); /* * The nominal buffer size (and minimum KVA allocation) is BKVASIZE. * For the first 64MB of ram nominally allocate sufficient buffers to * cover 1/4 of our ram. Beyond the first 64MB allocate additional * buffers to cover 1/20 of our ram over 64MB. */ if (nbuf == 0) { int factor = 4 * BKVASIZE / PAGE_SIZE; nbuf = 50; if (physmem > 1024) nbuf += min((physmem - 1024) / factor, 16384 / factor); if (physmem > 16384) nbuf += (physmem - 16384) * 2 / (factor * 5); } nswbuf = max(min(nbuf/4, 64), 16); valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); v = bufhashinit(v); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (vm_offset_t)kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size); buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, (nbuf*BKVASIZE)); buffer_map->system_map = 1; pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, (nswbuf*MAXPHYS) + pager_map_size); pager_map->system_map = 1; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (16*(ARG_MAX+(PAGE_SIZE*3)))); /* * XXX: Mbuf system machine-specific initializations should * go here, if anywhere. */ /* * Initialize callouts */ SLIST_INIT(&callfree); for (i = 0; i < ncallout; i++) { callout_init(&callout[i], 0); callout[i].c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle); } for (i = 0; i < callwheelsize; i++) { TAILQ_INIT(&callwheel[i]); } mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE); #endif #if defined(USERCONFIG) #if defined(USERCONFIG_BOOT) if (1) #else if (boothowto & RB_CONFIG) #endif { userconfig(); cninit(); /* the preferred console may have changed */ } #endif printf("avail memory = %ld (%ldK bytes)\n", ptoa(cnt.v_free_count), ptoa(cnt.v_free_count) / 1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); EVENTHANDLER_REGISTER(shutdown_final, alpha_srm_shutdown, 0, SHUTDOWN_PRI_LAST); } /* * Retrieve the platform name from the DSR. */ const char * alpha_dsr_sysname() { struct dsrdb *dsr; const char *sysname; /* * DSR does not exist on early HWRPB versions. */ if (hwrpb->rpb_version < HWRPB_DSRDB_MINVERS) return (NULL); dsr = (struct dsrdb *)(((caddr_t)hwrpb) + hwrpb->rpb_dsrdb_off); sysname = (const char *)((caddr_t)dsr + (dsr->dsr_sysname_off + sizeof(u_int64_t))); return (sysname); } /* * Lookup the system specified system variation in the provided table, * returning the model string on match. */ const char * alpha_variation_name(u_int64_t variation, const struct alpha_variation_table *avtp) { int i; for (i = 0; avtp[i].avt_model != NULL; i++) if (avtp[i].avt_variation == variation) return (avtp[i].avt_model); return (NULL); } /* * Generate a default platform name based for unknown system variations. */ const char * alpha_unknown_sysname() { static char s[128]; /* safe size */ snprintf(s, sizeof(s), "%s family, unknown model variation 0x%lx", platform.family, hwrpb->rpb_variation & SV_ST_MASK); return ((const char *)s); } static void identifycpu(void) { u_int64_t type, major, minor; u_int64_t amask; struct pcs *pcsp; char *cpuname[] = { "unknown", /* 0 */ "EV3", /* 1 */ "EV4 (21064)", /* 2 */ "Simulation", /* 3 */ "LCA Family", /* 4 */ "EV5 (21164)", /* 5 */ "EV45 (21064A)", /* 6 */ "EV56 (21164A)", /* 7 */ "EV6 (21264)", /* 8 */ "PCA56 (21164PC)", /* 9 */ "PCA57 (21164PC)", /* 10 */ "EV67 (21264A)", /* 11 */ "EV68CB (21264C)" /* 12 */ "EV68AL (21264B)", /* 13 */ "EV68CX (21264D)" /* 14 */ }; /* * print out CPU identification information. */ printf("%s\n%s, %ldMHz\n", platform.family, platform.model, hwrpb->rpb_cc_freq / 1000000); /* XXX true for 21164? */ printf("%ld byte page size, %d processor%s.\n", hwrpb->rpb_page_size, ncpus, ncpus == 1 ? "" : "s"); #if 0 /* this isn't defined for any systems that we run on? */ printf("serial number 0x%lx 0x%lx\n", ((long *)hwrpb->rpb_ssn)[0], ((long *)hwrpb->rpb_ssn)[1]); /* and these aren't particularly useful! */ printf("variation: 0x%lx, revision 0x%lx\n", hwrpb->rpb_variation, *(long *)hwrpb->rpb_revision); #endif pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); /* cpu type */ type = pcsp->pcs_proc_type; major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT; minor = (type & PCS_PROC_MINOR) >> PCS_PROC_MINORSHIFT; if (major < sizeof(cpuname)/sizeof(char *)) printf("CPU: %s major=%lu minor=%lu", cpuname[major], major, minor); else printf("CPU: major=%lu minor=%lu\n", major, minor); /* amask */ if (major >= PCS_PROC_EV56) { amask = 0xffffffff; /* 32 bit for printf */ amask = (~alpha_amask(amask)) & amask; printf(" extensions=0x%b\n", (u_int32_t) amask, "\020" "\001BWX" "\002FIX" "\003CIX" "\011MVI" "\012PRECISE" ); } else printf("\n"); /* PAL code */ printf("OSF PAL rev: 0x%lx\n", pcsp->pcs_palrevisions[PALvar_OSF1]); } extern char kernel_text[], _end[]; void alpha_init(pfn, ptb, bim, bip, biv) u_long pfn; /* first free PFN number */ u_long ptb; /* PFN of current level 1 page table */ u_long bim; /* bootinfo magic */ u_long bip; /* bootinfo pointer */ u_long biv; /* bootinfo version */ { int phys_avail_cnt; char *bootinfo_msg, *bootinfo_booted_kernel; vm_offset_t kernstart, kernend; vm_offset_t kernstartpfn, kernendpfn, pfn0, pfn1; struct mddt *mddtp; struct mddt_cluster *memc; int i, mddtweird; int cputype; char *p; /* NO OUTPUT ALLOWED UNTIL FURTHER NOTICE */ /* * Turn off interrupts (not mchecks) and floating point. * Make sure the instruction and data streams are consistent. */ (void)alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH); /* alpha_pal_wrfen(0); */ ALPHA_TBIA(); alpha_pal_imb(); /* * Get critical system information (if possible, from the * information provided by the boot program). */ bootinfo_msg = NULL; bootinfo_booted_kernel = NULL; if (bim == BOOTINFO_MAGIC) { if (biv == 0) { /* backward compat */ biv = *(u_long *)bip; bip += 8; } switch (biv) { case 1: { struct bootinfo_v1 *v1p = (struct bootinfo_v1 *)bip; bootinfo.ssym = v1p->ssym; bootinfo.esym = v1p->esym; bootinfo.kernend = v1p->kernend; bootinfo.modptr = v1p->modptr; bootinfo.envp = v1p->envp; /* hwrpb may not be provided by boot block in v1 */ if (v1p->hwrpb != NULL) { bootinfo.hwrpb_phys = ((struct rpb *)v1p->hwrpb)->rpb_phys; bootinfo.hwrpb_size = v1p->hwrpbsize; } else { bootinfo.hwrpb_phys = ((struct rpb *)HWRPB_ADDR)->rpb_phys; bootinfo.hwrpb_size = ((struct rpb *)HWRPB_ADDR)->rpb_size; } bcopy(v1p->boot_flags, bootinfo.boot_flags, min(sizeof v1p->boot_flags, sizeof bootinfo.boot_flags)); bcopy(v1p->booted_kernel, bootinfo.booted_kernel, min(sizeof v1p->booted_kernel, sizeof bootinfo.booted_kernel)); bootinfo_booted_kernel = bootinfo.booted_kernel; /* booted dev not provided in bootinfo */ init_prom_interface((struct rpb *) ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys)); prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev, sizeof bootinfo.booted_dev); break; } default: bootinfo_msg = "unknown bootinfo version"; goto nobootinfo; } } else { bootinfo_msg = "boot program did not pass bootinfo"; nobootinfo: bootinfo.ssym = (u_long)&_end; bootinfo.esym = (u_long)&_end; #ifdef SIMOS { char* p = (char*)bootinfo.ssym + 8; if (p[EI_MAG0] == ELFMAG0 && p[EI_MAG1] == ELFMAG1 && p[EI_MAG2] == ELFMAG2 && p[EI_MAG3] == ELFMAG3) { bootinfo.ssym = (u_long) p; bootinfo.esym = (u_long)p + *(u_long*)(p - 8); } } #endif bootinfo.hwrpb_phys = ((struct rpb *)HWRPB_ADDR)->rpb_phys; bootinfo.hwrpb_size = ((struct rpb *)HWRPB_ADDR)->rpb_size; init_prom_interface((struct rpb *)HWRPB_ADDR); prom_getenv(PROM_E_BOOTED_OSFLAGS, bootinfo.boot_flags, sizeof bootinfo.boot_flags); #ifndef SIMOS prom_getenv(PROM_E_BOOTED_FILE, bootinfo.booted_kernel, sizeof bootinfo.booted_kernel); #endif prom_getenv(PROM_E_BOOTED_DEV, bootinfo.booted_dev, sizeof bootinfo.booted_dev); } /* * Initialize the kernel's mapping of the RPB. It's needed for * lots of things. */ hwrpb = (struct rpb *)ALPHA_PHYS_TO_K0SEG(bootinfo.hwrpb_phys); /* * Remember how many cycles there are per microsecond, * so that we can use delay(). Round up, for safety. */ cycles_per_usec = (hwrpb->rpb_cc_freq + 999999) / 1000000; /* * Remember how many cycles per closk for coping with missed * clock interrupts. */ cycles_per_sec = hwrpb->rpb_cc_freq; /* Get the loader(8) metadata */ preload_metadata = (caddr_t)bootinfo.modptr; - kern_envp = bootinfo.envp; + if (envmode == 1) + kern_envp = static_env; + else + kern_envp = bootinfo.envp; /* Do basic tuning, hz etc */ init_param(); /* * Initalize the (temporary) bootstrap console interface, so * we can use printf until the VM system starts being setup. * The real console is initialized before then. */ init_bootstrap_console(); /* OUTPUT NOW ALLOWED */ /* delayed from above */ if (bootinfo_msg) printf("WARNING: %s (0x%lx, 0x%lx, 0x%lx)\n", bootinfo_msg, bim, bip, biv); /* * Point interrupt/exception vectors to our own. */ alpha_pal_wrent(XentInt, ALPHA_KENTRY_INT); alpha_pal_wrent(XentArith, ALPHA_KENTRY_ARITH); alpha_pal_wrent(XentMM, ALPHA_KENTRY_MM); alpha_pal_wrent(XentIF, ALPHA_KENTRY_IF); alpha_pal_wrent(XentUna, ALPHA_KENTRY_UNA); alpha_pal_wrent(XentSys, ALPHA_KENTRY_SYS); /* * Clear pending machine checks and error reports, and enable * system- and processor-correctable error reporting. */ alpha_pal_wrmces(alpha_pal_rdmces() & ~(ALPHA_MCES_DSC|ALPHA_MCES_DPC)); /* * Find out what hardware we're on, and do basic initialization. */ cputype = hwrpb->rpb_type; if (cputype < 0) { /* * At least some white-box (NT) systems have SRM which * reports a systype that's the negative of their * blue-box (UNIX/OVMS) counterpart. */ cputype = -cputype; } if (cputype >= API_ST_BASE) { if (cputype >= napi_cpuinit + API_ST_BASE) { platform_not_supported(cputype); /* NOTREACHED */ } cputype -= API_ST_BASE; api_cpuinit[cputype].init(cputype); } else { if (cputype >= ncpuinit) { platform_not_supported(cputype); /* NOTREACHED */ } cpuinit[cputype].init(cputype); } snprintf(cpu_model, sizeof(cpu_model), "%s", platform.model); /* * Initalize the real console, so the the bootstrap console is * no longer necessary. */ if (platform.cons_init) platform.cons_init(); /* NO MORE FIRMWARE ACCESS ALLOWED */ #ifdef _PMAP_MAY_USE_PROM_CONSOLE /* * XXX (unless _PMAP_MAY_USE_PROM_CONSOLE is defined and * XXX pmap_uses_prom_console() evaluates to non-zero.) */ #endif /* * find out this system's page size */ if (hwrpb->rpb_page_size != PAGE_SIZE) panic("page size %ld != 8192?!", hwrpb->rpb_page_size); /* * Find the beginning and end of the kernel (and leave a * bit of space before the beginning for the bootstrap * stack). */ kernstart = trunc_page(kernel_text) - 2 * PAGE_SIZE; #ifdef DDB ksym_start = (void *)bootinfo.ssym; ksym_end = (void *)bootinfo.esym; kernend = (vm_offset_t)round_page(ksym_end); #else kernend = (vm_offset_t)round_page(_end); #endif /* But if the bootstrap tells us otherwise, believe it! */ if (bootinfo.kernend) kernend = round_page(bootinfo.kernend); if (preload_metadata == NULL) printf("WARNING: loader(8) metadata is missing!\n"); kernstartpfn = atop(ALPHA_K0SEG_TO_PHYS(kernstart)); kernendpfn = atop(ALPHA_K0SEG_TO_PHYS(kernend)); #ifdef SIMOS /* * SimOS console puts the bootstrap stack after kernel */ kernendpfn += 4; #endif /* * Find out how much memory is available, by looking at * the memory cluster descriptors. This also tries to do * its best to detect things things that have never been seen * before... */ mddtp = (struct mddt *)(((caddr_t)hwrpb) + hwrpb->rpb_memdat_off); /* MDDT SANITY CHECKING */ mddtweird = 0; if (mddtp->mddt_cluster_cnt < 2) { mddtweird = 1; printf("WARNING: weird number of mem clusters: %ld\n", mddtp->mddt_cluster_cnt); } #ifdef DEBUG_CLUSTER printf("Memory cluster count: %d\n", mddtp->mddt_cluster_cnt); #endif phys_avail_cnt = 0; for (i = 0; i < mddtp->mddt_cluster_cnt; i++) { memc = &mddtp->mddt_clusters[i]; #ifdef DEBUG_CLUSTER printf("MEMC %d: pfn 0x%lx cnt 0x%lx usage 0x%lx\n", i, memc->mddt_pfn, memc->mddt_pg_cnt, memc->mddt_usage); #endif totalphysmem += memc->mddt_pg_cnt; if (memc->mddt_usage & MDDT_mbz) { mddtweird = 1; printf("WARNING: mem cluster %d has weird " "usage 0x%lx\n", i, memc->mddt_usage); unknownmem += memc->mddt_pg_cnt; continue; } if (memc->mddt_usage & MDDT_NONVOLATILE) { /* XXX should handle these... */ printf("WARNING: skipping non-volatile mem " "cluster %d\n", i); unusedmem += memc->mddt_pg_cnt; continue; } if (memc->mddt_usage & MDDT_PALCODE) { resvmem += memc->mddt_pg_cnt; continue; } /* * We have a memory cluster available for system * software use. We must determine if this cluster * holds the kernel. */ /* * XXX If the kernel uses the PROM console, we only use the * XXX memory after the kernel in the first system segment, * XXX to avoid clobbering prom mapping, data, etc. */ physmem += memc->mddt_pg_cnt; pfn0 = memc->mddt_pfn; pfn1 = memc->mddt_pfn + memc->mddt_pg_cnt; if (pfn0 <= kernendpfn && kernstartpfn <= pfn1) { /* * Must compute the location of the kernel * within the segment. */ #ifdef DEBUG_CLUSTER printf("Cluster %d contains kernel\n", i); #endif if (!pmap_uses_prom_console()) { if (pfn0 < kernstartpfn) { /* * There is a chunk before the kernel. */ #ifdef DEBUG_CLUSTER printf("Loading chunk before kernel: " "0x%lx / 0x%lx\n", pfn0, kernstartpfn); #endif phys_avail[phys_avail_cnt] = alpha_ptob(pfn0); phys_avail[phys_avail_cnt+1] = alpha_ptob(kernstartpfn); phys_avail_cnt += 2; } } if (kernendpfn < pfn1) { /* * There is a chunk after the kernel. */ #ifdef DEBUG_CLUSTER printf("Loading chunk after kernel: " "0x%lx / 0x%lx\n", kernendpfn, pfn1); #endif phys_avail[phys_avail_cnt] = alpha_ptob(kernendpfn); phys_avail[phys_avail_cnt+1] = alpha_ptob(pfn1); phys_avail_cnt += 2; } } else { /* * Just load this cluster as one chunk. */ #ifdef DEBUG_CLUSTER printf("Loading cluster %d: 0x%lx / 0x%lx\n", i, pfn0, pfn1); #endif phys_avail[phys_avail_cnt] = alpha_ptob(pfn0); phys_avail[phys_avail_cnt+1] = alpha_ptob(pfn1); phys_avail_cnt += 2; } } phys_avail[phys_avail_cnt] = 0; /* * Dump out the MDDT if it looks odd... */ if (mddtweird) { printf("\n"); printf("complete memory cluster information:\n"); for (i = 0; i < mddtp->mddt_cluster_cnt; i++) { printf("mddt %d:\n", i); printf("\tpfn %lx\n", mddtp->mddt_clusters[i].mddt_pfn); printf("\tcnt %lx\n", mddtp->mddt_clusters[i].mddt_pg_cnt); printf("\ttest %lx\n", mddtp->mddt_clusters[i].mddt_pg_test); printf("\tbva %lx\n", mddtp->mddt_clusters[i].mddt_v_bitaddr); printf("\tbpa %lx\n", mddtp->mddt_clusters[i].mddt_p_bitaddr); printf("\tbcksum %lx\n", mddtp->mddt_clusters[i].mddt_bit_cksum); printf("\tusage %lx\n", mddtp->mddt_clusters[i].mddt_usage); } printf("\n"); } Maxmem = physmem; /* * Initialize error message buffer (at end of core). */ { size_t sz = round_page(MSGBUF_SIZE); int i = phys_avail_cnt - 2; /* shrink so that it'll fit in the last segment */ if (phys_avail[i+1] - phys_avail[i] < sz) sz = phys_avail[i+1] - phys_avail[i]; phys_avail[i+1] -= sz; msgbufp = (struct msgbuf*) ALPHA_PHYS_TO_K0SEG(phys_avail[i+1]); msgbufinit(msgbufp, sz); /* Remove the last segment if it now has no pages. */ if (phys_avail[i] == phys_avail[i+1]) phys_avail[i] = 0; /* warn if the message buffer had to be shrunk */ if (sz != round_page(MSGBUF_SIZE)) printf("WARNING: %ld bytes not available for msgbuf in last cluster (%ld used)\n", round_page(MSGBUF_SIZE), sz); } /* * Init mapping for u page(s) for proc 0 */ proc0.p_addr = proc0paddr = (struct user *)pmap_steal_memory(UPAGES * PAGE_SIZE); /* * Setup the global data for the bootstrap cpu. */ { size_t sz = round_page(UPAGES * PAGE_SIZE); globalp = (struct globaldata *) pmap_steal_memory(sz); globaldata_init(globalp, alpha_pal_whami(), sz); alpha_pal_wrval((u_int64_t) globalp); PCPU_GET(next_asn) = 1; /* 0 used for proc0 pmap */ #ifdef SMP proc0.p_md.md_kernnest = 1; #endif } /* * Initialize the virtual memory system, and set the * page table base register in proc 0's PCB. */ pmap_bootstrap(ALPHA_PHYS_TO_K0SEG(alpha_ptob(ptb)), hwrpb->rpb_max_asn); hwrpb->rpb_vptb = VPTBASE; hwrpb->rpb_checksum = hwrpb_checksum(); /* * Initialize the rest of proc 0's PCB, and cache its physical * address. */ proc0.p_md.md_pcbpaddr = (struct pcb *)ALPHA_K0SEG_TO_PHYS((vm_offset_t)&proc0paddr->u_pcb); /* * Set the kernel sp, reserving space for an (empty) trapframe, * and make proc0's trapframe pointer point to it for sanity. */ proc0paddr->u_pcb.pcb_hw.apcb_ksp = (u_int64_t)proc0paddr + USPACE - sizeof(struct trapframe); proc0.p_frame = (struct trapframe *)proc0paddr->u_pcb.pcb_hw.apcb_ksp; /* * Get the right value for the boot cpu's idle ptbr. */ globalp->gd_idlepcb.apcb_ptbr = proc0.p_addr->u_pcb.pcb_hw.apcb_ptbr; /* Setup curproc so that mutexes work */ PCPU_SET(curproc, &proc0); PCPU_SET(spinlocks, NULL); LIST_INIT(&proc0.p_contested); /* * Initialise mutexes. */ mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE); mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE); mtx_init(&proc0.p_mtx, "process lock", MTX_DEF); mtx_init(&clock_lock, "clk", MTX_SPIN | MTX_RECURSE); mtx_lock(&Giant); /* * Look at arguments passed to us and compute boothowto. */ #ifdef KADB boothowto |= RB_KDB; #endif /* boothowto |= RB_KDB | RB_GDB; */ for (p = bootinfo.boot_flags; p && *p != '\0'; p++) { /* * Note that we'd really like to differentiate case here, * but the Alpha AXP Architecture Reference Manual * says that we shouldn't. */ switch (*p) { case 'a': /* autoboot */ case 'A': boothowto &= ~RB_SINGLE; break; #ifdef DEBUG case 'c': /* crash dump immediately after autoconfig */ case 'C': boothowto |= RB_DUMP; break; #endif #if defined(DDB) case 'd': /* break into the kernel debugger ASAP */ case 'D': boothowto |= RB_KDB; break; case 'g': /* use kernel gdb */ case 'G': boothowto |= RB_GDB; break; #endif case 'h': /* always halt, never reboot */ case 'H': boothowto |= RB_HALT; break; #if 0 case 'm': /* mini root present in memory */ case 'M': boothowto |= RB_MINIROOT; break; #endif case 'n': /* askname */ case 'N': boothowto |= RB_ASKNAME; break; case 's': /* single-user (default, supported for sanity) */ case 'S': boothowto |= RB_SINGLE; break; case 'v': case 'V': boothowto |= RB_VERBOSE; bootverbose = 1; break; default: printf("Unrecognized boot flag '%c'.\n", *p); break; } } /* * Catch case of boot_verbose set in environment. */ if ((p = getenv("boot_verbose")) != NULL) { if (strcmp(p, "yes") == 0 || strcmp(p, "YES") == 0) { boothowto |= RB_VERBOSE; bootverbose = 1; } } /* * Pick up kernelname. */ if (bootinfo_booted_kernel) { strncpy(kernelname, bootinfo_booted_kernel, min(sizeof(kernelname), sizeof bootinfo.booted_kernel) - 1); } else if ((p = getenv("kernelname")) != NULL) { strncpy(kernelname, p, sizeof(kernelname) - 1); } /* * Initialize debuggers, and break into them if appropriate. */ #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { printf("Boot flags requested debugger\n"); breakpoint(); } #endif /* * Figure out the number of cpus in the box, from RPB fields. * Really. We mean it. */ for (i = 0; i < hwrpb->rpb_pcs_cnt; i++) { struct pcs *pcsp; pcsp = (struct pcs *)((char *)hwrpb + hwrpb->rpb_pcs_off + (i * hwrpb->rpb_pcs_size)); if ((pcsp->pcs_flags & PCS_PP) != 0) ncpus++; } /* * Figure out our clock frequency, from RPB fields. */ hz = hwrpb->rpb_intr_freq >> 12; if (!(60 <= hz && hz <= 10240)) { hz = 1024; #ifdef DIAGNOSTIC printf("WARNING: unbelievable rpb_intr_freq: %ld (%d hz)\n", hwrpb->rpb_intr_freq, hz); #endif } hwrpb_restart_setup(); alpha_pal_wrfen(0); } void bzero(void *buf, size_t len) { caddr_t p = buf; while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) { *p++ = 0; len--; } while (len >= sizeof(u_long) * 8) { *(u_long*) p = 0; *((u_long*) p + 1) = 0; *((u_long*) p + 2) = 0; *((u_long*) p + 3) = 0; len -= sizeof(u_long) * 8; *((u_long*) p + 4) = 0; *((u_long*) p + 5) = 0; *((u_long*) p + 6) = 0; *((u_long*) p + 7) = 0; p += sizeof(u_long) * 8; } while (len >= sizeof(u_long)) { *(u_long*) p = 0; len -= sizeof(u_long); p += sizeof(u_long); } while (len) { *p++ = 0; len--; } } void DELAY(int n) { #ifndef SIMOS unsigned long pcc0, pcc1, curcycle, cycles; int usec; if (n == 0) return; pcc0 = alpha_rpcc() & 0xffffffffUL; cycles = 0; usec = 0; while (usec <= n) { /* * Get the next CPU cycle count. The assumption here * is that we can't have wrapped twice past 32 bits worth * of CPU cycles since we last checked. */ pcc1 = alpha_rpcc() & 0xffffffffUL; if (pcc1 < pcc0) { curcycle = (pcc1 + 0x100000000UL) - pcc0; } else { curcycle = pcc1 - pcc0; } /* * We now have the number of processor cycles since we * last checked. Add the current cycle count to the * running total. If it's over cycles_per_usec, increment * the usec counter. */ cycles += curcycle; while (cycles > cycles_per_usec) { usec++; cycles -= cycles_per_usec; } pcc0 = pcc1; } #endif } /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ #ifdef COMPAT_43 void osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { struct proc *p = curproc; osiginfo_t *sip, ksi; struct trapframe *frame; struct sigacts *psp; int oonstack, fsize, rndfsize; frame = p->p_frame; oonstack = sigonstack(alpha_pal_rdusp()); fsize = sizeof ksi; rndfsize = ((fsize + 15) / 16) * 16; PROC_LOCK_ASSERT(p, MA_OWNED); psp = p->p_sigacts; /* * Allocate and validate space for the signal handler * context. Note that if the stack is in P0 space, the * call to grow() is a nop, and the useracc() check * will fail if the process has not already allocated * the space with a `brk'. */ if ((p->p_flag & P_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sip = (osiginfo_t *)((caddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size - rndfsize); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sip = (osiginfo_t *)(alpha_pal_rdusp() - rndfsize); PROC_UNLOCK(p); (void)grow_stack(p, (u_long)sip); if (!useracc((caddr_t)sip, fsize, VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* * Build the signal context to be used by sigreturn. */ ksi.si_sc.sc_onstack = (oonstack) ? 1 : 0; SIG2OSIG(*mask, ksi.si_sc.sc_mask); ksi.si_sc.sc_pc = frame->tf_regs[FRAME_PC]; ksi.si_sc.sc_ps = frame->tf_regs[FRAME_PS]; /* copy the registers. */ fill_regs(p, (struct reg *)ksi.si_sc.sc_regs); ksi.si_sc.sc_regs[R_ZERO] = 0xACEDBADE; /* magic number */ ksi.si_sc.sc_regs[R_SP] = alpha_pal_rdusp(); /* save the floating-point state, if necessary, then copy it. */ alpha_fpstate_save(p, 1); /* XXX maybe write=0 */ ksi.si_sc.sc_ownedfp = p->p_md.md_flags & MDP_FPUSED; bcopy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)ksi.si_sc.sc_fpregs, sizeof(struct fpreg)); ksi.si_sc.sc_fp_control = p->p_addr->u_pcb.pcb_fp_control; bzero(ksi.si_sc.sc_reserved, sizeof ksi.si_sc.sc_reserved); /* XXX */ ksi.si_sc.sc_xxx1[0] = 0; /* XXX */ ksi.si_sc.sc_xxx1[1] = 0; /* XXX */ ksi.si_sc.sc_traparg_a0 = frame->tf_regs[FRAME_TRAPARG_A0]; ksi.si_sc.sc_traparg_a1 = frame->tf_regs[FRAME_TRAPARG_A1]; ksi.si_sc.sc_traparg_a2 = frame->tf_regs[FRAME_TRAPARG_A2]; ksi.si_sc.sc_xxx2[0] = 0; /* XXX */ ksi.si_sc.sc_xxx2[1] = 0; /* XXX */ ksi.si_sc.sc_xxx2[2] = 0; /* XXX */ /* Fill in POSIX parts */ ksi.si_signo = sig; ksi.si_code = code; ksi.si_value.sigval_ptr = NULL; /* XXX */ /* * copy the frame out to userland. */ (void) copyout((caddr_t)&ksi, (caddr_t)sip, fsize); /* * Set up the registers to return to sigcode. */ frame->tf_regs[FRAME_PC] = PS_STRINGS - (esigcode - sigcode); frame->tf_regs[FRAME_A0] = sig; frame->tf_regs[FRAME_FLAGS] = 0; /* full restore */ PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) frame->tf_regs[FRAME_A1] = (u_int64_t)sip; else frame->tf_regs[FRAME_A1] = code; PROC_UNLOCK(p); frame->tf_regs[FRAME_A2] = (u_int64_t)&sip->si_sc; frame->tf_regs[FRAME_T12] = (u_int64_t)catcher; /* t12 is pv */ alpha_pal_wrusp((unsigned long)sip); } #endif void sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { struct proc *p = curproc; struct trapframe *frame; struct sigacts *psp; struct sigframe sf, *sfp; int oonstack, rndfsize; PROC_LOCK(p); psp = p->p_sigacts; #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { osendsig(catcher, sig, mask, code); return; } #endif frame = p->p_frame; oonstack = sigonstack(alpha_pal_rdusp()); rndfsize = ((sizeof(sf) + 15) / 16) * 16; /* save user context */ bzero(&sf, sizeof(struct sigframe)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; fill_regs(p, (struct reg *)sf.sf_uc.uc_mcontext.mc_regs); sf.sf_uc.uc_mcontext.mc_regs[R_SP] = alpha_pal_rdusp(); sf.sf_uc.uc_mcontext.mc_regs[R_ZERO] = 0xACEDBADE; /* magic number */ sf.sf_uc.uc_mcontext.mc_regs[R_PS] = frame->tf_regs[FRAME_PS]; sf.sf_uc.uc_mcontext.mc_regs[R_PC] = frame->tf_regs[FRAME_PC]; sf.sf_uc.uc_mcontext.mc_regs[R_TRAPARG_A0] = frame->tf_regs[FRAME_TRAPARG_A0]; sf.sf_uc.uc_mcontext.mc_regs[R_TRAPARG_A1] = frame->tf_regs[FRAME_TRAPARG_A1]; sf.sf_uc.uc_mcontext.mc_regs[R_TRAPARG_A2] = frame->tf_regs[FRAME_TRAPARG_A2]; /* * Allocate and validate space for the signal handler * context. Note that if the stack is in P0 space, the * call to grow() is a nop, and the useracc() check * will fail if the process has not already allocated * the space with a `brk'. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)((caddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size - rndfsize); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sfp = (struct sigframe *)(alpha_pal_rdusp() - rndfsize); PROC_UNLOCK(p); (void)grow_stack(p, (u_long)sfp); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, sig, &sf, sfp); #endif if (!useracc((caddr_t)sfp, sizeof(sf), VM_PROT_WRITE)) { #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): useracc failed on sig %d\n", p->p_pid, sig); #endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* save the floating-point state, if necessary, then copy it. */ alpha_fpstate_save(p, 1); sf.sf_uc.uc_mcontext.mc_ownedfp = p->p_md.md_flags & MDP_FPUSED; bcopy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)sf.sf_uc.uc_mcontext.mc_fpregs, sizeof(struct fpreg)); sf.sf_uc.uc_mcontext.mc_fp_control = p->p_addr->u_pcb.pcb_fp_control; #ifdef COMPAT_OSF1 /* * XXX Create an OSF/1-style sigcontext and associated goo. */ #endif /* * copy the frame out to userland. */ (void) copyout((caddr_t)&sf, (caddr_t)sfp, sizeof(sf)); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): sig %d sfp %p code %lx\n", p->p_pid, sig, sfp, code); #endif /* * Set up the registers to return to sigcode. */ frame->tf_regs[FRAME_PC] = PS_STRINGS - (esigcode - sigcode); frame->tf_regs[FRAME_A0] = sig; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { frame->tf_regs[FRAME_A1] = (u_int64_t)&(sfp->sf_si); /* Fill in POSIX parts */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void*)frame->tf_regs[FRAME_TRAPARG_A0]; } else frame->tf_regs[FRAME_A1] = code; PROC_UNLOCK(p); frame->tf_regs[FRAME_A2] = (u_int64_t)&(sfp->sf_uc); frame->tf_regs[FRAME_T12] = (u_int64_t)catcher; /* t12 is pv */ frame->tf_regs[FRAME_FLAGS] = 0; /* full restore */ alpha_pal_wrusp((unsigned long)sfp); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): pc %lx, catcher %lx\n", p->p_pid, frame->tf_regs[FRAME_PC], frame->tf_regs[FRAME_A3]); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ #ifdef COMPAT_43 int osigreturn(struct proc *p, struct osigreturn_args /* { struct osigcontext *sigcntxp; } */ *uap) { struct osigcontext *scp, ksc; scp = uap->sigcntxp; /* * Fetch the entire context structure at once for speed. */ if (copyin((caddr_t)scp, (caddr_t)&ksc, sizeof ksc)) return (EFAULT); /* * XXX - Should we do this. What if we get a "handcrafted" * but valid sigcontext that hasn't the magic number? */ if (ksc.sc_regs[R_ZERO] != 0xACEDBADE) /* magic number */ return (EINVAL); PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) /* * Restore the user-supplied information */ if (ksc.sc_onstack) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif /* * longjmp is still implemented by calling osigreturn. The new * sigmask is stored in sc_reserved, sc_mask is only used for * backward compatibility. */ SIGSETOLD(p->p_sigmask, ksc.sc_mask); SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); set_regs(p, (struct reg *)ksc.sc_regs); p->p_frame->tf_regs[FRAME_PC] = ksc.sc_pc; p->p_frame->tf_regs[FRAME_PS] = (ksc.sc_ps | ALPHA_PSL_USERSET) & ~ALPHA_PSL_USERCLR; p->p_frame->tf_regs[FRAME_FLAGS] = 0; /* full restore */ alpha_pal_wrusp(ksc.sc_regs[R_SP]); /* XXX ksc.sc_ownedfp ? */ alpha_fpstate_drop(p); bcopy((struct fpreg *)ksc.sc_fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); p->p_addr->u_pcb.pcb_fp_control = ksc.sc_fp_control; return (EJUSTRETURN); } #endif int sigreturn(struct proc *p, struct sigreturn_args /* { ucontext_t *sigcntxp; } */ *uap) { ucontext_t uc, *ucp; struct pcb *pcb; unsigned long val; #ifdef COMPAT_43 if (((struct osigcontext*)uap->sigcntxp)->sc_regs[R_ZERO] == 0xACEDBADE) return osigreturn(p, (struct osigreturn_args *)uap); #endif ucp = uap->sigcntxp; pcb = &p->p_addr->u_pcb; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn: pid %d, scp %p\n", p->p_pid, ucp); #endif /* * Fetch the entire context structure at once for speed. */ if (copyin((caddr_t)ucp, (caddr_t)&uc, sizeof(ucontext_t))) return (EFAULT); /* * Restore the user-supplied information */ set_regs(p, (struct reg *)uc.uc_mcontext.mc_regs); val = (uc.uc_mcontext.mc_regs[R_PS] | ALPHA_PSL_USERSET) & ~ALPHA_PSL_USERCLR; p->p_frame->tf_regs[FRAME_PS] = val; p->p_frame->tf_regs[FRAME_PC] = uc.uc_mcontext.mc_regs[R_PC]; p->p_frame->tf_regs[FRAME_FLAGS] = 0; /* full restore */ alpha_pal_wrusp(uc.uc_mcontext.mc_regs[R_SP]); PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (uc.uc_mcontext.mc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif p->p_sigmask = uc.uc_sigmask; SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); /* XXX ksc.sc_ownedfp ? */ alpha_fpstate_drop(p); bcopy((struct fpreg *)uc.uc_mcontext.mc_fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); p->p_addr->u_pcb.pcb_fp_control = uc.uc_mcontext.mc_fp_control; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn(%d): returns\n", p->p_pid); #endif return (EJUSTRETURN); } /* * Machine dependent boot() routine * * I haven't seen anything to put here yet * Possibly some stuff might be grafted back here from boot() */ void cpu_boot(int howto) { } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { prom_halt(1); } /* * Clear registers on exec */ void setregs(struct proc *p, u_long entry, u_long stack, u_long ps_strings) { struct trapframe *tfp = p->p_frame; bzero(tfp->tf_regs, FRAME_SIZE * sizeof tfp->tf_regs[0]); bzero(&p->p_addr->u_pcb.pcb_fp, sizeof p->p_addr->u_pcb.pcb_fp); p->p_addr->u_pcb.pcb_fp_control = 0; p->p_addr->u_pcb.pcb_fp.fpr_cr = (FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED | FPCR_UNFD); alpha_pal_wrusp(stack); tfp->tf_regs[FRAME_PS] = ALPHA_PSL_USERSET; tfp->tf_regs[FRAME_PC] = entry & ~3; tfp->tf_regs[FRAME_A0] = stack; /* a0 = sp */ tfp->tf_regs[FRAME_A1] = 0; /* a1 = rtld cleanup */ tfp->tf_regs[FRAME_A2] = 0; /* a2 = rtld object */ tfp->tf_regs[FRAME_A3] = PS_STRINGS; /* a3 = ps_strings */ tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC]; /* a.k.a. PV */ tfp->tf_regs[FRAME_FLAGS] = 0; /* full restore */ p->p_md.md_flags &= ~MDP_FPUSED; alpha_fpstate_drop(p); } int ptrace_set_pc(struct proc *p, unsigned long addr) { struct trapframe *tp = p->p_frame; tp->tf_regs[FRAME_PC] = addr; return 0; } static int ptrace_read_int(struct proc *p, vm_offset_t addr, u_int32_t *v) { struct iovec iov; struct uio uio; iov.iov_base = (caddr_t) v; iov.iov_len = sizeof(u_int32_t); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = (off_t)addr; uio.uio_resid = sizeof(u_int32_t); uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_READ; uio.uio_procp = p; return procfs_domem(curproc, p, NULL, &uio); } static int ptrace_write_int(struct proc *p, vm_offset_t addr, u_int32_t v) { struct iovec iov; struct uio uio; iov.iov_base = (caddr_t) &v; iov.iov_len = sizeof(u_int32_t); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = (off_t)addr; uio.uio_resid = sizeof(u_int32_t); uio.uio_segflg = UIO_SYSSPACE; uio.uio_rw = UIO_WRITE; uio.uio_procp = p; return procfs_domem(curproc, p, NULL, &uio); } static u_int64_t ptrace_read_register(struct proc *p, int regno) { static int reg_to_frame[32] = { FRAME_V0, FRAME_T0, FRAME_T1, FRAME_T2, FRAME_T3, FRAME_T4, FRAME_T5, FRAME_T6, FRAME_T7, FRAME_S0, FRAME_S1, FRAME_S2, FRAME_S3, FRAME_S4, FRAME_S5, FRAME_S6, FRAME_A0, FRAME_A1, FRAME_A2, FRAME_A3, FRAME_A4, FRAME_A5, FRAME_T8, FRAME_T9, FRAME_T10, FRAME_T11, FRAME_RA, FRAME_T12, FRAME_AT, FRAME_GP, FRAME_SP, -1, /* zero */ }; if (regno == R_ZERO) return 0; return p->p_frame->tf_regs[reg_to_frame[regno]]; } static int ptrace_clear_bpt(struct proc *p, struct mdbpt *bpt) { return ptrace_write_int(p, bpt->addr, bpt->contents); } static int ptrace_set_bpt(struct proc *p, struct mdbpt *bpt) { int error; u_int32_t bpins = 0x00000080; error = ptrace_read_int(p, bpt->addr, &bpt->contents); if (error) return error; return ptrace_write_int(p, bpt->addr, bpins); } int ptrace_clear_single_step(struct proc *p) { if (p->p_md.md_flags & MDP_STEP2) { ptrace_clear_bpt(p, &p->p_md.md_sstep[1]); ptrace_clear_bpt(p, &p->p_md.md_sstep[0]); p->p_md.md_flags &= ~MDP_STEP2; } else if (p->p_md.md_flags & MDP_STEP1) { ptrace_clear_bpt(p, &p->p_md.md_sstep[0]); p->p_md.md_flags &= ~MDP_STEP1; } return 0; } int ptrace_single_step(struct proc *p) { int error; vm_offset_t pc = p->p_frame->tf_regs[FRAME_PC]; alpha_instruction ins; vm_offset_t addr[2]; /* places to set breakpoints */ int count = 0; /* count of breakpoints */ if (p->p_md.md_flags & (MDP_STEP1|MDP_STEP2)) panic("ptrace_single_step: step breakpoints not removed"); error = ptrace_read_int(p, pc, &ins.bits); if (error) return error; switch (ins.branch_format.opcode) { case op_j: /* Jump: target is register value */ addr[0] = ptrace_read_register(p, ins.jump_format.rs) & ~3; count = 1; break; case op_br: case op_fbeq: case op_fblt: case op_fble: case op_bsr: case op_fbne: case op_fbge: case op_fbgt: case op_blbc: case op_beq: case op_blt: case op_ble: case op_blbs: case op_bne: case op_bge: case op_bgt: /* Branch: target is pc+4+4*displacement */ addr[0] = pc + 4; addr[1] = pc + 4 + 4 * ins.branch_format.displacement; count = 2; break; default: addr[0] = pc + 4; count = 1; } p->p_md.md_sstep[0].addr = addr[0]; error = ptrace_set_bpt(p, &p->p_md.md_sstep[0]); if (error) return error; if (count == 2) { p->p_md.md_sstep[1].addr = addr[1]; error = ptrace_set_bpt(p, &p->p_md.md_sstep[1]); if (error) { ptrace_clear_bpt(p, &p->p_md.md_sstep[0]); return error; } p->p_md.md_flags |= MDP_STEP2; } else p->p_md.md_flags |= MDP_STEP1; return 0; } int alpha_pa_access(vm_offset_t pa) { #if 0 int i; for (i = 0; phys_avail[i] != 0; i += 2) { if (pa < phys_avail[i]) continue; if (pa < phys_avail[i+1]) return VM_PROT_READ|VM_PROT_WRITE; } return 0; #else return VM_PROT_READ|VM_PROT_WRITE; #endif } int fill_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb = &p->p_addr->u_pcb; struct trapframe *tp = p->p_frame; tp = p->p_frame; #define C(r) regs->r_regs[R_ ## r] = tp->tf_regs[FRAME_ ## r] C(V0); C(T0); C(T1); C(T2); C(T3); C(T4); C(T5); C(T6); C(T7); C(S0); C(S1); C(S2); C(S3); C(S4); C(S5); C(S6); C(A0); C(A1); C(A2); C(A3); C(A4); C(A5); C(T8); C(T9); C(T10); C(T11); C(RA); C(T12); C(AT); C(GP); #undef C regs->r_regs[R_ZERO] = tp->tf_regs[FRAME_PC]; regs->r_regs[R_SP] = pcb->pcb_hw.apcb_usp; return (0); } int set_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb = &p->p_addr->u_pcb; struct trapframe *tp = p->p_frame; tp = p->p_frame; #define C(r) tp->tf_regs[FRAME_ ## r] = regs->r_regs[R_ ## r] C(V0); C(T0); C(T1); C(T2); C(T3); C(T4); C(T5); C(T6); C(T7); C(S0); C(S1); C(S2); C(S3); C(S4); C(S5); C(S6); C(A0); C(A1); C(A2); C(A3); C(A4); C(A5); C(T8); C(T9); C(T10); C(T11); C(RA); C(T12); C(AT); C(GP); #undef C tp->tf_regs[FRAME_PC] = regs->r_regs[R_ZERO]; pcb->pcb_hw.apcb_usp = regs->r_regs[R_SP]; return (0); } int fill_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { alpha_fpstate_save(p, 0); bcopy(&p->p_addr->u_pcb.pcb_fp, fpregs, sizeof *fpregs); return (0); } int set_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { alpha_fpstate_drop(p); bcopy(fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof *fpregs); return (0); } #ifndef DDB void Debugger(const char *msg) { printf("Debugger(\"%s\") called.\n", msg); } #endif /* no DDB */ #include /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. Adjust transfer * if needed, and signal errors or early completion. */ int bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel) { struct partition *p = lp->d_partitions + dkpart(bp->bio_dev); int labelsect = lp->d_partitions[0].p_offset; int maxsz = p->p_size, sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect && #endif (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #endif /* beyond partition? */ if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->bio_blkno == maxsz) { bp->bio_resid = bp->bio_bcount; return(0); } /* or truncate if part of it fits */ sz = maxsz - bp->bio_blkno; if (sz <= 0) { bp->bio_error = EINVAL; goto bad; } bp->bio_bcount = sz << DEV_BSHIFT; } bp->bio_pblkno = bp->bio_blkno + p->p_offset; return(1); bad: bp->bio_flags |= BIO_ERROR; return(-1); } static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) { int error; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (!error && req->newptr) resettodr(); return (error); } SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 0, ""); SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, &wall_cmos_clock, 0, ""); void alpha_fpstate_check(struct proc *p) { /* * For SMP, we should check the fpcurproc of each cpu. */ #ifndef SMP critical_t s; s = critical_enter(); if (p->p_addr->u_pcb.pcb_hw.apcb_flags & ALPHA_PCB_FLAGS_FEN) if (p != PCPU_GET(fpcurproc)) panic("alpha_check_fpcurproc: bogus"); critical_exit(s); #endif } #define SET_FEN(p) \ (p)->p_addr->u_pcb.pcb_hw.apcb_flags |= ALPHA_PCB_FLAGS_FEN #define CLEAR_FEN(p) \ (p)->p_addr->u_pcb.pcb_hw.apcb_flags &= ~ALPHA_PCB_FLAGS_FEN /* * Save the floating point state in the pcb. Use this to get read-only * access to the floating point state. If write is true, the current * fp process is cleared so that fp state can safely be modified. The * process will automatically reload the changed state by generating a * FEN trap. */ void alpha_fpstate_save(struct proc *p, int write) { critical_t s; s = critical_enter(); if (p != NULL && p == PCPU_GET(fpcurproc)) { /* * If curproc != fpcurproc, then we need to enable FEN * so that we can dump the fp state. */ alpha_pal_wrfen(1); /* * Save the state in the pcb. */ savefpstate(&p->p_addr->u_pcb.pcb_fp); if (write) { /* * If fpcurproc == curproc, just ask the * PALcode to disable FEN, otherwise we must * clear the FEN bit in fpcurproc's pcb. */ if (PCPU_GET(fpcurproc) == curproc) alpha_pal_wrfen(0); else CLEAR_FEN(PCPU_GET(fpcurproc)); PCPU_SET(fpcurproc, NULL); } else { /* * Make sure that we leave FEN enabled if * curproc == fpcurproc. We must have at most * one process with FEN enabled. Note that FEN * must already be set in fpcurproc's pcb. */ if (curproc != PCPU_GET(fpcurproc)) alpha_pal_wrfen(0); } } critical_exit(s); } /* * Relinquish ownership of the FP state. This is called instead of * alpha_save_fpstate() if the entire FP state is being changed * (e.g. on sigreturn). */ void alpha_fpstate_drop(struct proc *p) { critical_t s; s = critical_enter(); if (p == PCPU_GET(fpcurproc)) { if (p == curproc) { /* * Disable FEN via the PALcode. This will * clear the bit in the pcb as well. */ alpha_pal_wrfen(0); } else { /* * Clear the FEN bit of the pcb. */ CLEAR_FEN(p); } PCPU_SET(fpcurproc, NULL); } critical_exit(s); } /* * Switch the current owner of the fp state to p, reloading the state * from the pcb. */ void alpha_fpstate_switch(struct proc *p) { critical_t s; /* * Enable FEN so that we can access the fp registers. */ s = critical_enter(); alpha_pal_wrfen(1); if (PCPU_GET(fpcurproc)) { /* * Dump the old fp state if its valid. */ savefpstate(&PCPU_GET(fpcurproc)->p_addr->u_pcb.pcb_fp); CLEAR_FEN(PCPU_GET(fpcurproc)); } /* * Remember the new FP owner and reload its state. */ PCPU_SET(fpcurproc, p); restorefpstate(&PCPU_GET(fpcurproc)->p_addr->u_pcb.pcb_fp); /* * If the new owner is curproc, leave FEN enabled, otherwise * mark its PCB so that it gets FEN when we context switch to * it later. */ if (p != curproc) { alpha_pal_wrfen(0); SET_FEN(p); } p->p_md.md_flags |= MDP_FPUSED; critical_exit(s); } /* * Initialise a struct globaldata. */ void globaldata_init(struct globaldata *globaldata, int cpuid, size_t sz) { bzero(globaldata, sz); globaldata->gd_idlepcbphys = vtophys((vm_offset_t) &globaldata->gd_idlepcb); globaldata->gd_idlepcb.apcb_ksp = (u_int64_t) ((caddr_t) globaldata + sz - sizeof(struct trapframe)); globaldata->gd_idlepcb.apcb_ptbr = proc0.p_addr->u_pcb.pcb_hw.apcb_ptbr; globaldata->gd_cpuid = cpuid; globaldata->gd_next_asn = 0; globaldata->gd_current_asngen = 1; globaldata_register(globaldata); } Index: head/sys/amd64/amd64/machdep.c =================================================================== --- head/sys/amd64/amd64/machdep.c (revision 82392) +++ head/sys/amd64/amd64/machdep.c (revision 82393) @@ -1,2534 +1,2536 @@ /*- * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD$ */ #include "opt_atalk.h" #include "opt_compat.h" #include "opt_cpu.h" #include "opt_ddb.h" #include "opt_inet.h" #include "opt_ipx.h" #include "opt_isa.h" #include "opt_maxmem.h" #include "opt_msgbuf.h" #include "opt_npx.h" #include "opt_perfmon.h" #include "opt_upages.h" /* #include "opt_userconfig.h" */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* pcb.h included via sys/user.h */ #include #ifdef PERFMON #include #endif #ifdef SMP #include #endif #include #include #include #include #include #include extern void init386 __P((int first)); extern void dblfault_handler __P((void)); extern void printcpuinfo(void); /* XXX header file */ extern void earlysetcpuclass(void); /* same header file */ extern void finishidentcpu(void); extern void panicifcpuunsupported(void); extern void initializecpu(void); #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) #define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) static void cpu_startup __P((void *)); #ifdef CPU_ENABLE_SSE static void set_fpregs_xmm __P((struct save87 *, struct savexmm *)); static void fill_fpregs_xmm __P((struct savexmm *, struct save87 *)); #endif /* CPU_ENABLE_SSE */ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL) int _udatasel, _ucodesel; u_int atdevbase; #if defined(SWTCH_OPTIM_STATS) extern int swtch_optim_stats; SYSCTL_INT(_debug, OID_AUTO, swtch_optim_stats, CTLFLAG_RD, &swtch_optim_stats, 0, ""); SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count, CTLFLAG_RD, &tlb_flush_count, 0, ""); #endif #ifdef PC98 static int ispc98 = 1; #else static int ispc98 = 0; #endif SYSCTL_INT(_machdep, OID_AUTO, ispc98, CTLFLAG_RD, &ispc98, 0, ""); int physmem = 0; int cold = 1; #ifdef COMPAT_43 static void osendsig __P((sig_t catcher, int sig, sigset_t *mask, u_long code)); #endif static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem), req); return (error); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "IU", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem - cnt.v_wire_count), req); return (error); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "IU", ""); static int sysctl_hw_availpages(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, i386_btop(avail_end - avail_start), req); return (error); } SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_availpages, "I", ""); int Maxmem = 0; long dumplo; vm_offset_t phys_avail[10]; /* must be 2 less so 0 0 can signal end of chunks */ #define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2) struct kva_md_info kmi; static struct trapframe proc0_tf; #ifndef SMP static struct globaldata __globaldata; #endif struct mtx sched_lock; struct mtx Giant; static void cpu_startup(dummy) void *dummy; { /* * Good {morning,afternoon,evening,night}. */ earlysetcpuclass(); startrtclock(); printcpuinfo(); panicifcpuunsupported(); #ifdef PERFMON perfmon_init(); #endif printf("real memory = %u (%uK bytes)\n", ptoa(Maxmem), ptoa(Maxmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { unsigned int size1; size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08x - 0x%08x, %u bytes (%u pages)\n", phys_avail[indx], phys_avail[indx + 1] - 1, size1, size1 / PAGE_SIZE); } } vm_ksubmap_init(&kmi); #if 0 /* * Calculate callout wheel size */ for (callwheelsize = 1, callwheelbits = 0; callwheelsize < ncallout; callwheelsize <<= 1, ++callwheelbits) ; callwheelmask = callwheelsize - 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(callout, struct callout, ncallout); valloc(callwheel, struct callout_tailq, callwheelsize); /* * Discount the physical memory larger than the size of kernel_map * to avoid eating up all of KVA space. */ if (kernel_map->first_free == NULL) { printf("Warning: no free entries in kernel_map.\n"); physmem_est = physmem; } else { physmem_est = min(physmem, btoc(kernel_map->max_offset - kernel_map->min_offset)); } /* * The nominal buffer size (and minimum KVA allocation) is BKVASIZE. * For the first 64MB of ram nominally allocate sufficient buffers to * cover 1/4 of our ram. Beyond the first 64MB allocate additional * buffers to cover 1/20 of our ram over 64MB. When auto-sizing * the buffer cache we limit the eventual kva reservation to * maxbcache bytes. * * factor represents the 1/4 x ram conversion. */ if (nbuf == 0) { int factor = 4 * BKVASIZE / PAGE_SIZE; nbuf = 50; if (physmem_est > 1024) nbuf += min((physmem_est - 1024) / factor, 16384 / factor); if (physmem_est > 16384) nbuf += (physmem_est - 16384) * 2 / (factor * 5); if (maxbcache && nbuf > maxbcache / BKVASIZE) nbuf = maxbcache / BKVASIZE; } /* * Do not allow the buffer_map to be more then 1/2 the size of the * kernel_map. */ if (nbuf > (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2)) { nbuf = (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2); printf("Warning: nbufs capped at %d\n", nbuf); } nswbuf = max(min(nbuf/4, 256), 16); valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); v = bufhashinit(v); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size); buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, (nbuf*BKVASIZE)); buffer_map->system_map = 1; pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, (nswbuf*MAXPHYS) + pager_map_size); pager_map->system_map = 1; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (16*(ARG_MAX+(PAGE_SIZE*3)))); /* * XXX: Mbuf system machine-specific initializations should * go here, if anywhere. */ /* * Initialize callouts */ SLIST_INIT(&callfree); for (i = 0; i < ncallout; i++) { callout_init(&callout[i], 0); callout[i].c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle); } for (i = 0; i < callwheelsize; i++) { TAILQ_INIT(&callwheel[i]); } mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE); #endif #if defined(USERCONFIG) userconfig(); cninit(); /* the preferred console may have changed */ #endif printf("avail memory = %u (%uK bytes)\n", ptoa(cnt.v_free_count), ptoa(cnt.v_free_count) / 1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); globaldata_register(GLOBALDATA); #ifndef SMP /* For SMP, we delay the cpu_setregs() until after SMP startup. */ cpu_setregs(); #endif } /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ #ifdef COMPAT_43 static void osendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct osigframe sf; struct osigframe *fp; struct proc *p; struct sigacts *psp; struct trapframe *regs; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct osigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct osigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else fp = (struct osigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *fp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)fp) == 0 || !useracc((caddr_t)fp, sizeof(*fp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; } else { /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* Save most if not all of trap frame. */ sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax; sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx; sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx; sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx; sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi; sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi; sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs; sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds; sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss; sf.sf_siginfo.si_sc.sc_es = regs->tf_es; sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs; sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; /* Build the signal context to be used by osigreturn(). */ sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0; SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags; sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno; sf.sf_siginfo.si_sc.sc_err = regs->tf_err; /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs; sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs; sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es; sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* See sendsig() for comments. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, fp, sizeof(*fp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)fp; regs->tf_eip = PS_STRINGS - szosigcode; regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; load_gs(_udatasel); regs->tf_ss = _udatasel; } #endif void sendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct sigframe sf; struct proc *p; struct sigacts *psp; struct trapframe *regs; struct sigframe *sfp; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { PROC_UNLOCK(p); osendsig(catcher, sig, mask, code); return; } #endif regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_gs = rgs(); bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct sigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sfp = (struct sigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *sfp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)sfp) == 0 || !useracc((caddr_t)sfp, sizeof(*sfp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG printf("process %d has trashed its stack\n", p->p_pid); #endif PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_ucontext = (register_t)&sfp->sf_uc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_siginfo = (register_t)&sfp->sf_si; sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; /* Fill siginfo structure. */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void *)regs->tf_err; } else { /* Old FreeBSD-style arguments. */ sf.sf_siginfo = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_uc.uc_mcontext.mc_eflags = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 * mode. It may be set here if we deliver a signal before * getting to vm86 mode, so turn it off. * * Clear PSL_NT to inhibit T_TSSFLT faults on return from * syscalls made by the signal handler. This just avoids * wasting time for our lazy fixup of such faults. PSL_NT * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_ss = _udatasel; } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ #ifdef COMPAT_43 int osigreturn(p, uap) struct proc *p; struct osigreturn_args /* { struct osigcontext *sigcntxp; } */ *uap; { struct trapframe *regs; struct osigcontext *scp; int eflags; regs = p->p_frame; scp = uap->sigcntxp; if (!useracc((caddr_t)scp, sizeof(*scp), VM_PROT_READ)) return (EFAULT); eflags = scp->sc_ps; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } tf->tf_vm86_ds = scp->sc_ds; tf->tf_vm86_es = scp->sc_es; tf->tf_vm86_fs = scp->sc_fs; tf->tf_vm86_gs = scp->sc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ if (!CS_SECURE(scp->sc_cs)) { trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } regs->tf_ds = scp->sc_ds; regs->tf_es = scp->sc_es; regs->tf_fs = scp->sc_fs; } /* Restore remaining registers. */ regs->tf_eax = scp->sc_eax; regs->tf_ebx = scp->sc_ebx; regs->tf_ecx = scp->sc_ecx; regs->tf_edx = scp->sc_edx; regs->tf_esi = scp->sc_esi; regs->tf_edi = scp->sc_edi; regs->tf_cs = scp->sc_cs; regs->tf_ss = scp->sc_ss; regs->tf_isp = scp->sc_isp; PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (scp->sc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif SIGSETOLD(p->p_sigmask, scp->sc_mask); SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; regs->tf_eflags = eflags; return (EJUSTRETURN); } #endif int sigreturn(p, uap) struct proc *p; struct sigreturn_args /* { ucontext_t *sigcntxp; } */ *uap; { struct trapframe *regs; ucontext_t *ucp; int cs, eflags; ucp = uap->sigcntxp; #ifdef COMPAT_43 if (!useracc((caddr_t)ucp, sizeof(struct osigcontext), VM_PROT_READ)) return (EFAULT); if (((struct osigcontext *)ucp)->sc_trapno == 0x01d516) return (osigreturn(p, (struct osigreturn_args *)uap)); /* * Since ucp is not an osigcontext but a ucontext_t, we have to * check again if all of it is accessible. A ucontext_t is * much larger, so instead of just checking for the pointer * being valid for the size of an osigcontext, now check for * it being valid for a whole, new-style ucontext_t. */ #endif if (!useracc((caddr_t)ucp, sizeof(*ucp), VM_PROT_READ)) return (EFAULT); regs = p->p_frame; eflags = ucp->uc_mcontext.mc_eflags; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); tf->tf_eflags = eflags; tf->tf_vm86_ds = tf->tf_ds; tf->tf_vm86_es = tf->tf_es; tf->tf_vm86_fs = tf->tf_fs; tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { printf("sigreturn: eflags = 0x%x\n", eflags); return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ cs = ucp->uc_mcontext.mc_cs; if (!CS_SECURE(cs)) { printf("sigreturn: cs = 0x%x\n", cs); trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); } PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (ucp->uc_mcontext.mc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif p->p_sigmask = ucp->uc_sigmask; SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); return (EJUSTRETURN); } /* * Machine dependent boot() routine * * I haven't seen anything to put here yet * Possibly some stuff might be grafted back here from boot() */ void cpu_boot(int howto) { } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { for (;;) __asm__ ("hlt"); } /* * Hook to idle the CPU when possible. This currently only works in * the !SMP case, as there is no clean way to ensure that a CPU will be * woken when there is work available for it. */ static int cpu_idle_hlt = 1; SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, &cpu_idle_hlt, 0, "Idle loop HLT enable"); /* * Note that we have to be careful here to avoid a race between checking * procrunnable() and actually halting. If we don't do this, we may waste * the time between calling hlt and the next interrupt even though there * is a runnable process. */ void cpu_idle(void) { #ifndef SMP if (cpu_idle_hlt) { disable_intr(); if (procrunnable()) enable_intr(); else { enable_intr(); __asm __volatile("hlt"); } } #endif } /* * Clear registers on exec */ void setregs(p, entry, stack, ps_strings) struct proc *p; u_long entry; u_long stack; u_long ps_strings; { struct trapframe *regs = p->p_frame; struct pcb *pcb = &p->p_addr->u_pcb; if (pcb->pcb_ldt) user_ldt_free(pcb); bzero((char *)regs, sizeof(struct trapframe)); regs->tf_eip = entry; regs->tf_esp = stack; regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T); regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_cs = _ucodesel; /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */ regs->tf_ebx = ps_strings; /* reset %gs as well */ if (pcb == PCPU_GET(curpcb)) load_gs(_udatasel); else pcb->pcb_gs = _udatasel; /* * Reset the hardware debug registers if they were in use. * They won't have any meaning for the newly exec'd process. */ if (pcb->pcb_flags & PCB_DBREGS) { pcb->pcb_dr0 = 0; pcb->pcb_dr1 = 0; pcb->pcb_dr2 = 0; pcb->pcb_dr3 = 0; pcb->pcb_dr6 = 0; pcb->pcb_dr7 = 0; if (pcb == PCPU_GET(curpcb)) { /* * Clear the debug registers on the running * CPU, otherwise they will end up affecting * the next process we switch to. */ reset_dbregs(); } pcb->pcb_flags &= ~PCB_DBREGS; } /* * Initialize the math emulator (if any) for the current process. * Actually, just clear the bit that says that the emulator has * been initialized. Initialization is delayed until the process * traps to the emulator (if it is done at all) mainly because * emulators don't provide an entry point for initialization. */ p->p_addr->u_pcb.pcb_flags &= ~FP_SOFTFP; /* * Arrange to trap the next npx or `fwait' instruction (see npx.c * for why fwait must be trapped at least if there is an npx or an * emulator). This is mainly to handle the case where npx0 is not * configured, since the npx routines normally set up the trap * otherwise. It should be done only at boot time, but doing it * here allows modifying `npx_exists' for testing the emulator on * systems with an npx. */ load_cr0(rcr0() | CR0_MP | CR0_TS); #ifdef DEV_NPX /* Initialize the npx (if any) for the current process. */ npxinit(__INITIAL_NPXCW__); #endif /* * XXX - Linux emulator * Make sure sure edx is 0x0 on entry. Linux binaries depend * on it. */ p->p_retval[1] = 0; } void cpu_setregs(void) { unsigned int cr0; cr0 = rcr0(); cr0 |= CR0_NE; /* Done by npxinit() */ cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */ #ifndef I386_CPU cr0 |= CR0_WP | CR0_AM; #endif load_cr0(cr0); load_gs(_udatasel); } static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) { int error; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (!error && req->newptr) resettodr(); return (error); } SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 0, ""); SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo, CTLFLAG_RD, &bootinfo, bootinfo, ""); SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, &wall_cmos_clock, 0, ""); /* * Initialize 386 and configure to run kernel */ /* * Initialize segments & interrupt table */ int _default_ldt; union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ static struct gate_descriptor idt0[NIDT]; struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ #ifdef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif int private_tss; /* flag indicating private tss */ #if defined(I586_CPU) && !defined(NO_F00F_HACK) extern int has_f00f_bug; #endif static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; extern struct user *proc0paddr; /* software prototypes -- in more palatable form */ struct soft_segment_descriptor gdt_segs[] = { /* GNULL_SEL 0 Null Descriptor */ { 0x0, /* segment base address */ 0x0, /* length */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GCODE_SEL 1 Code Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GDATA_SEL 2 Data Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPRIV_SEL 3 SMP Per-Processor Private Data Descriptor */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPROC0_SEL 4 Proc 0 Tss Descriptor */ { 0x0, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GLDT_SEL 5 LDT Descriptor */ { (int) ldt, /* segment base address */ sizeof(ldt)-1, /* length - all address space */ SDT_SYSLDT, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GUSERLDT_SEL 6 User LDT Descriptor per process */ { (int) ldt, /* segment base address */ (512 * sizeof(union descriptor)-1), /* length */ SDT_SYSLDT, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GTGATE_SEL 7 Null Descriptor - Placeholder */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSLOWMEM_SEL 8 BIOS access to realmode segment 0x40, must be #8 in GDT */ { 0x400, /* segment base address */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPANIC_SEL 9 Panic Tss Descriptor */ { (int) &dblfault_tss, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE32_SEL 10 BIOS 32-bit interface (32bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE16_SEL 11 BIOS 32-bit interface (16bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSDATA_SEL 12 BIOS 32-bit interface (Data) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSUTIL_SEL 13 BIOS 16-bit interface (Utility) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSARGS_SEL 14 BIOS 16-bit interface (Arguments) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Code Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Data Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; void setidt(idx, func, typ, dpl, selec) int idx; inthand_t *func; int typ; int dpl; int selec; { struct gate_descriptor *ip; ip = idt + idx; ip->gd_looffset = (int)func; ip->gd_selector = selec; ip->gd_stkcpy = 0; ip->gd_xx = 0; ip->gd_type = typ; ip->gd_dpl = dpl; ip->gd_p = 1; ip->gd_hioffset = ((int)func)>>16 ; } #define IDTVEC(name) __CONCAT(X,name) extern inthand_t IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); void sdtossd(sd, ssd) struct segment_descriptor *sd; struct soft_segment_descriptor *ssd; { ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; ssd->ssd_type = sd->sd_type; ssd->ssd_dpl = sd->sd_dpl; ssd->ssd_p = sd->sd_p; ssd->ssd_def32 = sd->sd_def32; ssd->ssd_gran = sd->sd_gran; } #define PHYSMAP_SIZE (2 * 8) /* * Populate the (physmap) array with base/bound pairs describing the * available physical memory in the system, then test this memory and * build the phys_avail array describing the actually-available memory. * * If we cannot accurately determine the physical memory map, then use * value from the 0xE801 call, and failing that, the RTC. * * Total memory size may be set by the kernel environment variable * hw.physmem or the compile-time define MAXMEM. */ static void getmemsize(int first) { int i, physmap_idx, pa_indx; u_int basemem, extmem; struct vm86frame vmf; struct vm86context vmc; vm_offset_t pa, physmap[PHYSMAP_SIZE]; pt_entry_t pte; const char *cp; struct bios_smap *smap; bzero(&vmf, sizeof(struct vm86frame)); bzero(physmap, sizeof(physmap)); /* * Perform "base memory" related probes & setup */ vm86_intcall(0x12, &vmf); basemem = vmf.vmf_ax; if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); basemem = 640; } /* * XXX if biosbasemem is now < 640, there is a `hole' * between the end of base memory and the start of * ISA memory. The hole may be empty or it may * contain BIOS code or data. Map it read/write so * that the BIOS can write to it. (Memory from 0 to * the physical end of the kernel is mapped read-only * to begin with and then parts of it are remapped. * The parts that aren't remapped form holes that * remain read-only and are unused by the kernel. * The base memory area is below the physical end of * the kernel and right now forms a read-only hole. * The part of it from PAGE_SIZE to * (trunc_page(biosbasemem * 1024) - 1) will be * remapped and used by the kernel later.) * * This code is similar to the code used in * pmap_mapdev, but since no memory needs to be * allocated we simply change the mapping. */ for (pa = trunc_page(basemem * 1024); pa < ISA_HOLE_START; pa += PAGE_SIZE) { pte = (pt_entry_t)vtopte(pa + KERNBASE); *pte = pa | PG_RW | PG_V; } /* * if basemem != 640, map pages r/w into vm86 page table so * that the bios can scribble on it. */ pte = (pt_entry_t)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; /* * map page 1 R/W into the kernel page table so we can use it * as a buffer. The kernel will unmap this page later. */ pte = (pt_entry_t)vtopte(KERNBASE + (1 << PAGE_SHIFT)); *pte = (1 << PAGE_SHIFT) | PG_RW | PG_V; /* * get memory map with INT 15:E820 */ vmc.npages = 0; smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); physmap_idx = 0; vmf.vmf_ebx = 0; do { vmf.vmf_eax = 0xE820; vmf.vmf_edx = SMAP_SIG; vmf.vmf_ecx = sizeof(struct bios_smap); i = vm86_datacall(0x15, &vmf, &vmc); if (i || vmf.vmf_eax != SMAP_SIG) break; if (boothowto & RB_VERBOSE) printf("SMAP type=%02x base=%08x %08x len=%08x %08x\n", smap->type, *(u_int32_t *)((char *)&smap->base + 4), (u_int32_t)smap->base, *(u_int32_t *)((char *)&smap->length + 4), (u_int32_t)smap->length); if (smap->type != 0x01) goto next_run; if (smap->length == 0) goto next_run; if (smap->base >= 0xffffffff) { printf("%uK of memory above 4GB ignored\n", (u_int)(smap->length / 1024)); goto next_run; } for (i = 0; i <= physmap_idx; i += 2) { if (smap->base < physmap[i + 1]) { if (boothowto & RB_VERBOSE) printf( "Overlapping or non-montonic memory region, ignoring second region\n"); goto next_run; } } if (smap->base == physmap[physmap_idx + 1]) { physmap[physmap_idx + 1] += smap->length; goto next_run; } physmap_idx += 2; if (physmap_idx == PHYSMAP_SIZE) { printf( "Too many segments in the physical address map, giving up\n"); break; } physmap[physmap_idx] = smap->base; physmap[physmap_idx + 1] = smap->base + smap->length; next_run: } while (vmf.vmf_ebx != 0); if (physmap[1] != 0) goto physmap_done; /* * If we failed above, try memory map with INT 15:E801 */ vmf.vmf_ax = 0xE801; if (vm86_intcall(0x15, &vmf) == 0) { extmem = vmf.vmf_cx + vmf.vmf_dx * 64; } else { #if 0 vmf.vmf_ah = 0x88; vm86_intcall(0x15, &vmf); extmem = vmf.vmf_ax; #else /* * Prefer the RTC value for extended memory. */ extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8); #endif } /* * Special hack for chipsets that still remap the 384k hole when * there's 16MB of memory - this really confuses people that * are trying to use bus mastering ISA controllers with the * "16MB limit"; they only have 16MB, but the remapping puts * them beyond the limit. * * If extended memory is between 15-16MB (16-17MB phys address range), * chop it to 15MB. */ if ((extmem > 15 * 1024) && (extmem < 16 * 1024)) extmem = 15 * 1024; physmap[0] = 0; physmap[1] = basemem * 1024; physmap_idx = 2; physmap[physmap_idx] = 0x100000; physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024; physmap_done: /* * Now, physmap contains a map of physical memory. */ #ifdef SMP /* make hole for AP bootstrap code */ physmap[1] = mp_bootaddress(physmap[1] / 1024); /* look for the MP hardware - needed for apic addresses */ i386_mp_probe(); #endif /* * Maxmem isn't the "maximum memory", it's one larger than the * highest page of the physical address space. It should be * called something like "Maxphyspage". We may adjust this * based on ``hw.physmem'' and the results of the memory test. */ Maxmem = atop(physmap[physmap_idx + 1]); #ifdef MAXMEM Maxmem = MAXMEM / 4; #endif /* * hw.physmem is a size in bytes; we also allow k, m, and g suffixes * for the appropriate modifiers. This overrides MAXMEM. */ if ((cp = getenv("hw.physmem")) != NULL) { u_int64_t AllowMem, sanity; char *ep; sanity = AllowMem = strtouq(cp, &ep, 0); if ((ep != cp) && (*ep != 0)) { switch(*ep) { case 'g': case 'G': AllowMem <<= 10; case 'm': case 'M': AllowMem <<= 10; case 'k': case 'K': AllowMem <<= 10; break; default: AllowMem = sanity = 0; } if (AllowMem < sanity) AllowMem = 0; } if (AllowMem == 0) printf("Ignoring invalid memory size of '%s'\n", cp); else Maxmem = atop(AllowMem); } if (atop(physmap[physmap_idx + 1]) != Maxmem && (boothowto & RB_VERBOSE)) printf("Physical memory use set to %uK\n", Maxmem * 4); /* * If Maxmem has been increased beyond what the system has detected, * extend the last memory segment to the new limit. */ if (atop(physmap[physmap_idx + 1]) < Maxmem) physmap[physmap_idx + 1] = ptoa(Maxmem); /* call pmap initialization to make new kernel address space */ pmap_bootstrap(first, 0); /* * Size up each available chunk of physical memory. */ physmap[0] = PAGE_SIZE; /* mask off page 0 */ pa_indx = 0; phys_avail[pa_indx++] = physmap[0]; phys_avail[pa_indx] = physmap[0]; #if 0 pte = (pt_entry_t)vtopte(KERNBASE); #else pte = (pt_entry_t)CMAP1; #endif /* * physmap is in bytes, so when converting to page boundaries, * round up the start address and round down the end address. */ for (i = 0; i <= physmap_idx; i += 2) { vm_offset_t end; end = ptoa(Maxmem); if (physmap[i + 1] < end) end = trunc_page(physmap[i + 1]); for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) { int tmp, page_bad; #if 0 int *ptr = 0; #else int *ptr = (int *)CADDR1; #endif /* * block out kernel memory as not available. */ if (pa >= 0x100000 && pa < first) continue; page_bad = FALSE; /* * map page into kernel: valid, read/write,non-cacheable */ *pte = pa | PG_V | PG_RW | PG_N; invltlb(); tmp = *(int *)ptr; /* * Test for alternating 1's and 0's */ *(volatile int *)ptr = 0xaaaaaaaa; if (*(volatile int *)ptr != 0xaaaaaaaa) { page_bad = TRUE; } /* * Test for alternating 0's and 1's */ *(volatile int *)ptr = 0x55555555; if (*(volatile int *)ptr != 0x55555555) { page_bad = TRUE; } /* * Test for all 1's */ *(volatile int *)ptr = 0xffffffff; if (*(volatile int *)ptr != 0xffffffff) { page_bad = TRUE; } /* * Test for all 0's */ *(volatile int *)ptr = 0x0; if (*(volatile int *)ptr != 0x0) { page_bad = TRUE; } /* * Restore original value. */ *(int *)ptr = tmp; /* * Adjust array of valid/good pages. */ if (page_bad == TRUE) { continue; } /* * If this good page is a continuation of the * previous set of good pages, then just increase * the end pointer. Otherwise start a new chunk. * Note that "end" points one higher than end, * making the range >= start and < end. * If we're also doing a speculative memory * test and we at or past the end, bump up Maxmem * so that we keep going. The first bad page * will terminate the loop. */ if (phys_avail[pa_indx] == pa) { phys_avail[pa_indx] += PAGE_SIZE; } else { pa_indx++; if (pa_indx == PHYS_AVAIL_ARRAY_END) { printf( "Too many holes in the physical address space, giving up\n"); pa_indx--; break; } phys_avail[pa_indx++] = pa; /* start */ phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */ } physmem++; } } *pte = 0; invltlb(); /* * XXX * The last chunk must contain at least one page plus the message * buffer to avoid complicating other code (message buffer address * calculation, etc.). */ while (phys_avail[pa_indx - 1] + PAGE_SIZE + round_page(MSGBUF_SIZE) >= phys_avail[pa_indx]) { physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]); phys_avail[pa_indx--] = 0; phys_avail[pa_indx--] = 0; } Maxmem = atop(phys_avail[pa_indx]); /* Trim off space for the message buffer. */ phys_avail[pa_indx] -= round_page(MSGBUF_SIZE); avail_end = phys_avail[pa_indx]; } void init386(first) int first; { struct gate_descriptor *gdp; int gsel_tss, metadata_missing, off, x; #ifndef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif proc0.p_addr = proc0paddr; atdevbase = ISA_HOLE_START + KERNBASE; metadata_missing = 0; if (bootinfo.bi_modulep) { preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE; preload_bootstrap_relocate(KERNBASE); } else { metadata_missing = 1; } - if (bootinfo.bi_envp) + if (envmode == 1) + kern_envp = static_env; + else if (bootinfo.bi_envp) kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; /* Init basic tunables, hz etc */ init_param(); /* * make gdt memory segments, the code segment goes up to end of the * page with etext in it, the data segment goes to the end of * the address space */ /* * XXX text protection is temporarily (?) disabled. The limit was * i386_btop(round_page(etext)) - 1. */ gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1); gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1); #ifdef SMP gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct privatespace) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[0]; gdt_segs[GPROC0_SEL].ssd_base = (int) &SMP_prvspace[0].globaldata.gd_common_tss; SMP_prvspace[0].globaldata.gd_prvspace = &SMP_prvspace[0].globaldata; #else gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct globaldata) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &__globaldata; gdt_segs[GPROC0_SEL].ssd_base = (int) &__globaldata.gd_common_tss; __globaldata.gd_prvspace = &__globaldata; #endif for (x = 0; x < NGDT; x++) { #ifdef BDE_DEBUGGER /* avoid overwriting db entries with APM ones */ if (x >= GAPMCODE32_SEL && x <= GAPMDATA_SEL) continue; #endif ssdtosd(&gdt_segs[x], &gdt[x].sd); } r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; r_gdt.rd_base = (int) gdt; lgdt(&r_gdt); /* setup curproc so that mutexes work */ PCPU_SET(curproc, &proc0); PCPU_SET(spinlocks, NULL); LIST_INIT(&proc0.p_contested); /* * Initialize mutexes. */ mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE); mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE); mtx_init(&proc0.p_mtx, "process lock", MTX_DEF); mtx_init(&clock_lock, "clk", MTX_SPIN | MTX_RECURSE); #ifdef SMP mtx_init(&imen_mtx, "imen", MTX_SPIN); #endif mtx_lock(&Giant); /* make ldt memory segments */ /* * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it * should be spelled ...MAX_USER... */ ldt_segs[LUCODE_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); ldt_segs[LUDATA_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++) ssdtosd(&ldt_segs[x], &ldt[x].sd); _default_ldt = GSEL(GLDT_SEL, SEL_KPL); lldt(_default_ldt); PCPU_SET(currentldt, _default_ldt); /* exceptions */ for (x = 0; x < NIDT; x++) setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(1, &IDTVEC(dbg), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(3, &IDTVEC(bpt), SDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL , GSEL(GCODE_SEL, SEL_KPL)); setidt(8, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL)); setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(14, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(18, &IDTVEC(mchk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(19, &IDTVEC(xmm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); r_idt.rd_limit = sizeof(idt0) - 1; r_idt.rd_base = (int) idt; lidt(&r_idt); /* * Initialize the console before we print anything out. */ cninit(); if (metadata_missing) printf("WARNING: loader(8) metadata is missing!\n"); #ifdef DEV_ISA isa_defaultirq(); #endif #ifdef DDB kdb_init(); if (boothowto & RB_KDB) Debugger("Boot flags requested debugger"); #endif finishidentcpu(); /* Final stage of CPU initialization */ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); initializecpu(); /* Initialize CPU registers */ /* make an initial tss so cpu can get interrupt stack on syscall! */ PCPU_SET(common_tss.tss_esp0, (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16); PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); private_tss = 0; PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); ltr(gsel_tss); dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)]; dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 = dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_cr3 = (int)IdlePTD; dblfault_tss.tss_eip = (int)dblfault_handler; dblfault_tss.tss_eflags = PSL_KERNEL; dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL); dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL); dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL); vm86_initialize(); getmemsize(first); /* now running on new page tables, configured,and u/iom is accessible */ /* Map the message buffer. */ for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE) pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off); msgbufinit(msgbufp, MSGBUF_SIZE); /* make a call gate to reenter kernel with */ gdp = &ldt[LSYS5CALLS_SEL].gd; x = (int) &IDTVEC(lcall_syscall); gdp->gd_looffset = x; gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); gdp->gd_stkcpy = 1; gdp->gd_type = SDT_SYS386CGT; gdp->gd_dpl = SEL_UPL; gdp->gd_p = 1; gdp->gd_hioffset = x >> 16; /* XXX does this work? */ ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL]; ldt[LSOL26CALLS_SEL] = ldt[LSYS5CALLS_SEL]; /* transfer to user mode */ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); _udatasel = LSEL(LUDATA_SEL, SEL_UPL); /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = (int)IdlePTD; proc0.p_addr->u_pcb.pcb_ext = 0; proc0.p_frame = &proc0_tf; } #if defined(I586_CPU) && !defined(NO_F00F_HACK) static void f00f_hack(void *unused); SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); static void f00f_hack(void *unused) { struct gate_descriptor *new_idt; #ifndef SMP struct region_descriptor r_idt; #endif vm_offset_t tmp; if (!has_f00f_bug) return; GIANT_REQUIRED; printf("Intel Pentium detected, installing workaround for F00F bug\n"); r_idt.rd_limit = sizeof(idt0) - 1; tmp = kmem_alloc(kernel_map, PAGE_SIZE * 2); if (tmp == 0) panic("kmem_alloc returned 0"); if (((unsigned int)tmp & (PAGE_SIZE-1)) != 0) panic("kmem_alloc returned non-page-aligned memory"); /* Put the first seven entries in the lower page */ new_idt = (struct gate_descriptor*)(tmp + PAGE_SIZE - (7*8)); bcopy(idt, new_idt, sizeof(idt0)); r_idt.rd_base = (int)new_idt; lidt(&r_idt); idt = new_idt; if (vm_map_protect(kernel_map, tmp, tmp + PAGE_SIZE, VM_PROT_READ, FALSE) != KERN_SUCCESS) panic("vm_map_protect failed"); return; } #endif /* defined(I586_CPU) && !NO_F00F_HACK */ int ptrace_set_pc(p, addr) struct proc *p; unsigned long addr; { p->p_frame->tf_eip = addr; return (0); } int ptrace_single_step(p) struct proc *p; { p->p_frame->tf_eflags |= PSL_T; return (0); } int fill_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; regs->r_fs = tp->tf_fs; regs->r_es = tp->tf_es; regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_edi; regs->r_esi = tp->tf_esi; regs->r_ebp = tp->tf_ebp; regs->r_ebx = tp->tf_ebx; regs->r_edx = tp->tf_edx; regs->r_ecx = tp->tf_ecx; regs->r_eax = tp->tf_eax; regs->r_eip = tp->tf_eip; regs->r_cs = tp->tf_cs; regs->r_eflags = tp->tf_eflags; regs->r_esp = tp->tf_esp; regs->r_ss = tp->tf_ss; pcb = &p->p_addr->u_pcb; regs->r_gs = pcb->pcb_gs; return (0); } int set_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; tp->tf_edi = regs->r_edi; tp->tf_esi = regs->r_esi; tp->tf_ebp = regs->r_ebp; tp->tf_ebx = regs->r_ebx; tp->tf_edx = regs->r_edx; tp->tf_ecx = regs->r_ecx; tp->tf_eax = regs->r_eax; tp->tf_eip = regs->r_eip; tp->tf_cs = regs->r_cs; tp->tf_eflags = regs->r_eflags; tp->tf_esp = regs->r_esp; tp->tf_ss = regs->r_ss; pcb = &p->p_addr->u_pcb; pcb->pcb_gs = regs->r_gs; return (0); } #ifdef CPU_ENABLE_SSE static void fill_fpregs_xmm(sv_xmm, sv_87) struct savexmm *sv_xmm; struct save87 *sv_87; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_87->en_cw = penv_xmm->en_cw; penv_87->en_sw = penv_xmm->en_sw; penv_87->en_tw = penv_xmm->en_tw; penv_87->en_fip = penv_xmm->en_fip; penv_87->en_fcs = penv_xmm->en_fcs; penv_87->en_opcode = penv_xmm->en_opcode; penv_87->en_foo = penv_xmm->en_foo; penv_87->en_fos = penv_xmm->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc; sv_87->sv_ex_sw = sv_xmm->sv_ex_sw; } static void set_fpregs_xmm(sv_87, sv_xmm) struct save87 *sv_87; struct savexmm *sv_xmm; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_xmm->en_cw = penv_87->en_cw; penv_xmm->en_sw = penv_87->en_sw; penv_xmm->en_tw = penv_87->en_tw; penv_xmm->en_fip = penv_87->en_fip; penv_xmm->en_fcs = penv_87->en_fcs; penv_xmm->en_opcode = penv_87->en_opcode; penv_xmm->en_foo = penv_87->en_foo; penv_xmm->en_fos = penv_87->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i]; sv_xmm->sv_ex_sw = sv_87->sv_ex_sw; } #endif /* CPU_ENABLE_SSE */ int fill_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { fill_fpregs_xmm(&p->p_addr->u_pcb.pcb_save.sv_xmm, (struct save87 *)fpregs); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(&p->p_addr->u_pcb.pcb_save.sv_87, fpregs, sizeof *fpregs); return (0); } int set_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { set_fpregs_xmm((struct save87 *)fpregs, &p->p_addr->u_pcb.pcb_save.sv_xmm); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(fpregs, &p->p_addr->u_pcb.pcb_save.sv_87, sizeof *fpregs); return (0); } int fill_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; if (p == NULL) { dbregs->dr0 = rdr0(); dbregs->dr1 = rdr1(); dbregs->dr2 = rdr2(); dbregs->dr3 = rdr3(); dbregs->dr4 = rdr4(); dbregs->dr5 = rdr5(); dbregs->dr6 = rdr6(); dbregs->dr7 = rdr7(); } else { pcb = &p->p_addr->u_pcb; dbregs->dr0 = pcb->pcb_dr0; dbregs->dr1 = pcb->pcb_dr1; dbregs->dr2 = pcb->pcb_dr2; dbregs->dr3 = pcb->pcb_dr3; dbregs->dr4 = 0; dbregs->dr5 = 0; dbregs->dr6 = pcb->pcb_dr6; dbregs->dr7 = pcb->pcb_dr7; } return (0); } int set_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; int i; u_int32_t mask1, mask2; if (p == NULL) { load_dr0(dbregs->dr0); load_dr1(dbregs->dr1); load_dr2(dbregs->dr2); load_dr3(dbregs->dr3); load_dr4(dbregs->dr4); load_dr5(dbregs->dr5); load_dr6(dbregs->dr6); load_dr7(dbregs->dr7); } else { /* * Don't let an illegal value for dr7 get set. Specifically, * check for undefined settings. Setting these bit patterns * result in undefined behaviour and can lead to an unexpected * TRCTRAP. */ for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8; i++, mask1 <<= 2, mask2 <<= 2) if ((dbregs->dr7 & mask1) == mask2) return (EINVAL); pcb = &p->p_addr->u_pcb; /* * Don't let a process set a breakpoint that is not within the * process's address space. If a process could do this, it * could halt the system by setting a breakpoint in the kernel * (if ddb was enabled). Thus, we need to check to make sure * that no breakpoints are being enabled for addresses outside * process's address space, unless, perhaps, we were called by * uid 0. * * XXX - what about when the watched area of the user's * address space is written into from within the kernel * ... wouldn't that still cause a breakpoint to be generated * from within kernel mode? */ if (suser(p) != 0) { if (dbregs->dr7 & 0x3) { /* dr0 is enabled */ if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<2)) { /* dr1 is enabled */ if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<4)) { /* dr2 is enabled */ if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<6)) { /* dr3 is enabled */ if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) return (EINVAL); } } pcb->pcb_dr0 = dbregs->dr0; pcb->pcb_dr1 = dbregs->dr1; pcb->pcb_dr2 = dbregs->dr2; pcb->pcb_dr3 = dbregs->dr3; pcb->pcb_dr6 = dbregs->dr6; pcb->pcb_dr7 = dbregs->dr7; pcb->pcb_flags |= PCB_DBREGS; } return (0); } /* * Return > 0 if a hardware breakpoint has been hit, and the * breakpoint was in user space. Return 0, otherwise. */ int user_dbreg_trap(void) { u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */ u_int32_t bp; /* breakpoint bits extracted from dr6 */ int nbp; /* number of breakpoints that triggered */ caddr_t addr[4]; /* breakpoint addresses */ int i; dr7 = rdr7(); if ((dr7 & 0x000000ff) == 0) { /* * all GE and LE bits in the dr7 register are zero, * thus the trap couldn't have been caused by the * hardware debug registers */ return 0; } nbp = 0; dr6 = rdr6(); bp = dr6 & 0x0000000f; if (!bp) { /* * None of the breakpoint bits are set meaning this * trap was not caused by any of the debug registers */ return 0; } /* * at least one of the breakpoints were hit, check to see * which ones and if any of them are user space addresses */ if (bp & 0x01) { addr[nbp++] = (caddr_t)rdr0(); } if (bp & 0x02) { addr[nbp++] = (caddr_t)rdr1(); } if (bp & 0x04) { addr[nbp++] = (caddr_t)rdr2(); } if (bp & 0x08) { addr[nbp++] = (caddr_t)rdr3(); } for (i=0; i /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. Adjust transfer * if needed, and signal errors or early completion. */ int bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel) { struct partition *p = lp->d_partitions + dkpart(bp->bio_dev); int labelsect = lp->d_partitions[0].p_offset; int maxsz = p->p_size, sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect && #endif (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #endif /* beyond partition? */ if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->bio_blkno == maxsz) { bp->bio_resid = bp->bio_bcount; return(0); } /* or truncate if part of it fits */ sz = maxsz - bp->bio_blkno; if (sz <= 0) { bp->bio_error = EINVAL; goto bad; } bp->bio_bcount = sz << DEV_BSHIFT; } bp->bio_pblkno = bp->bio_blkno + p->p_offset; return(1); bad: bp->bio_flags |= BIO_ERROR; return(-1); } #ifdef DDB /* * Provide inb() and outb() as functions. They are normally only * available as macros calling inlined functions, thus cannot be * called inside DDB. * * The actual code is stolen from , and de-inlined. */ #undef inb #undef outb /* silence compiler warnings */ u_char inb(u_int); void outb(u_int, u_char); u_char inb(u_int port) { u_char data; /* * We use %%dx and not %1 here because i/o is done at %dx and not at * %edx, while gcc generates inferior code (movw instead of movl) * if we tell it to load (u_short) port. */ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); return (data); } void outb(u_int port, u_char data) { u_char al; /* * Use an unnecessary assignment to help gcc's register allocator. * This make a large difference for gcc-1.40 and a tiny difference * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for * best results. gcc-2.6.0 can't handle this. */ al = data; __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); } #endif /* DDB */ Index: head/sys/conf/Makefile.alpha =================================================================== --- head/sys/conf/Makefile.alpha (revision 82392) +++ head/sys/conf/Makefile.alpha (revision 82393) @@ -1,375 +1,378 @@ # Makefile.alpha -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.alpha 7.1 5/10/91 # $FreeBSD$ # # Makefile for FreeBSD # # This makefile is constructed from a machine description: # config machineid # Most changes should be made in the machine description # /sys/alpha/conf/``machineid'' # after which you should do # config machineid # Generic makefile changes should be made in # /sys/alpha/conf/Makefile.alpha # after which config should be rerun for all machines. # # Which version of config(8) is required. -%VERSREQ= 500007 +%VERSREQ= 500008 # Can be overridden by makeoptions or /etc/make.conf KERNEL_KO?= kernel KERNEL?= kernel KODIR?= /boot/${KERNEL} STD8X16FONT?= iso .if !defined(S) .if exists(./@/.) S= ./@ .else S= ../../.. .endif .endif M= ${MACHINE_ARCH} SIZE?= size OBJCOPY?= objcopy COPTFLAGS?=-O -pipe .if !defined(NO_CPU_COPTFLAGS) COPTFLAGS+= ${_CPUCFLAGS} .endif INCLUDES= -nostdinc -I- ${INCLMAGIC} -I. -I$S -I$S/dev # This hack lets us use the ipfilter code without spamming a new # include path into 100+ source files. INCLUDES+= -I$S/contrib/ipfilter # This hack is to allow kernel compiles to succeed on machines w/out srcdist .if exists($S/../include) INCLUDES+= -I$S/../include .else INCLUDES+= -I/usr/include .endif COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -include opt_global.h CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS} # XXX LOCORE means "don't declare C stuff" not "for locore.s". ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} # Select the correct set of tools. Can't set OBJFORMAT here because it # doesn't get exported into the environment, and if it were exported # then it might break building of utilities. FMT= -elf CFLAGS+= ${FMT} DEFINED_PROF= ${PROF} .if defined(PROF) CFLAGS+= -malign-functions=4 .if ${PROFLEVEL} >= 2 IDENT+= -DGPROF4 -DGUPROF PROF+= -mprofiler-epilogue .endif .endif # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC} PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC} NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \ ${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c GEN_CFILES= $S/$M/$M/genassym.c -SYSTEM_CFILES= vnode_if.c hints.c config.c +SYSTEM_CFILES= vnode_if.c hints.c env.c config.c SYSTEM_SFILES= $S/$M/$M/locore.s SYSTEM_DEP= Makefile ${SYSTEM_OBJS} -SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o config.o hack.So +SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o env.o config.o hack.So SYSTEM_LD= @${LD} ${FMT} -Bdynamic -T $S/conf/ldscript.$M \ -e locorestart \ -export-dynamic -dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${FMT} ${.TARGET} ; chmod 755 ${.TARGET} SYSTEM_DEP+= $S/conf/ldscript.$M %BEFORE_DEPEND %OBJS %FILES.c %FILES.s %FILES.m %CLEAN .PHONY: all modules all: ${KERNEL_KO} depend: kernel-depend clean: kernel-clean cleandepend: kernel-cleandepend clobber: kernel-clobber tags: kernel-tags install: kernel-install install.debug: kernel-install.debug reinstall: kernel-reinstall reinstall.debug: kernel-reinstall.debug .if !defined(DEBUG) FULLKERNEL= ${KERNEL_KO} .else FULLKERNEL= ${KERNEL_KO}.debug ${KERNEL_KO}: ${FULLKERNEL} ${OBJCOPY} --strip-debug ${FULLKERNEL} ${KERNEL_KO} .endif ${FULLKERNEL}: ${SYSTEM_DEP} vers.o @rm -f ${.TARGET} @echo linking ${.TARGET} ${SYSTEM_LD} ${SYSTEM_LD_TAIL} .if !exists(.depend) ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/} .endif .for mfile in ${MFILES} ${mfile:T:S/.m$/.h/}: ${mfile} perl5 $S/kern/makeobjops.pl -h ${mfile} .endfor kernel-clean: rm -f *.o *.so *.So *.ko *.s eddep errs \ ${FULLKERNEL} ${KERNEL_KO} linterrs makelinks \ setdef[01].c setdefs.h tags \ vers.c vnode_if.c vnode_if.h \ ${MFILES:T:S/.m$/.c/} ${MFILES:T:S/.m$/.h/} \ ${CLEAN} kernel-clobber: find . -type f ! -name version -delete locore.o: $S/$M/$M/locore.s assym.s ${NORMAL_S} # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. hack.So: Makefile touch hack.c ${CC} ${FMT} -shared -nostdlib hack.c -o hack.So rm -f hack.c # this rule stops ./assym.s in .depend from causing problems ./assym.s: assym.s assym.s: $S/kern/genassym.sh genassym.o OBJFORMAT=elf sh $S/kern/genassym.sh genassym.o > ${.TARGET} genassym.o: $S/$M/$M/genassym.c ${CC} -c ${CFLAGS} -elf $S/$M/$M/genassym.c SYSTEM_OBJS+= __divqu.o __divq.o __divlu.o __divl.o SYSTEM_OBJS+= __remqu.o __remq.o __remlu.o __reml.o CLEAN+= __divqu.S __divq.S __divlu.S __divl.S CLEAN+= __remqu.S __remq.S __remlu.S __reml.S __divqu.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__divqu')define(OP,\`div')define(S,\`false')"; \ echo "define(WORDSIZE,64)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __divq.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__divq')define(OP,\`div')define(S,\`true')"; \ echo "define(WORDSIZE,64)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __divlu.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__divlu')define(OP,\`div')define(S,\`false')"; \ echo "define(WORDSIZE,32)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __divl.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__divl')define(OP,\`div')define(S,\`true')"; \ echo "define(WORDSIZE,32)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __remqu.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__remqu')define(OP,\`rem')define(S,\`false')"; \ echo "define(WORDSIZE,64)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __remq.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__remq')define(OP,\`rem')define(S,\`true')"; \ echo "define(WORDSIZE,64)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __remlu.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__remlu')define(OP,\`rem')define(S,\`false')"; \ echo "define(WORDSIZE,32)"; cat ${.ALLSRC}) | m4 > ${.TARGET} __reml.S: $S/$M/$M/divrem.m4 @echo 'building ${.TARGET} from ${.ALLSRC}' @(echo "define(NAME,\`__reml')define(OP,\`rem')define(S,\`true')"; \ echo "define(WORDSIZE,32)"; cat ${.ALLSRC}) | m4 > ${.TARGET} ${SYSTEM_OBJS} genassym.o vers.o: opt_global.h kernel-depend: rm -f .olddep if [ -f .depend ]; then mv .depend .olddep; fi ${MAKE} _kernel-depend _kernel-depend: assym.s vnode_if.h ${BEFORE_DEPEND} \ ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \ ${SYSTEM_SFILES} ${MFILES:T:S/.m$/.h/} if [ -f .olddep ]; then mv .olddep .depend; fi rm -f .newdep mkdep -a -f .newdep ${CFLAGS} ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${ASM_CFLAGS} ${SFILES} ${SYSTEM_SFILES} rm -f .depend mv .newdep .depend kernel-cleandepend: rm -f .depend links: egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ sort -u | comm -23 - dontlink | \ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks; rm -f dontlink kernel-tags: @[ -f .depend ] || { echo "you must make depend first"; exit 1; } sh $S/conf/systags.sh rm -f tags1 sed -e 's, ../, ,' tags > tags1 kernel-install kernel-install.debug: .if exists(${DESTDIR}/boot) @if [ ! -f ${DESTDIR}/boot/device.hints ] ; then \ echo "You must set up a ${DESTDIR}/boot/device.hints file first." ; \ exit 1 ; \ fi @if [ x"`grep device.hints ${DESTDIR}/boot/defaults/loader.conf ${DESTDIR}/boot/loader.conf`" = "x" ]; then \ echo "You must activate /boot/device.hints in loader.conf." ; \ exit 1 ; \ fi .endif @if [ ! -f ${KERNEL_KO}${.TARGET:S/kernel-install//} ] ; then \ echo "You must build a kernel first." ; \ exit 1 ; \ fi .if exists(${DESTDIR}${KODIR}) .if exists(${DESTDIR}${KODIR}.old) @-chflags -R noschg ${DESTDIR}${KODIR}.old -rm -rf ${DESTDIR}${KODIR}.old .endif mv ${DESTDIR}${KODIR} ${DESTDIR}${KODIR}.old .endif mkdir -p ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-install//} ${DESTDIR}${KODIR} kernel-reinstall kernel-reinstall.debug: @-chflags -R noschg ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-reinstall//} ${DESTDIR}${KODIR} .if !defined(MODULES_WITH_WORLD) && !defined(NO_MODULES) && exists($S/modules) all: modules depend: modules-depend clean: modules-clean cleandepend: modules-cleandepend cleandir: modules-cleandir clobber: modules-clobber tags: modules-tags install: modules-install install.debug: modules-install.debug reinstall: modules-reinstall reinstall.debug: modules-reinstall.debug .endif MKMODULESENV= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif .if defined(DEBUG) MKMODULESENV+= DEBUG="${DEBUG}" DEBUG_FLAGS="${DEBUG}" .endif modules: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} all modules-depend: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} depend modules-clean: cd $S/modules ; env ${MKMODULESENV} ${MAKE} clean modules-cleandepend: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandepend modules-clobber: modules-clean rm -rf ${MKMODULESENV} modules-cleandir: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandir modules-tags: cd $S/modules ; env ${MKMODULESENV} ${MAKE} tags modules-install modules-install.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install modules-reinstall modules-reinstall.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install config.o: ${NORMAL_C} vers.c: $S/conf/newvers.sh $S/sys/param.h ${SYSTEM_DEP} sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} # XXX strictly, everything depends on Makefile because changes to ${PROF} # only appear there, but we don't handle that. vers.o: ${NORMAL_C} hints.o: hints.c + ${NORMAL_C} + +env.o: env.c ${NORMAL_C} vnode_if.c: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -c $S/kern/vnode_if.src vnode_if.h: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -h $S/kern/vnode_if.src vnode_if.o: ${NORMAL_C} .if exists($S/../share/mk) .include "$S/../share/mk/bsd.kern.mk" .else .include .endif %RULES Index: head/sys/conf/Makefile.i386 =================================================================== --- head/sys/conf/Makefile.i386 (revision 82392) +++ head/sys/conf/Makefile.i386 (revision 82393) @@ -1,335 +1,338 @@ # Makefile.i386 -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 # $FreeBSD$ # # Makefile for FreeBSD # # This makefile is constructed from a machine description: # config machineid # Most changes should be made in the machine description # /sys/i386/conf/``machineid'' # after which you should do # config machineid # Generic makefile changes should be made in # /sys/i386/conf/Makefile.i386 # after which config should be rerun for all machines. # # Which version of config(8) is required. -%VERSREQ= 500007 +%VERSREQ= 500008 # Can be overridden by makeoptions or /etc/make.conf KERNEL_KO?= kernel KERNEL?= kernel KODIR?= /boot/${KERNEL} STD8X16FONT?= iso .if !defined(S) .if exists(./@/.) S= ./@ .else S= ../../.. .endif .endif M= ${MACHINE_ARCH} SIZE?= size OBJCOPY?= objcopy COPTFLAGS?=-O -pipe .if !defined(NO_CPU_COPTFLAGS) COPTFLAGS+= ${_CPUCFLAGS} .endif INCLUDES= -nostdinc -I- ${INCLMAGIC} -I. -I$S -I$S/dev # This hack lets us use the Intel ACPICA code without spamming a new # include path into 100+ source files. INCLUDES+= -I$S/contrib/dev/acpica # ... and the same for ipfilter INCLUDES+= -I$S/contrib/ipfilter # This hack is to allow kernel compiles to succeed on machines w/out srcdist .if exists($S/../include) INCLUDES+= -I$S/../include .else INCLUDES+= -I/usr/include .endif COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -include opt_global.h CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS} # XXX LOCORE means "don't declare C stuff" not "for locore.s". ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} # Select the correct set of tools. Can't set OBJFORMAT here because it # doesn't get exported into the environment, and if it were exported # then it might break building of utilities. FMT= -elf CFLAGS+= ${FMT} DEFINED_PROF= ${PROF} .if defined(PROF) CFLAGS+= -malign-functions=4 .if ${PROFLEVEL} >= 2 IDENT+= -DGPROF4 -DGUPROF PROF+= -mprofiler-epilogue .endif .endif # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC} PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC} NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \ ${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c GEN_CFILES= $S/$M/$M/genassym.c -SYSTEM_CFILES= vnode_if.c hints.c config.c +SYSTEM_CFILES= vnode_if.c hints.c env.c config.c SYSTEM_SFILES= $S/$M/$M/locore.s SYSTEM_DEP= Makefile ${SYSTEM_OBJS} -SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o config.o hack.So +SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o env.o config.o hack.So SYSTEM_LD= @${LD} ${FMT} -Bdynamic -T $S/conf/ldscript.$M \ -export-dynamic -dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${FMT} ${.TARGET} ; chmod 755 ${.TARGET} SYSTEM_DEP+= $S/conf/ldscript.$M %BEFORE_DEPEND %OBJS %FILES.c %FILES.s %FILES.m %CLEAN .PHONY: all modules all: ${KERNEL_KO} depend: kernel-depend clean: kernel-clean cleandepend: kernel-cleandepend clobber: kernel-clobber tags: kernel-tags install: kernel-install install.debug: kernel-install.debug reinstall: kernel-reinstall reinstall.debug: kernel-reinstall.debug .if !defined(DEBUG) FULLKERNEL= ${KERNEL_KO} .else FULLKERNEL= ${KERNEL_KO}.debug ${KERNEL_KO}: ${FULLKERNEL} ${OBJCOPY} --strip-debug ${FULLKERNEL} ${KERNEL_KO} .endif ${FULLKERNEL}: ${SYSTEM_DEP} vers.o @rm -f ${.TARGET} @echo linking ${.TARGET} ${SYSTEM_LD} ${SYSTEM_LD_TAIL} .if !exists(.depend) ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/} .endif .for mfile in ${MFILES} ${mfile:T:S/.m$/.h/}: ${mfile} perl5 $S/kern/makeobjops.pl -h ${mfile} .endfor kernel-clean: rm -f *.o *.so *.So *.ko *.s eddep errs \ ${FULLKERNEL} ${KERNEL_KO} linterrs makelinks \ setdef[01].c setdefs.h tags \ vers.c vnode_if.c vnode_if.h \ ${MFILES:T:S/.m$/.c/} ${MFILES:T:S/.m$/.h/} \ ${CLEAN} kernel-clobber: find . -type f ! -name version -delete locore.o: $S/$M/$M/locore.s assym.s ${NORMAL_S} # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. hack.So: Makefile touch hack.c ${CC} ${FMT} -shared -nostdlib hack.c -o hack.So rm -f hack.c # this rule stops ./assym.s in .depend from causing problems ./assym.s: assym.s assym.s: $S/kern/genassym.sh genassym.o OBJFORMAT=elf sh $S/kern/genassym.sh genassym.o > ${.TARGET} genassym.o: $S/$M/$M/genassym.c ${CC} -c ${CFLAGS} -elf $S/$M/$M/genassym.c ${SYSTEM_OBJS} genassym.o vers.o: opt_global.h kernel-depend: rm -f .olddep if [ -f .depend ]; then mv .depend .olddep; fi ${MAKE} _kernel-depend _kernel-depend: assym.s vnode_if.h ${BEFORE_DEPEND} \ ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \ ${SYSTEM_SFILES} ${MFILES:T:S/.m$/.h/} if [ -f .olddep ]; then mv .olddep .depend; fi rm -f .newdep mkdep -a -f .newdep ${CFLAGS} ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${ASM_CFLAGS} ${SFILES} ${SYSTEM_SFILES} rm -f .depend mv .newdep .depend kernel-cleandepend: rm -f .depend links: egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ sort -u | comm -23 - dontlink | \ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks; rm -f dontlink kernel-tags: @[ -f .depend ] || { echo "you must make depend first"; exit 1; } sh $S/conf/systags.sh rm -f tags1 sed -e 's, ../, ,' tags > tags1 kernel-install kernel-install.debug: .if exists(${DESTDIR}/boot) @if [ ! -f ${DESTDIR}/boot/device.hints ] ; then \ echo "You must set up a ${DESTDIR}/boot/device.hints file first." ; \ exit 1 ; \ fi @if [ x"`grep device.hints ${DESTDIR}/boot/defaults/loader.conf ${DESTDIR}/boot/loader.conf`" = "x" ]; then \ echo "You must activate /boot/device.hints in loader.conf." ; \ exit 1 ; \ fi .endif @if [ ! -f ${KERNEL_KO}${.TARGET:S/kernel-install//} ] ; then \ echo "You must build a kernel first." ; \ exit 1 ; \ fi .if exists(${DESTDIR}${KODIR}) .if exists(${DESTDIR}${KODIR}.old) @-chflags -R noschg ${DESTDIR}${KODIR}.old -rm -rf ${DESTDIR}${KODIR}.old .endif mv ${DESTDIR}${KODIR} ${DESTDIR}${KODIR}.old .endif mkdir -p ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-install//} ${DESTDIR}${KODIR} kernel-reinstall kernel-reinstall.debug: @-chflags -R noschg ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-reinstall//} ${DESTDIR}${KODIR} .if !defined(MODULES_WITH_WORLD) && !defined(NO_MODULES) && exists($S/modules) all: modules depend: modules-depend clean: modules-clean cleandepend: modules-cleandepend cleandir: modules-cleandir clobber: modules-clobber tags: modules-tags install: modules-install install.debug: modules-install.debug reinstall: modules-reinstall reinstall.debug: modules-reinstall.debug .endif MKMODULESENV= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif .if defined(DEBUG) MKMODULESENV+= DEBUG="${DEBUG}" DEBUG_FLAGS="${DEBUG}" .endif modules: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} all modules-depend: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} depend modules-clean: cd $S/modules ; env ${MKMODULESENV} ${MAKE} clean modules-cleandepend: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandepend modules-clobber: modules-clean rm -rf ${MKMODULESENV} modules-cleandir: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandir modules-tags: cd $S/modules ; env ${MKMODULESENV} ${MAKE} tags modules-install modules-install.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install modules-reinstall modules-reinstall.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install config.o: ${NORMAL_C} vers.c: $S/conf/newvers.sh $S/sys/param.h ${SYSTEM_DEP} sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} # XXX strictly, everything depends on Makefile because changes to ${PROF} # only appear there, but we don't handle that. vers.o: ${NORMAL_C} hints.o: hints.c + ${NORMAL_C} + +env.o: env.c ${NORMAL_C} vnode_if.c: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -c $S/kern/vnode_if.src vnode_if.h: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -h $S/kern/vnode_if.src vnode_if.o: ${NORMAL_C} # Commented out for now pending a better solution. # How do we pick up compiler version specific flags?? #.if exists($S/../share/mk) #.include "$S/../share/mk/bsd.kern.mk" #.else .include #.endif %RULES Index: head/sys/conf/Makefile.ia64 =================================================================== --- head/sys/conf/Makefile.ia64 (revision 82392) +++ head/sys/conf/Makefile.ia64 (revision 82393) @@ -1,340 +1,343 @@ # Makefile.ia64 -- with config changes. # Copyright 1990 W. Jolitz # from: src/sys/conf/Makefile.alpha,v 1.76 # $FreeBSD$ # # Makefile for FreeBSD # # This makefile is constructed from a machine description: # config machineid # Most changes should be made in the machine description # /sys/ia64/conf/``machineid'' # after which you should do # config machineid # after which config should be rerun for all machines. # # The Linux cross tools don't understand -fformat-extensions CWARNFLAGS= -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes \ -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual \ -ansi CC= ia64-unknown-linux-gcc -D__FreeBSD__ -U__linux__ LD= ia64-unknown-linux-ld NM= ia64-unknown-linux-nm SIZE= ia64-unknown-linux-size OBJCOPY= ia64-unknown-linux-objcopy OBJDUMP= ia64-unknown-linux-objdump MACHINE_ARCH= ia64 # Which version of config(8) is required. -%VERSREQ= 500007 +%VERSREQ= 500008 # Can be overridden by makeoptions or /etc/make.conf KERNEL_KO?= kernel KERNEL?= kernel KODIR?= /boot/${KERNEL} STD8X16FONT?= iso .if !defined(S) .if exists(./@/.) S= ./@ .else S= ../../.. .endif .endif M= ${MACHINE_ARCH} SIZE?= size OBJCOPY?= objcopy COPTFLAGS?=-O -pipe .if !defined(NO_CPU_COPTFLAGS) COPTFLAGS+= ${_CPUCFLAGS} .endif INCLUDES= -nostdinc -I- ${INCLMAGIC} -I. -I$S -I$S/dev # This hack lets us use the Intel ACPICA code without spamming a new # include path into 100+ source files. INCLUDES+= -I$S/contrib/dev/acpica # ... and the same for ipfilter INCLUDES+= -I$S/contrib/ipfilter # This hack is to allow kernel compiles to succeed on machines w/out srcdist .if exists($S/../include) INCLUDES+= -I$S/../include .else INCLUDES+= -I/usr/include .endif COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -include opt_global.h CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS} # XXX LOCORE means "don't declare C stuff" not "for locore.s". ASM_CFLAGS= -x assembler-with-cpp -Wa,-x -DLOCORE ${CFLAGS} # Select the correct set of tools. Can't set OBJFORMAT here because it # doesn't get exported into the environment, and if it were exported # then it might break building of utilities. #FMT= -elf CFLAGS+= ${FMT} DEFINED_PROF= ${PROF} .if defined(PROF) CFLAGS+= -malign-functions=4 .if ${PROFLEVEL} >= 2 IDENT+= -DGPROF4 -DGUPROF PROF+= -mprofiler-epilogue .endif .endif # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC} PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC} NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \ ${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c GEN_CFILES= $S/$M/$M/genassym.c -SYSTEM_CFILES= vnode_if.c hints.c config.c +SYSTEM_CFILES= vnode_if.c hints.c env.c config.c SYSTEM_SFILES= $S/$M/$M/locore.s SYSTEM_DEP= Makefile ${SYSTEM_OBJS} -SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o config.o \ +SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o env.o config.o \ # hack.So ski can't cope with dynamic relocs SYSTEM_LD= @${LD} ${FMT} -Bdynamic -T $S/conf/ldscript.$M \ -e locorestart \ -export-dynamic -dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${FMT} ${.TARGET} ; chmod 755 ${.TARGET} SYSTEM_DEP+= $S/conf/ldscript.$M %BEFORE_DEPEND %OBJS %FILES.c %FILES.s %FILES.m %CLEAN .PHONY: all modules all: ${KERNEL_KO} depend: kernel-depend clean: kernel-clean cleandepend: kernel-cleandepend clobber: kernel-clobber tags: kernel-tags install: kernel-install install.debug: kernel-install.debug reinstall: kernel-reinstall reinstall.debug: kernel-reinstall.debug .if !defined(DEBUG) FULLKERNEL= ${KERNEL_KO} .else FULLKERNEL= ${KERNEL_KO}.debug ${KERNEL_KO}: ${FULLKERNEL} ${OBJCOPY} --strip-debug ${FULLKERNEL} ${KERNEL_KO} .endif ${FULLKERNEL}: ${SYSTEM_DEP} vers.o @rm -f ${.TARGET} @echo linking ${.TARGET} ${SYSTEM_LD} ${SYSTEM_LD_TAIL} .if !exists(.depend) ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/} .endif .for mfile in ${MFILES} ${mfile:T:S/.m$/.h/}: ${mfile} perl5 $S/kern/makeobjops.pl -h ${mfile} .endfor kernel-clean: rm -f *.o *.so *.So *.ko *.s eddep errs \ ${FULLKERNEL} ${KERNEL_KO} linterrs makelinks \ setdef[01].c setdefs.h tags \ vers.c vnode_if.c vnode_if.h \ ${MFILES:T:S/.m$/.c/} ${MFILES:T:S/.m$/.h/} \ ${CLEAN} kernel-clobber: find . -type f ! -name version -delete locore.o: $S/$M/$M/locore.s assym.s ${NORMAL_S} # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. hack.So: Makefile touch hack.c ${CC} ${FMT} -shared -nostdlib hack.c -o hack.So rm -f hack.c # this rule stops ./assym.s in .depend from causing problems ./assym.s: assym.s assym.s: $S/kern/genassym.sh genassym.o NM=${NM} sh $S/kern/genassym.sh genassym.o > ${.TARGET} genassym.o: $S/$M/$M/genassym.c ${CC} -c ${CFLAGS} $S/$M/$M/genassym.c ${SYSTEM_OBJS} genassym.o vers.o: opt_global.h kernel-depend: rm -f .olddep if [ -f .depend ]; then mv .depend .olddep; fi ${MAKE} _kernel-depend _kernel-depend: assym.s vnode_if.h ${BEFORE_DEPEND} \ ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \ ${SYSTEM_SFILES} ${MFILES:T:S/.m$/.h/} if [ -f .olddep ]; then mv .olddep .depend; fi rm -f .newdep CC="${CC}" mkdep -a -f .newdep ${CFLAGS} ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${ASM_CFLAGS} ${SFILES} ${SYSTEM_SFILES} rm -f .depend mv .newdep .depend kernel-cleandepend: rm -f .depend links: egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ sort -u | comm -23 - dontlink | \ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks; rm -f dontlink kernel-tags: @[ -f .depend ] || { echo "you must make depend first"; exit 1; } sh $S/conf/systags.sh rm -f tags1 sed -e 's, ../, ,' tags > tags1 kernel-install kernel-install.debug: .if exists(${DESTDIR}/boot) @if [ ! -f ${DESTDIR}/boot/device.hints ] ; then \ echo "You must set up a ${DESTDIR}/boot/device.hints file first." ; \ exit 1 ; \ fi @if [ x"`grep device.hints ${DESTDIR}/boot/defaults/loader.conf ${DESTDIR}/boot/loader.conf`" = "x" ]; then \ echo "You must activate /boot/device.hints in loader.conf." ; \ exit 1 ; \ fi .endif @if [ ! -f ${KERNEL_KO}${.TARGET:S/kernel-install//} ] ; then \ echo "You must build a kernel first." ; \ exit 1 ; \ fi .if exists(${DESTDIR}${KODIR}) .if exists(${DESTDIR}${KODIR}.old) @-chflags -R noschg ${DESTDIR}${KODIR}.old -rm -rf ${DESTDIR}${KODIR}.old .endif mv ${DESTDIR}${KODIR} ${DESTDIR}${KODIR}.old .endif mkdir -p ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-install//} ${DESTDIR}${KODIR} kernel-reinstall kernel-reinstall.debug: @-chflags -R noschg ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-reinstall//} ${DESTDIR}${KODIR} .if !defined(MODULES_WITH_WORLD) && !defined(NO_MODULES) && exists($S/modules) all: modules depend: modules-depend clean: modules-clean cleandepend: modules-cleandepend cleandir: modules-cleandir clobber: modules-clobber tags: modules-tags install: modules-install install.debug: modules-install.debug reinstall: modules-reinstall reinstall.debug: modules-reinstall.debug .endif MKMODULESENV= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif .if defined(DEBUG) MKMODULESENV+= DEBUG="${DEBUG}" DEBUG_FLAGS="${DEBUG}" .endif modules: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} all modules-depend: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} depend modules-clean: cd $S/modules ; env ${MKMODULESENV} ${MAKE} clean modules-cleandepend: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandepend modules-clobber: modules-clean rm -rf ${MKMODULESENV} modules-cleandir: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandir modules-tags: cd $S/modules ; env ${MKMODULESENV} ${MAKE} tags modules-install modules-install.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install modules-reinstall modules-reinstall.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install config.o: ${NORMAL_C} vers.c: $S/conf/newvers.sh $S/sys/param.h ${SYSTEM_DEP} sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} # XXX strictly, everything depends on Makefile because changes to ${PROF} # only appear there, but we don't handle that. vers.o: ${NORMAL_C} hints.o: hints.c + ${NORMAL_C} + +env.o: env.c ${NORMAL_C} vnode_if.c: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -c $S/kern/vnode_if.src vnode_if.h: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -h $S/kern/vnode_if.src vnode_if.o: ${NORMAL_C} .include %RULES Index: head/sys/conf/Makefile.pc98 =================================================================== --- head/sys/conf/Makefile.pc98 (revision 82392) +++ head/sys/conf/Makefile.pc98 (revision 82393) @@ -1,339 +1,342 @@ # Makefile for FreeBSD(98) after: # # Makefile.i386 -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 # $FreeBSD$ # # Makefile for FreeBSD # # This makefile is constructed from a machine description: # config machineid # Most changes should be made in the machine description # /sys/i386/conf/``machineid'' # after which you should do # config machineid # Generic makefile changes should be made in # /sys/i386/conf/Makefile.i386 # after which config should be rerun for all machines. # # Which version of config(8) is required. -%VERSREQ= 500007 +%VERSREQ= 500008 # Can be overridden by makeoptions or /etc/make.conf KERNEL_KO?= kernel KERNEL?= kernel KODIR?= /boot/${KERNEL} #STD8X16FONT?= iso .if !defined(S) .if exists(./@/.) S= ./@ .else S= ../../.. .endif .endif M= ${MACHINE_ARCH} SIZE?= size OBJCOPY?= objcopy COPTFLAGS?=-O -pipe .if !defined(NO_CPU_COPTFLAGS) COPTFLAGS+= ${_CPUCFLAGS} .endif INCLUDES= -nostdinc -I- ${INCLMAGIC} -I. -I$S -I$S/dev # This hack lets us use the Intel ACPICA code without spamming a new # include path into 100+ source files. INCLUDES+= -I$S/contrib/dev/acpica # ... and the same for ipfilter INCLUDES+= -I$S/contrib/ipfilter # This hack is to allow kernel compiles to succeed on machines w/out srcdist .if exists($S/../include) INCLUDES+= -I$S/../include .else INCLUDES+= -I/usr/include .endif COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -include opt_global.h CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS} # XXX LOCORE means "don't declare C stuff" not "for locore.s". ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} # Select the correct set of tools. Can't set OBJFORMAT here because it # doesn't get exported into the environment, and if it were exported # then it might break building of utilities. FMT= -elf CFLAGS+= ${FMT} DEFINED_PROF= ${PROF} .if defined(PROF) CFLAGS+= -malign-functions=4 .if ${PROFLEVEL} >= 2 IDENT+= -DGPROF4 -DGUPROF PROF+= -mprofiler-epilogue .endif .endif # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC} PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC} NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \ ${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c GEN_CFILES= $S/$M/$M/genassym.c -SYSTEM_CFILES= vnode_if.c hints.c config.c +SYSTEM_CFILES= vnode_if.c hints.c env.c config.c SYSTEM_SFILES= $S/$M/$M/locore.s SYSTEM_DEP= Makefile ${SYSTEM_OBJS} -SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o config.o hack.So +SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o env.o config.o hack.So SYSTEM_LD= @${LD} ${FMT} -Bdynamic -T $S/conf/ldscript.$M \ -export-dynamic -dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${FMT} ${.TARGET} ; chmod 755 ${.TARGET} SYSTEM_DEP+= $S/conf/ldscript.$M %BEFORE_DEPEND %OBJS %FILES.c %FILES.s %FILES.m %CLEAN .PHONY: all modules all: ${KERNEL_KO} depend: kernel-depend clean: kernel-clean cleandepend: kernel-cleandepend clobber: kernel-clobber tags: kernel-tags install: kernel-install install.debug: kernel-install.debug reinstall: kernel-reinstall reinstall.debug: kernel-reinstall.debug .if !defined(DEBUG) FULLKERNEL= ${KERNEL_KO} .else FULLKERNEL= ${KERNEL_KO}.debug ${KERNEL_KO}: ${FULLKERNEL} ${OBJCOPY} --strip-debug ${FULLKERNEL} ${KERNEL_KO} .endif ${FULLKERNEL}: ${SYSTEM_DEP} vers.o @rm -f ${.TARGET} @echo linking ${.TARGET} ${SYSTEM_LD} ${SYSTEM_LD_TAIL} .if !exists(.depend) ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/} .endif .for mfile in ${MFILES} ${mfile:T:S/.m$/.h/}: ${mfile} perl5 $S/kern/makeobjops.pl -h ${mfile} .endfor kernel-clean: rm -f *.o *.so *.So *.ko *.s eddep errs \ ${FULLKERNEL} ${KERNEL_KO} linterrs makelinks \ setdef[01].c setdefs.h tags \ vers.c vnode_if.c vnode_if.h \ ${MFILES:T:S/.m$/.c/} ${MFILES:T:S/.m$/.h/} \ ${CLEAN} kernel-clobber: find . -type f ! -name version -delete locore.o: $S/$M/$M/locore.s assym.s ${NORMAL_S} # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. hack.So: Makefile touch hack.c ${CC} ${FMT} -shared -nostdlib hack.c -o hack.So rm -f hack.c # this rule stops ./assym.s in .depend from causing problems ./assym.s: assym.s assym.s: $S/kern/genassym.sh genassym.o OBJFORMAT=elf sh $S/kern/genassym.sh genassym.o > ${.TARGET} genassym.o: $S/$M/$M/genassym.c ${CC} -c ${CFLAGS} -elf $S/$M/$M/genassym.c ${SYSTEM_OBJS} genassym.o vers.o: opt_global.h kernel-depend: rm -f ./machine ; ln -s $S/$M/include ./machine rm -f .olddep if [ -f .depend ]; then mv .depend .olddep; fi ${MAKE} _kernel-depend _kernel-depend: assym.s vnode_if.h ${BEFORE_DEPEND} \ ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \ ${SYSTEM_SFILES} ${MFILES:T:S/.m$/.h/} if [ -f .olddep ]; then mv .olddep .depend; fi rm -f .newdep mkdep -a -f .newdep ${CFLAGS} ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${ASM_CFLAGS} ${SFILES} ${SYSTEM_SFILES} rm -f .depend mv .newdep .depend kernel-cleandepend: rm -f .depend links: egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ sort -u | comm -23 - dontlink | \ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks; rm -f dontlink kernel-tags: @[ -f .depend ] || { echo "you must make depend first"; exit 1; } sh $S/conf/systags.sh rm -f tags1 sed -e 's, ../, ,' tags > tags1 kernel-install kernel-install.debug: .if exists(${DESTDIR}/boot) @if [ ! -f ${DESTDIR}/boot/device.hints ] ; then \ echo "You must set up a ${DESTDIR}/boot/device.hints file first." ; \ exit 1 ; \ fi @if [ x"`grep device.hints ${DESTDIR}/boot/defaults/loader.conf ${DESTDIR}/boot/loader.conf`" = "x" ]; then \ echo "You must activate /boot/device.hints in loader.conf." ; \ exit 1 ; \ fi .endif @if [ ! -f ${KERNEL_KO}${.TARGET:S/kernel-install//} ] ; then \ echo "You must build a kernel first." ; \ exit 1 ; \ fi .if exists(${DESTDIR}${KODIR}) .if exists(${DESTDIR}${KODIR}.old) @-chflags -R noschg ${DESTDIR}${KODIR}.old -rm -rf ${DESTDIR}${KODIR}.old .endif mv ${DESTDIR}${KODIR} ${DESTDIR}${KODIR}.old .endif mkdir -p ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-install//} ${DESTDIR}${KODIR} kernel-reinstall kernel-reinstall.debug: @-chflags -R noschg ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-reinstall//} ${DESTDIR}${KODIR} .if !defined(MODULES_WITH_WORLD) && !defined(NO_MODULES) && exists($S/modules) all: modules depend: modules-depend clean: modules-clean cleandepend: modules-cleandepend cleandir: modules-cleandir clobber: modules-clobber tags: modules-tags install: modules-install install.debug: modules-install.debug reinstall: modules-reinstall reinstall.debug: modules-reinstall.debug .endif MKMODULESENV= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif .if defined(DEBUG) MKMODULESENV+= DEBUG="${DEBUG}" DEBUG_FLAGS="${DEBUG}" .endif MKMODULESENV+= MACHINE=pc98 modules: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} all modules-depend: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} depend modules-clean: cd $S/modules ; env ${MKMODULESENV} ${MAKE} clean modules-cleandepend: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandepend modules-clobber: modules-clean rm -rf ${MKMODULESENV} modules-cleandir: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandir modules-tags: cd $S/modules ; env ${MKMODULESENV} ${MAKE} tags modules-install modules-install.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install modules-reinstall modules-reinstall.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install config.o: ${NORMAL_C} vers.c: $S/conf/newvers.sh $S/sys/param.h ${SYSTEM_DEP} sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} # XXX strictly, everything depends on Makefile because changes to ${PROF} # only appear there, but we don't handle that. vers.o: ${NORMAL_C} hints.o: hints.c + ${NORMAL_C} + +env.o: env.c ${NORMAL_C} vnode_if.c: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -c $S/kern/vnode_if.src vnode_if.h: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -h $S/kern/vnode_if.src vnode_if.o: ${NORMAL_C} # Commented out for now pending a better solution. # How do we pick up compiler version specific flags?? #.if exists($S/../share/mk) #.include "$S/../share/mk/bsd.kern.mk" #.else .include #.endif %RULES Index: head/sys/conf/Makefile.powerpc =================================================================== --- head/sys/conf/Makefile.powerpc (revision 82392) +++ head/sys/conf/Makefile.powerpc (revision 82393) @@ -1,338 +1,341 @@ # Makefile.powerpc -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 # $FreeBSD$ # # Makefile for FreeBSD # # This makefile is constructed from a machine description: # config machineid # Most changes should be made in the machine description # /sys/powerpc/conf/``machineid'' # after which you should do # config machineid # Generic makefile changes should be made in # /sys/powerpc/conf/Makefile.powerpc # after which config should be rerun for all machines. # # Which version of config(8) is required. -%VERSREQ= 500007 +%VERSREQ= 500008 # Temporary stuff while we're still embryonic NO_MODULES?= yes # Can be overridden by makeoptions or /etc/make.conf KERNEL_KO?= kernel KERNEL?= kernel KODIR?= /boot/${KERNEL} STD8X16FONT?= iso .if !defined(S) .if exists(./@/.) S= ./@ .else S= ../../.. .endif .endif M= ${MACHINE_ARCH} SIZE?= size OBJCOPY?= objcopy COPTFLAGS?=-O -pipe .if !defined(NO_CPU_COPTFLAGS) COPTFLAGS+= ${_CPUCFLAGS} .endif INCLUDES= -nostdinc -I- ${INCLMAGIC} -I. -I$S -I$S/dev # This hack lets us use the Intel ACPICA code without spamming a new # include path into 100+ source files. INCLUDES+= -I$S/contrib/dev/acpica # ... and the same for ipfilter INCLUDES+= -I$S/contrib/ipfilter # This hack is to allow kernel compiles to succeed on machines w/out srcdist .if exists($S/../include) INCLUDES+= -I$S/../include .else INCLUDES+= -I/usr/include .endif COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -D__ELF__ -D__FreeBSD__ -include opt_global.h -msoft-float CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS} # XXX LOCORE means "don't declare C stuff" not "for locore.s". ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} # Select the correct set of tools. Can't set OBJFORMAT here because it # doesn't get exported into the environment, and if it were exported # then it might break building of utilities. FMT= -elf CFLAGS+= ${FMT} DEFINED_PROF= ${PROF} .if defined(PROF) CFLAGS+= -malign-functions=4 .if ${PROFLEVEL} >= 2 IDENT+= -DGPROF4 -DGUPROF PROF+= -mprofiler-epilogue .endif .endif # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC} PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC} NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \ ${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c GEN_CFILES= $S/$M/$M/genassym.c -SYSTEM_CFILES= vnode_if.c hints.c config.c +SYSTEM_CFILES= vnode_if.c hints.c env.c config.c SYSTEM_SFILES= $S/$M/$M/locore.s SYSTEM_DEP= Makefile ${SYSTEM_OBJS} -SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o config.o hack.So +SYSTEM_OBJS= locore.o vnode_if.o ${OBJS} hints.o env.o config.o hack.So SYSTEM_LD= @${LD} ${FMT} -Bdynamic -T $S/conf/ldscript.$M \ -export-dynamic -dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${FMT} ${.TARGET} ; chmod 755 ${.TARGET} SYSTEM_DEP+= $S/conf/ldscript.$M %BEFORE_DEPEND %OBJS %FILES.c %FILES.s %FILES.m %CLEAN .PHONY: all modules all: ${KERNEL_KO} depend: kernel-depend clean: kernel-clean cleandepend: kernel-cleandepend clobber: kernel-clobber tags: kernel-tags install: kernel-install install.debug: kernel-install.debug reinstall: kernel-reinstall reinstall.debug: kernel-reinstall.debug .if !defined(DEBUG) FULLKERNEL= ${KERNEL_KO} .else FULLKERNEL= ${KERNEL_KO}.debug ${KERNEL_KO}: ${FULLKERNEL} ${OBJCOPY} --strip-debug ${FULLKERNEL} ${KERNEL_KO} .endif ${FULLKERNEL}: ${SYSTEM_DEP} vers.o @rm -f ${.TARGET} @echo linking ${.TARGET} ${SYSTEM_LD} ${SYSTEM_LD_TAIL} .if !exists(.depend) ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/} .endif .for mfile in ${MFILES} ${mfile:T:S/.m$/.h/}: ${mfile} perl5 $S/kern/makeobjops.pl -h ${mfile} .endfor kernel-clean: rm -f *.o *.so *.So *.ko *.s eddep errs \ ${FULLKERNEL} ${KERNEL_KO} linterrs makelinks \ setdef[01].c setdefs.h tags \ vers.c vnode_if.c vnode_if.h \ ${MFILES:T:S/.m$/.c/} ${MFILES:T:S/.m$/.h/} \ ${CLEAN} kernel-clobber: find . -type f ! -name version -delete locore.o: $S/$M/$M/locore.s assym.s ${NORMAL_S} # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. hack.So: Makefile touch hack.c ${CC} ${FMT} -shared -nostdlib hack.c -o hack.So rm -f hack.c # this rule stops ./assym.s in .depend from causing problems ./assym.s: assym.s assym.s: $S/kern/genassym.sh genassym.o OBJFORMAT=elf sh $S/kern/genassym.sh genassym.o > ${.TARGET} genassym.o: $S/$M/$M/genassym.c ${CC} -c ${CFLAGS} -elf $S/$M/$M/genassym.c ${SYSTEM_OBJS} genassym.o vers.o: opt_global.h kernel-depend: rm -f .olddep if [ -f .depend ]; then mv .depend .olddep; fi ${MAKE} _kernel-depend _kernel-depend: assym.s vnode_if.h ${BEFORE_DEPEND} \ ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \ ${SYSTEM_SFILES} ${MFILES:T:S/.m$/.h/} if [ -f .olddep ]; then mv .olddep .depend; fi rm -f .newdep mkdep -a -f .newdep ${CFLAGS} ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${ASM_CFLAGS} ${SFILES} ${SYSTEM_SFILES} rm -f .depend mv .newdep .depend kernel-cleandepend: rm -f .depend links: egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ sort -u | comm -23 - dontlink | \ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks; rm -f dontlink kernel-tags: @[ -f .depend ] || { echo "you must make depend first"; exit 1; } sh $S/conf/systags.sh rm -f tags1 sed -e 's, ../, ,' tags > tags1 kernel-install kernel-install.debug: .if exists(${DESTDIR}/boot) @if [ ! -f ${DESTDIR}/boot/device.hints ] ; then \ echo "You must set up a ${DESTDIR}/boot/device.hints file first." ; \ exit 1 ; \ fi @if [ x"`grep device.hints ${DESTDIR}/boot/defaults/loader.conf ${DESTDIR}/boot/loader.conf`" = "x" ]; then \ echo "You must activate /boot/device.hints in loader.conf." ; \ exit 1 ; \ fi .endif @if [ ! -f ${KERNEL_KO}${.TARGET:S/kernel-install//} ] ; then \ echo "You must build a kernel first." ; \ exit 1 ; \ fi .if exists(${DESTDIR}${KODIR}) .if exists(${DESTDIR}${KODIR}.old) @-chflags -R noschg ${DESTDIR}${KODIR}.old -rm -rf ${DESTDIR}${KODIR}.old .endif mv ${DESTDIR}${KODIR} ${DESTDIR}${KODIR}.old .endif mkdir -p ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-install//} ${DESTDIR}${KODIR} kernel-reinstall kernel-reinstall.debug: @-chflags -R noschg ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-reinstall//} ${DESTDIR}${KODIR} .if !defined(MODULES_WITH_WORLD) && !defined(NO_MODULES) && exists($S/modules) all: modules depend: modules-depend clean: modules-clean cleandepend: modules-cleandepend cleandir: modules-cleandir clobber: modules-clobber tags: modules-tags install: modules-install install.debug: modules-install.debug reinstall: modules-reinstall reinstall.debug: modules-reinstall.debug .endif MKMODULESENV= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif .if defined(DEBUG) MKMODULESENV+= DEBUG="${DEBUG}" DEBUG_FLAGS="${DEBUG}" .endif modules: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} all modules-depend: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} depend modules-clean: cd $S/modules ; env ${MKMODULESENV} ${MAKE} clean modules-cleandepend: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandepend modules-clobber: modules-clean rm -rf ${MKMODULESENV} modules-cleandir: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandir modules-tags: cd $S/modules ; env ${MKMODULESENV} ${MAKE} tags modules-install modules-install.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install modules-reinstall modules-reinstall.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install config.o: ${NORMAL_C} vers.c: $S/conf/newvers.sh $S/sys/param.h ${SYSTEM_DEP} sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} # XXX strictly, everything depends on Makefile because changes to ${PROF} # only appear there, but we don't handle that. vers.o: ${NORMAL_C} hints.o: hints.c + ${NORMAL_C} + +env.o: env.c ${NORMAL_C} vnode_if.c: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -c $S/kern/vnode_if.src vnode_if.h: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -h $S/kern/vnode_if.src vnode_if.o: ${NORMAL_C} # Commented out for now pending a better solution. # How do we pick up compiler version specific flags?? #.if exists($S/../share/mk) #.include "$S/../share/mk/bsd.kern.mk" #.else .include #.endif %RULES Index: head/sys/conf/Makefile.sparc64 =================================================================== --- head/sys/conf/Makefile.sparc64 (revision 82392) +++ head/sys/conf/Makefile.sparc64 (revision 82393) @@ -1,349 +1,352 @@ # Makefile.sparc64 -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 # $FreeBSD$ # # Makefile for FreeBSD # # This makefile is constructed from a machine description: # config machineid # Most changes should be made in the machine description # /sys/sparc64/conf/``machineid'' # after which you should do # config machineid # Generic makefile changes should be made in # /sys/sparc64/conf/Makefile.sparc64 # after which config should be rerun for all machines. # MACHINE_ARCH= sparc64 AR= sparc64-ar CC= sparc64-unknown-elf-gcc -D__sparc64__ LD= sparc64-ld NM= sparc64-nm OBJCOPY= sparc64-objcopy OBJDUMP= sparc64-objdump RANLIB= sparc64-ranlib SIZE= sparc64-size CWARNFLAGS= -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes \ -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual \ -ansi # Which version of config(8) is required. -%VERSREQ= 500007 +%VERSREQ= 500008 # Can be overridden by makeoptions or /etc/make.conf KERNEL_KO?= kernel KERNEL?= kernel KODIR?= /boot/${KERNEL} STD8X16FONT?= iso .if !defined(S) .if exists(./@/.) S= ./@ .else S= ../../.. .endif .endif M= ${MACHINE_ARCH} SIZE?= size OBJCOPY?= objcopy COPTFLAGS?=-O -pipe .if !defined(NO_CPU_COPTFLAGS) COPTFLAGS+= ${_CPUCFLAGS} .endif INCLUDES= -nostdinc -I- ${INCLMAGIC} -I. -I$S -I$S/dev # This hack is to allow kernel compiles to succeed on machines w/out srcdist .if exists($S/../include) INCLUDES+= -I$S/../include .else INCLUDES+= -I/usr/include .endif COPTS= ${INCLUDES} ${IDENT} -D_KERNEL -include opt_global.h CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS} -mcmodel=medlow # XXX LOCORE means "don't declare C stuff" not "for locore.s". ASM_CFLAGS= -x assembler-with-cpp -DLOCORE ${CFLAGS} # Select the correct set of tools. Can't set OBJFORMAT here because it # doesn't get exported into the environment, and if it were exported # then it might break building of utilities. FMT= CFLAGS+= ${FMT} DEFINED_PROF= ${PROF} .if defined(PROF) CFLAGS+= -malign-functions=4 .if ${PROFLEVEL} >= 2 IDENT+= -DGPROF4 -DGUPROF PROF+= -mprofiler-epilogue .endif .endif # Put configuration-specific C flags last (except for ${PROF}) so that they # can override the others. CFLAGS+= ${CONF_CFLAGS} NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${.IMPSRC} NORMAL_S= ${CC} -c ${ASM_CFLAGS} ${.IMPSRC} PROFILE_C= ${CC} -c ${CFLAGS} ${.IMPSRC} NORMAL_M= perl5 $S/kern/makeobjops.pl -c $<; \ ${CC} -c ${CFLAGS} ${PROF} ${.PREFIX}.c GEN_CFILES= $S/$M/$M/genassym.c -SYSTEM_CFILES= vnode_if.c hints.c config.c +SYSTEM_CFILES= vnode_if.c hints.c env.c config.c SYSTEM_SFILES= $S/$M/$M/locore.s $S/$M/$M/exception.s SYSTEM_DEP= Makefile ${SYSTEM_OBJS} -SYSTEM_OBJS= locore.o exception.o vnode_if.o ${OBJS} hints.o config.o hack.So +SYSTEM_OBJS= locore.o exception.o vnode_if.o ${OBJS} hints.o env.o config.o hack.So SYSTEM_LD= @${LD} ${FMT} -Bdynamic -T $S/conf/ldscript.$M \ -export-dynamic -dynamic-linker /red/herring \ -o ${.TARGET} -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @${OBJCOPY} --strip-symbol gcc2_compiled. ${.TARGET} ; \ ${SIZE} ${FMT} ${.TARGET} ; chmod 755 ${.TARGET} SYSTEM_DEP+= $S/conf/ldscript.$M %BEFORE_DEPEND %OBJS %FILES.c %FILES.s %FILES.m %CLEAN .PHONY: all modules all: ${KERNEL_KO} depend: kernel-depend clean: kernel-clean cleandepend: kernel-cleandepend clobber: kernel-clobber tags: kernel-tags install: kernel-install install.debug: kernel-install.debug reinstall: kernel-reinstall reinstall.debug: kernel-reinstall.debug .if !defined(DEBUG) FULLKERNEL= ${KERNEL_KO} .else FULLKERNEL= ${KERNEL_KO}.debug ${KERNEL_KO}: ${FULLKERNEL} ${OBJCOPY} --strip-debug ${FULLKERNEL} ${KERNEL_KO} .endif ${FULLKERNEL}: ${SYSTEM_DEP} vers.o @rm -f ${.TARGET} @echo linking ${.TARGET} ${SYSTEM_LD} ${SYSTEM_LD_TAIL} .if !exists(.depend) ${SYSTEM_OBJS}: vnode_if.h ${BEFORE_DEPEND:M*.h} ${MFILES:T:S/.m$/.h/} .endif .for mfile in ${MFILES} ${mfile:T:S/.m$/.h/}: ${mfile} perl5 $S/kern/makeobjops.pl -h ${mfile} .endfor kernel-clean: rm -f *.o *.so *.So *.ko *.s eddep errs \ ${FULLKERNEL} ${KERNEL_KO} linterrs makelinks \ setdef[01].c setdefs.h tags \ vers.c vnode_if.c vnode_if.h \ ${MFILES:T:S/.m$/.c/} ${MFILES:T:S/.m$/.h/} \ ${CLEAN} kernel-clobber: find . -type f ! -name version -delete #lint: /tmp # @lint -hbxn -DGENERIC -Dvolatile= ${COPTS} \ # $S/$M/$M/Locore.c ${CFILES} | \ # grep -v 'struct/union .* never defined' | \ # grep -v 'possible pointer alignment problem' locore.o: $S/$M/$M/locore.s assym.s ${NORMAL_S} exception.o: $S/$M/$M/exception.s assym.s ${NORMAL_S} # This is a hack. BFD "optimizes" away dynamic mode if there are no # dynamic references. We could probably do a '-Bforcedynamic' mode like # in the a.out ld. For now, this works. hack.So: Makefile touch hack.c ${CC} ${FMT} -Wl,-shared -nostdlib hack.c -o hack.So rm -f hack.c # this rule stops ./assym.s in .depend from causing problems ./assym.s: assym.s assym.s: $S/kern/genassym.sh genassym.o OBJFORMAT=elf NM=${NM} sh $S/kern/genassym.sh genassym.o > ${.TARGET} genassym.o: $S/$M/$M/genassym.c ${CC} -c ${CFLAGS} -elf $S/$M/$M/genassym.c ${SYSTEM_OBJS} genassym.o vers.o: opt_global.h kernel-depend: rm -f .olddep if [ -f .depend ]; then mv .depend .olddep; fi ${MAKE} _kernel-depend _kernel-depend: assym.s vnode_if.h ${BEFORE_DEPEND} \ ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} ${SFILES} \ ${SYSTEM_SFILES} ${MFILES:T:S/.m$/.h/} if [ -f .olddep ]; then mv .olddep .depend; fi rm -f .newdep env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${CFLAGS} ${CFILES} ${SYSTEM_CFILES} ${GEN_CFILES} env MKDEP_CPP="${CC} -E" \ mkdep -a -f .newdep ${ASM_CFLAGS} ${SFILES} ${SYSTEM_SFILES} rm -f .depend mv .newdep .depend kernel-cleandepend: rm -f .depend links: egrep '#if' ${CFILES} | sed -f $S/conf/defines | \ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \ sort -u | comm -23 - dontlink | \ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks sh makelinks; rm -f dontlink kernel-tags: @[ -f .depend ] || { echo "you must make depend first"; exit 1; } sh $S/conf/systags.sh rm -f tags1 sed -e 's, ../, ,' tags > tags1 kernel-install kernel-install.debug: .if exists(${DESTDIR}/boot) @if [ ! -f ${DESTDIR}/boot/device.hints ] ; then \ echo "You must set up a ${DESTDIR}/boot/device.hints file first." ; \ exit 1 ; \ fi @if [ x"`grep device.hints ${DESTDIR}/boot/defaults/loader.conf ${DESTDIR}/boot/loader.conf`" = "x" ]; then \ echo "You must activate /boot/device.hints in loader.conf." ; \ exit 1 ; \ fi .endif @if [ ! -f ${KERNEL_KO}${.TARGET:S/kernel-install//} ] ; then \ echo "You must build a kernel first." ; \ exit 1 ; \ fi .if exists(${DESTDIR}${KODIR}) .if exists(${DESTDIR}${KODIR}.old) @-chflags -R noschg ${DESTDIR}${KODIR}.old -rm -rf ${DESTDIR}${KODIR}.old .endif mv ${DESTDIR}${KODIR} ${DESTDIR}${KODIR}.old .endif mkdir -p ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-install//} ${DESTDIR}${KODIR} kernel-reinstall kernel-reinstall.debug: @-chflags -R noschg ${DESTDIR}${KODIR} install -c -m 555 -o root -g wheel \ ${KERNEL_KO}${.TARGET:S/kernel-reinstall//} ${DESTDIR}${KODIR} .if !defined(MODULES_WITH_WORLD) && !defined(NO_MODULES) && exists($S/modules) all: modules depend: modules-depend clean: modules-clean cleandepend: modules-cleandepend cleandir: modules-cleandir clobber: modules-clobber tags: modules-tags install: modules-install install.debug: modules-install.debug reinstall: modules-reinstall reinstall.debug: modules-reinstall.debug .endif MKMODULESENV= MAKEOBJDIRPREFIX=${.OBJDIR}/modules KMODDIR=${KODIR} .if defined(MODULES_OVERRIDE) MKMODULESENV+= MODULES_OVERRIDE="${MODULES_OVERRIDE}" .endif modules: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} all modules-depend: @mkdir -p ${.OBJDIR}/modules cd $S/modules ; env ${MKMODULESENV} ${MAKE} obj ; \ env ${MKMODULESENV} ${MAKE} depend modules-clean: cd $S/modules ; env ${MKMODULESENV} ${MAKE} clean modules-cleandepend: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandepend modules-clobber: modules-clean rm -rf ${MKMODULESENV} modules-cleandir: cd $S/modules ; env ${MKMODULESENV} ${MAKE} cleandir modules-tags: cd $S/modules ; env ${MKMODULESENV} ${MAKE} tags modules-install modules-install.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install modules-reinstall modules-reinstall.debug: cd $S/modules ; env ${MKMODULESENV} ${MAKE} install config.o: ${NORMAL_C} vers.c: $S/conf/newvers.sh $S/sys/param.h ${SYSTEM_DEP} sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT} # XXX strictly, everything depends on Makefile because changes to ${PROF} # only appear there, but we don't handle that. vers.o: ${NORMAL_C} hints.o: hints.c + ${NORMAL_C} + +env.o: env.c ${NORMAL_C} vnode_if.c: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -c $S/kern/vnode_if.src vnode_if.h: $S/kern/vnode_if.pl $S/kern/vnode_if.src perl5 $S/kern/vnode_if.pl -h $S/kern/vnode_if.src vnode_if.o: ${NORMAL_C} # Commented out for now pending a better solution. # How do we pick up compiler version specific flags?? #.if exists($S/../share/mk) #.include "$S/../share/mk/bsd.kern.mk" #.else .include #.endif %RULES Index: head/sys/i386/i386/machdep.c =================================================================== --- head/sys/i386/i386/machdep.c (revision 82392) +++ head/sys/i386/i386/machdep.c (revision 82393) @@ -1,2534 +1,2536 @@ /*- * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD$ */ #include "opt_atalk.h" #include "opt_compat.h" #include "opt_cpu.h" #include "opt_ddb.h" #include "opt_inet.h" #include "opt_ipx.h" #include "opt_isa.h" #include "opt_maxmem.h" #include "opt_msgbuf.h" #include "opt_npx.h" #include "opt_perfmon.h" #include "opt_upages.h" /* #include "opt_userconfig.h" */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* pcb.h included via sys/user.h */ #include #ifdef PERFMON #include #endif #ifdef SMP #include #endif #include #include #include #include #include #include extern void init386 __P((int first)); extern void dblfault_handler __P((void)); extern void printcpuinfo(void); /* XXX header file */ extern void earlysetcpuclass(void); /* same header file */ extern void finishidentcpu(void); extern void panicifcpuunsupported(void); extern void initializecpu(void); #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) #define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) static void cpu_startup __P((void *)); #ifdef CPU_ENABLE_SSE static void set_fpregs_xmm __P((struct save87 *, struct savexmm *)); static void fill_fpregs_xmm __P((struct savexmm *, struct save87 *)); #endif /* CPU_ENABLE_SSE */ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL) int _udatasel, _ucodesel; u_int atdevbase; #if defined(SWTCH_OPTIM_STATS) extern int swtch_optim_stats; SYSCTL_INT(_debug, OID_AUTO, swtch_optim_stats, CTLFLAG_RD, &swtch_optim_stats, 0, ""); SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count, CTLFLAG_RD, &tlb_flush_count, 0, ""); #endif #ifdef PC98 static int ispc98 = 1; #else static int ispc98 = 0; #endif SYSCTL_INT(_machdep, OID_AUTO, ispc98, CTLFLAG_RD, &ispc98, 0, ""); int physmem = 0; int cold = 1; #ifdef COMPAT_43 static void osendsig __P((sig_t catcher, int sig, sigset_t *mask, u_long code)); #endif static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem), req); return (error); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "IU", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem - cnt.v_wire_count), req); return (error); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "IU", ""); static int sysctl_hw_availpages(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, i386_btop(avail_end - avail_start), req); return (error); } SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_availpages, "I", ""); int Maxmem = 0; long dumplo; vm_offset_t phys_avail[10]; /* must be 2 less so 0 0 can signal end of chunks */ #define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2) struct kva_md_info kmi; static struct trapframe proc0_tf; #ifndef SMP static struct globaldata __globaldata; #endif struct mtx sched_lock; struct mtx Giant; static void cpu_startup(dummy) void *dummy; { /* * Good {morning,afternoon,evening,night}. */ earlysetcpuclass(); startrtclock(); printcpuinfo(); panicifcpuunsupported(); #ifdef PERFMON perfmon_init(); #endif printf("real memory = %u (%uK bytes)\n", ptoa(Maxmem), ptoa(Maxmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { unsigned int size1; size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08x - 0x%08x, %u bytes (%u pages)\n", phys_avail[indx], phys_avail[indx + 1] - 1, size1, size1 / PAGE_SIZE); } } vm_ksubmap_init(&kmi); #if 0 /* * Calculate callout wheel size */ for (callwheelsize = 1, callwheelbits = 0; callwheelsize < ncallout; callwheelsize <<= 1, ++callwheelbits) ; callwheelmask = callwheelsize - 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(callout, struct callout, ncallout); valloc(callwheel, struct callout_tailq, callwheelsize); /* * Discount the physical memory larger than the size of kernel_map * to avoid eating up all of KVA space. */ if (kernel_map->first_free == NULL) { printf("Warning: no free entries in kernel_map.\n"); physmem_est = physmem; } else { physmem_est = min(physmem, btoc(kernel_map->max_offset - kernel_map->min_offset)); } /* * The nominal buffer size (and minimum KVA allocation) is BKVASIZE. * For the first 64MB of ram nominally allocate sufficient buffers to * cover 1/4 of our ram. Beyond the first 64MB allocate additional * buffers to cover 1/20 of our ram over 64MB. When auto-sizing * the buffer cache we limit the eventual kva reservation to * maxbcache bytes. * * factor represents the 1/4 x ram conversion. */ if (nbuf == 0) { int factor = 4 * BKVASIZE / PAGE_SIZE; nbuf = 50; if (physmem_est > 1024) nbuf += min((physmem_est - 1024) / factor, 16384 / factor); if (physmem_est > 16384) nbuf += (physmem_est - 16384) * 2 / (factor * 5); if (maxbcache && nbuf > maxbcache / BKVASIZE) nbuf = maxbcache / BKVASIZE; } /* * Do not allow the buffer_map to be more then 1/2 the size of the * kernel_map. */ if (nbuf > (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2)) { nbuf = (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2); printf("Warning: nbufs capped at %d\n", nbuf); } nswbuf = max(min(nbuf/4, 256), 16); valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); v = bufhashinit(v); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size); buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, (nbuf*BKVASIZE)); buffer_map->system_map = 1; pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, (nswbuf*MAXPHYS) + pager_map_size); pager_map->system_map = 1; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (16*(ARG_MAX+(PAGE_SIZE*3)))); /* * XXX: Mbuf system machine-specific initializations should * go here, if anywhere. */ /* * Initialize callouts */ SLIST_INIT(&callfree); for (i = 0; i < ncallout; i++) { callout_init(&callout[i], 0); callout[i].c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle); } for (i = 0; i < callwheelsize; i++) { TAILQ_INIT(&callwheel[i]); } mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE); #endif #if defined(USERCONFIG) userconfig(); cninit(); /* the preferred console may have changed */ #endif printf("avail memory = %u (%uK bytes)\n", ptoa(cnt.v_free_count), ptoa(cnt.v_free_count) / 1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); globaldata_register(GLOBALDATA); #ifndef SMP /* For SMP, we delay the cpu_setregs() until after SMP startup. */ cpu_setregs(); #endif } /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ #ifdef COMPAT_43 static void osendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct osigframe sf; struct osigframe *fp; struct proc *p; struct sigacts *psp; struct trapframe *regs; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct osigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct osigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else fp = (struct osigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *fp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)fp) == 0 || !useracc((caddr_t)fp, sizeof(*fp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; } else { /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* Save most if not all of trap frame. */ sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax; sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx; sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx; sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx; sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi; sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi; sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs; sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds; sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss; sf.sf_siginfo.si_sc.sc_es = regs->tf_es; sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs; sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; /* Build the signal context to be used by osigreturn(). */ sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0; SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags; sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno; sf.sf_siginfo.si_sc.sc_err = regs->tf_err; /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs; sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs; sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es; sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* See sendsig() for comments. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, fp, sizeof(*fp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)fp; regs->tf_eip = PS_STRINGS - szosigcode; regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; load_gs(_udatasel); regs->tf_ss = _udatasel; } #endif void sendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct sigframe sf; struct proc *p; struct sigacts *psp; struct trapframe *regs; struct sigframe *sfp; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { PROC_UNLOCK(p); osendsig(catcher, sig, mask, code); return; } #endif regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_gs = rgs(); bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct sigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sfp = (struct sigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *sfp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)sfp) == 0 || !useracc((caddr_t)sfp, sizeof(*sfp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG printf("process %d has trashed its stack\n", p->p_pid); #endif PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_ucontext = (register_t)&sfp->sf_uc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_siginfo = (register_t)&sfp->sf_si; sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; /* Fill siginfo structure. */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void *)regs->tf_err; } else { /* Old FreeBSD-style arguments. */ sf.sf_siginfo = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_uc.uc_mcontext.mc_eflags = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 * mode. It may be set here if we deliver a signal before * getting to vm86 mode, so turn it off. * * Clear PSL_NT to inhibit T_TSSFLT faults on return from * syscalls made by the signal handler. This just avoids * wasting time for our lazy fixup of such faults. PSL_NT * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_ss = _udatasel; } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ #ifdef COMPAT_43 int osigreturn(p, uap) struct proc *p; struct osigreturn_args /* { struct osigcontext *sigcntxp; } */ *uap; { struct trapframe *regs; struct osigcontext *scp; int eflags; regs = p->p_frame; scp = uap->sigcntxp; if (!useracc((caddr_t)scp, sizeof(*scp), VM_PROT_READ)) return (EFAULT); eflags = scp->sc_ps; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } tf->tf_vm86_ds = scp->sc_ds; tf->tf_vm86_es = scp->sc_es; tf->tf_vm86_fs = scp->sc_fs; tf->tf_vm86_gs = scp->sc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ if (!CS_SECURE(scp->sc_cs)) { trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } regs->tf_ds = scp->sc_ds; regs->tf_es = scp->sc_es; regs->tf_fs = scp->sc_fs; } /* Restore remaining registers. */ regs->tf_eax = scp->sc_eax; regs->tf_ebx = scp->sc_ebx; regs->tf_ecx = scp->sc_ecx; regs->tf_edx = scp->sc_edx; regs->tf_esi = scp->sc_esi; regs->tf_edi = scp->sc_edi; regs->tf_cs = scp->sc_cs; regs->tf_ss = scp->sc_ss; regs->tf_isp = scp->sc_isp; PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (scp->sc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif SIGSETOLD(p->p_sigmask, scp->sc_mask); SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; regs->tf_eflags = eflags; return (EJUSTRETURN); } #endif int sigreturn(p, uap) struct proc *p; struct sigreturn_args /* { ucontext_t *sigcntxp; } */ *uap; { struct trapframe *regs; ucontext_t *ucp; int cs, eflags; ucp = uap->sigcntxp; #ifdef COMPAT_43 if (!useracc((caddr_t)ucp, sizeof(struct osigcontext), VM_PROT_READ)) return (EFAULT); if (((struct osigcontext *)ucp)->sc_trapno == 0x01d516) return (osigreturn(p, (struct osigreturn_args *)uap)); /* * Since ucp is not an osigcontext but a ucontext_t, we have to * check again if all of it is accessible. A ucontext_t is * much larger, so instead of just checking for the pointer * being valid for the size of an osigcontext, now check for * it being valid for a whole, new-style ucontext_t. */ #endif if (!useracc((caddr_t)ucp, sizeof(*ucp), VM_PROT_READ)) return (EFAULT); regs = p->p_frame; eflags = ucp->uc_mcontext.mc_eflags; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); tf->tf_eflags = eflags; tf->tf_vm86_ds = tf->tf_ds; tf->tf_vm86_es = tf->tf_es; tf->tf_vm86_fs = tf->tf_fs; tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { printf("sigreturn: eflags = 0x%x\n", eflags); return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ cs = ucp->uc_mcontext.mc_cs; if (!CS_SECURE(cs)) { printf("sigreturn: cs = 0x%x\n", cs); trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); } PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (ucp->uc_mcontext.mc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif p->p_sigmask = ucp->uc_sigmask; SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); return (EJUSTRETURN); } /* * Machine dependent boot() routine * * I haven't seen anything to put here yet * Possibly some stuff might be grafted back here from boot() */ void cpu_boot(int howto) { } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { for (;;) __asm__ ("hlt"); } /* * Hook to idle the CPU when possible. This currently only works in * the !SMP case, as there is no clean way to ensure that a CPU will be * woken when there is work available for it. */ static int cpu_idle_hlt = 1; SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, &cpu_idle_hlt, 0, "Idle loop HLT enable"); /* * Note that we have to be careful here to avoid a race between checking * procrunnable() and actually halting. If we don't do this, we may waste * the time between calling hlt and the next interrupt even though there * is a runnable process. */ void cpu_idle(void) { #ifndef SMP if (cpu_idle_hlt) { disable_intr(); if (procrunnable()) enable_intr(); else { enable_intr(); __asm __volatile("hlt"); } } #endif } /* * Clear registers on exec */ void setregs(p, entry, stack, ps_strings) struct proc *p; u_long entry; u_long stack; u_long ps_strings; { struct trapframe *regs = p->p_frame; struct pcb *pcb = &p->p_addr->u_pcb; if (pcb->pcb_ldt) user_ldt_free(pcb); bzero((char *)regs, sizeof(struct trapframe)); regs->tf_eip = entry; regs->tf_esp = stack; regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T); regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_cs = _ucodesel; /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */ regs->tf_ebx = ps_strings; /* reset %gs as well */ if (pcb == PCPU_GET(curpcb)) load_gs(_udatasel); else pcb->pcb_gs = _udatasel; /* * Reset the hardware debug registers if they were in use. * They won't have any meaning for the newly exec'd process. */ if (pcb->pcb_flags & PCB_DBREGS) { pcb->pcb_dr0 = 0; pcb->pcb_dr1 = 0; pcb->pcb_dr2 = 0; pcb->pcb_dr3 = 0; pcb->pcb_dr6 = 0; pcb->pcb_dr7 = 0; if (pcb == PCPU_GET(curpcb)) { /* * Clear the debug registers on the running * CPU, otherwise they will end up affecting * the next process we switch to. */ reset_dbregs(); } pcb->pcb_flags &= ~PCB_DBREGS; } /* * Initialize the math emulator (if any) for the current process. * Actually, just clear the bit that says that the emulator has * been initialized. Initialization is delayed until the process * traps to the emulator (if it is done at all) mainly because * emulators don't provide an entry point for initialization. */ p->p_addr->u_pcb.pcb_flags &= ~FP_SOFTFP; /* * Arrange to trap the next npx or `fwait' instruction (see npx.c * for why fwait must be trapped at least if there is an npx or an * emulator). This is mainly to handle the case where npx0 is not * configured, since the npx routines normally set up the trap * otherwise. It should be done only at boot time, but doing it * here allows modifying `npx_exists' for testing the emulator on * systems with an npx. */ load_cr0(rcr0() | CR0_MP | CR0_TS); #ifdef DEV_NPX /* Initialize the npx (if any) for the current process. */ npxinit(__INITIAL_NPXCW__); #endif /* * XXX - Linux emulator * Make sure sure edx is 0x0 on entry. Linux binaries depend * on it. */ p->p_retval[1] = 0; } void cpu_setregs(void) { unsigned int cr0; cr0 = rcr0(); cr0 |= CR0_NE; /* Done by npxinit() */ cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */ #ifndef I386_CPU cr0 |= CR0_WP | CR0_AM; #endif load_cr0(cr0); load_gs(_udatasel); } static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) { int error; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (!error && req->newptr) resettodr(); return (error); } SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 0, ""); SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo, CTLFLAG_RD, &bootinfo, bootinfo, ""); SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, &wall_cmos_clock, 0, ""); /* * Initialize 386 and configure to run kernel */ /* * Initialize segments & interrupt table */ int _default_ldt; union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ static struct gate_descriptor idt0[NIDT]; struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ #ifdef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif int private_tss; /* flag indicating private tss */ #if defined(I586_CPU) && !defined(NO_F00F_HACK) extern int has_f00f_bug; #endif static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; extern struct user *proc0paddr; /* software prototypes -- in more palatable form */ struct soft_segment_descriptor gdt_segs[] = { /* GNULL_SEL 0 Null Descriptor */ { 0x0, /* segment base address */ 0x0, /* length */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GCODE_SEL 1 Code Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GDATA_SEL 2 Data Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPRIV_SEL 3 SMP Per-Processor Private Data Descriptor */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPROC0_SEL 4 Proc 0 Tss Descriptor */ { 0x0, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GLDT_SEL 5 LDT Descriptor */ { (int) ldt, /* segment base address */ sizeof(ldt)-1, /* length - all address space */ SDT_SYSLDT, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GUSERLDT_SEL 6 User LDT Descriptor per process */ { (int) ldt, /* segment base address */ (512 * sizeof(union descriptor)-1), /* length */ SDT_SYSLDT, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GTGATE_SEL 7 Null Descriptor - Placeholder */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSLOWMEM_SEL 8 BIOS access to realmode segment 0x40, must be #8 in GDT */ { 0x400, /* segment base address */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPANIC_SEL 9 Panic Tss Descriptor */ { (int) &dblfault_tss, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE32_SEL 10 BIOS 32-bit interface (32bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE16_SEL 11 BIOS 32-bit interface (16bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSDATA_SEL 12 BIOS 32-bit interface (Data) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSUTIL_SEL 13 BIOS 16-bit interface (Utility) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSARGS_SEL 14 BIOS 16-bit interface (Arguments) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Code Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Data Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; void setidt(idx, func, typ, dpl, selec) int idx; inthand_t *func; int typ; int dpl; int selec; { struct gate_descriptor *ip; ip = idt + idx; ip->gd_looffset = (int)func; ip->gd_selector = selec; ip->gd_stkcpy = 0; ip->gd_xx = 0; ip->gd_type = typ; ip->gd_dpl = dpl; ip->gd_p = 1; ip->gd_hioffset = ((int)func)>>16 ; } #define IDTVEC(name) __CONCAT(X,name) extern inthand_t IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); void sdtossd(sd, ssd) struct segment_descriptor *sd; struct soft_segment_descriptor *ssd; { ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; ssd->ssd_type = sd->sd_type; ssd->ssd_dpl = sd->sd_dpl; ssd->ssd_p = sd->sd_p; ssd->ssd_def32 = sd->sd_def32; ssd->ssd_gran = sd->sd_gran; } #define PHYSMAP_SIZE (2 * 8) /* * Populate the (physmap) array with base/bound pairs describing the * available physical memory in the system, then test this memory and * build the phys_avail array describing the actually-available memory. * * If we cannot accurately determine the physical memory map, then use * value from the 0xE801 call, and failing that, the RTC. * * Total memory size may be set by the kernel environment variable * hw.physmem or the compile-time define MAXMEM. */ static void getmemsize(int first) { int i, physmap_idx, pa_indx; u_int basemem, extmem; struct vm86frame vmf; struct vm86context vmc; vm_offset_t pa, physmap[PHYSMAP_SIZE]; pt_entry_t pte; const char *cp; struct bios_smap *smap; bzero(&vmf, sizeof(struct vm86frame)); bzero(physmap, sizeof(physmap)); /* * Perform "base memory" related probes & setup */ vm86_intcall(0x12, &vmf); basemem = vmf.vmf_ax; if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); basemem = 640; } /* * XXX if biosbasemem is now < 640, there is a `hole' * between the end of base memory and the start of * ISA memory. The hole may be empty or it may * contain BIOS code or data. Map it read/write so * that the BIOS can write to it. (Memory from 0 to * the physical end of the kernel is mapped read-only * to begin with and then parts of it are remapped. * The parts that aren't remapped form holes that * remain read-only and are unused by the kernel. * The base memory area is below the physical end of * the kernel and right now forms a read-only hole. * The part of it from PAGE_SIZE to * (trunc_page(biosbasemem * 1024) - 1) will be * remapped and used by the kernel later.) * * This code is similar to the code used in * pmap_mapdev, but since no memory needs to be * allocated we simply change the mapping. */ for (pa = trunc_page(basemem * 1024); pa < ISA_HOLE_START; pa += PAGE_SIZE) { pte = (pt_entry_t)vtopte(pa + KERNBASE); *pte = pa | PG_RW | PG_V; } /* * if basemem != 640, map pages r/w into vm86 page table so * that the bios can scribble on it. */ pte = (pt_entry_t)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; /* * map page 1 R/W into the kernel page table so we can use it * as a buffer. The kernel will unmap this page later. */ pte = (pt_entry_t)vtopte(KERNBASE + (1 << PAGE_SHIFT)); *pte = (1 << PAGE_SHIFT) | PG_RW | PG_V; /* * get memory map with INT 15:E820 */ vmc.npages = 0; smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); physmap_idx = 0; vmf.vmf_ebx = 0; do { vmf.vmf_eax = 0xE820; vmf.vmf_edx = SMAP_SIG; vmf.vmf_ecx = sizeof(struct bios_smap); i = vm86_datacall(0x15, &vmf, &vmc); if (i || vmf.vmf_eax != SMAP_SIG) break; if (boothowto & RB_VERBOSE) printf("SMAP type=%02x base=%08x %08x len=%08x %08x\n", smap->type, *(u_int32_t *)((char *)&smap->base + 4), (u_int32_t)smap->base, *(u_int32_t *)((char *)&smap->length + 4), (u_int32_t)smap->length); if (smap->type != 0x01) goto next_run; if (smap->length == 0) goto next_run; if (smap->base >= 0xffffffff) { printf("%uK of memory above 4GB ignored\n", (u_int)(smap->length / 1024)); goto next_run; } for (i = 0; i <= physmap_idx; i += 2) { if (smap->base < physmap[i + 1]) { if (boothowto & RB_VERBOSE) printf( "Overlapping or non-montonic memory region, ignoring second region\n"); goto next_run; } } if (smap->base == physmap[physmap_idx + 1]) { physmap[physmap_idx + 1] += smap->length; goto next_run; } physmap_idx += 2; if (physmap_idx == PHYSMAP_SIZE) { printf( "Too many segments in the physical address map, giving up\n"); break; } physmap[physmap_idx] = smap->base; physmap[physmap_idx + 1] = smap->base + smap->length; next_run: } while (vmf.vmf_ebx != 0); if (physmap[1] != 0) goto physmap_done; /* * If we failed above, try memory map with INT 15:E801 */ vmf.vmf_ax = 0xE801; if (vm86_intcall(0x15, &vmf) == 0) { extmem = vmf.vmf_cx + vmf.vmf_dx * 64; } else { #if 0 vmf.vmf_ah = 0x88; vm86_intcall(0x15, &vmf); extmem = vmf.vmf_ax; #else /* * Prefer the RTC value for extended memory. */ extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8); #endif } /* * Special hack for chipsets that still remap the 384k hole when * there's 16MB of memory - this really confuses people that * are trying to use bus mastering ISA controllers with the * "16MB limit"; they only have 16MB, but the remapping puts * them beyond the limit. * * If extended memory is between 15-16MB (16-17MB phys address range), * chop it to 15MB. */ if ((extmem > 15 * 1024) && (extmem < 16 * 1024)) extmem = 15 * 1024; physmap[0] = 0; physmap[1] = basemem * 1024; physmap_idx = 2; physmap[physmap_idx] = 0x100000; physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024; physmap_done: /* * Now, physmap contains a map of physical memory. */ #ifdef SMP /* make hole for AP bootstrap code */ physmap[1] = mp_bootaddress(physmap[1] / 1024); /* look for the MP hardware - needed for apic addresses */ i386_mp_probe(); #endif /* * Maxmem isn't the "maximum memory", it's one larger than the * highest page of the physical address space. It should be * called something like "Maxphyspage". We may adjust this * based on ``hw.physmem'' and the results of the memory test. */ Maxmem = atop(physmap[physmap_idx + 1]); #ifdef MAXMEM Maxmem = MAXMEM / 4; #endif /* * hw.physmem is a size in bytes; we also allow k, m, and g suffixes * for the appropriate modifiers. This overrides MAXMEM. */ if ((cp = getenv("hw.physmem")) != NULL) { u_int64_t AllowMem, sanity; char *ep; sanity = AllowMem = strtouq(cp, &ep, 0); if ((ep != cp) && (*ep != 0)) { switch(*ep) { case 'g': case 'G': AllowMem <<= 10; case 'm': case 'M': AllowMem <<= 10; case 'k': case 'K': AllowMem <<= 10; break; default: AllowMem = sanity = 0; } if (AllowMem < sanity) AllowMem = 0; } if (AllowMem == 0) printf("Ignoring invalid memory size of '%s'\n", cp); else Maxmem = atop(AllowMem); } if (atop(physmap[physmap_idx + 1]) != Maxmem && (boothowto & RB_VERBOSE)) printf("Physical memory use set to %uK\n", Maxmem * 4); /* * If Maxmem has been increased beyond what the system has detected, * extend the last memory segment to the new limit. */ if (atop(physmap[physmap_idx + 1]) < Maxmem) physmap[physmap_idx + 1] = ptoa(Maxmem); /* call pmap initialization to make new kernel address space */ pmap_bootstrap(first, 0); /* * Size up each available chunk of physical memory. */ physmap[0] = PAGE_SIZE; /* mask off page 0 */ pa_indx = 0; phys_avail[pa_indx++] = physmap[0]; phys_avail[pa_indx] = physmap[0]; #if 0 pte = (pt_entry_t)vtopte(KERNBASE); #else pte = (pt_entry_t)CMAP1; #endif /* * physmap is in bytes, so when converting to page boundaries, * round up the start address and round down the end address. */ for (i = 0; i <= physmap_idx; i += 2) { vm_offset_t end; end = ptoa(Maxmem); if (physmap[i + 1] < end) end = trunc_page(physmap[i + 1]); for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) { int tmp, page_bad; #if 0 int *ptr = 0; #else int *ptr = (int *)CADDR1; #endif /* * block out kernel memory as not available. */ if (pa >= 0x100000 && pa < first) continue; page_bad = FALSE; /* * map page into kernel: valid, read/write,non-cacheable */ *pte = pa | PG_V | PG_RW | PG_N; invltlb(); tmp = *(int *)ptr; /* * Test for alternating 1's and 0's */ *(volatile int *)ptr = 0xaaaaaaaa; if (*(volatile int *)ptr != 0xaaaaaaaa) { page_bad = TRUE; } /* * Test for alternating 0's and 1's */ *(volatile int *)ptr = 0x55555555; if (*(volatile int *)ptr != 0x55555555) { page_bad = TRUE; } /* * Test for all 1's */ *(volatile int *)ptr = 0xffffffff; if (*(volatile int *)ptr != 0xffffffff) { page_bad = TRUE; } /* * Test for all 0's */ *(volatile int *)ptr = 0x0; if (*(volatile int *)ptr != 0x0) { page_bad = TRUE; } /* * Restore original value. */ *(int *)ptr = tmp; /* * Adjust array of valid/good pages. */ if (page_bad == TRUE) { continue; } /* * If this good page is a continuation of the * previous set of good pages, then just increase * the end pointer. Otherwise start a new chunk. * Note that "end" points one higher than end, * making the range >= start and < end. * If we're also doing a speculative memory * test and we at or past the end, bump up Maxmem * so that we keep going. The first bad page * will terminate the loop. */ if (phys_avail[pa_indx] == pa) { phys_avail[pa_indx] += PAGE_SIZE; } else { pa_indx++; if (pa_indx == PHYS_AVAIL_ARRAY_END) { printf( "Too many holes in the physical address space, giving up\n"); pa_indx--; break; } phys_avail[pa_indx++] = pa; /* start */ phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */ } physmem++; } } *pte = 0; invltlb(); /* * XXX * The last chunk must contain at least one page plus the message * buffer to avoid complicating other code (message buffer address * calculation, etc.). */ while (phys_avail[pa_indx - 1] + PAGE_SIZE + round_page(MSGBUF_SIZE) >= phys_avail[pa_indx]) { physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]); phys_avail[pa_indx--] = 0; phys_avail[pa_indx--] = 0; } Maxmem = atop(phys_avail[pa_indx]); /* Trim off space for the message buffer. */ phys_avail[pa_indx] -= round_page(MSGBUF_SIZE); avail_end = phys_avail[pa_indx]; } void init386(first) int first; { struct gate_descriptor *gdp; int gsel_tss, metadata_missing, off, x; #ifndef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif proc0.p_addr = proc0paddr; atdevbase = ISA_HOLE_START + KERNBASE; metadata_missing = 0; if (bootinfo.bi_modulep) { preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE; preload_bootstrap_relocate(KERNBASE); } else { metadata_missing = 1; } - if (bootinfo.bi_envp) + if (envmode == 1) + kern_envp = static_env; + else if (bootinfo.bi_envp) kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; /* Init basic tunables, hz etc */ init_param(); /* * make gdt memory segments, the code segment goes up to end of the * page with etext in it, the data segment goes to the end of * the address space */ /* * XXX text protection is temporarily (?) disabled. The limit was * i386_btop(round_page(etext)) - 1. */ gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1); gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1); #ifdef SMP gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct privatespace) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[0]; gdt_segs[GPROC0_SEL].ssd_base = (int) &SMP_prvspace[0].globaldata.gd_common_tss; SMP_prvspace[0].globaldata.gd_prvspace = &SMP_prvspace[0].globaldata; #else gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct globaldata) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &__globaldata; gdt_segs[GPROC0_SEL].ssd_base = (int) &__globaldata.gd_common_tss; __globaldata.gd_prvspace = &__globaldata; #endif for (x = 0; x < NGDT; x++) { #ifdef BDE_DEBUGGER /* avoid overwriting db entries with APM ones */ if (x >= GAPMCODE32_SEL && x <= GAPMDATA_SEL) continue; #endif ssdtosd(&gdt_segs[x], &gdt[x].sd); } r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; r_gdt.rd_base = (int) gdt; lgdt(&r_gdt); /* setup curproc so that mutexes work */ PCPU_SET(curproc, &proc0); PCPU_SET(spinlocks, NULL); LIST_INIT(&proc0.p_contested); /* * Initialize mutexes. */ mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE); mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE); mtx_init(&proc0.p_mtx, "process lock", MTX_DEF); mtx_init(&clock_lock, "clk", MTX_SPIN | MTX_RECURSE); #ifdef SMP mtx_init(&imen_mtx, "imen", MTX_SPIN); #endif mtx_lock(&Giant); /* make ldt memory segments */ /* * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it * should be spelled ...MAX_USER... */ ldt_segs[LUCODE_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); ldt_segs[LUDATA_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++) ssdtosd(&ldt_segs[x], &ldt[x].sd); _default_ldt = GSEL(GLDT_SEL, SEL_KPL); lldt(_default_ldt); PCPU_SET(currentldt, _default_ldt); /* exceptions */ for (x = 0; x < NIDT; x++) setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(1, &IDTVEC(dbg), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(3, &IDTVEC(bpt), SDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL , GSEL(GCODE_SEL, SEL_KPL)); setidt(8, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL)); setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(14, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(18, &IDTVEC(mchk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(19, &IDTVEC(xmm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); r_idt.rd_limit = sizeof(idt0) - 1; r_idt.rd_base = (int) idt; lidt(&r_idt); /* * Initialize the console before we print anything out. */ cninit(); if (metadata_missing) printf("WARNING: loader(8) metadata is missing!\n"); #ifdef DEV_ISA isa_defaultirq(); #endif #ifdef DDB kdb_init(); if (boothowto & RB_KDB) Debugger("Boot flags requested debugger"); #endif finishidentcpu(); /* Final stage of CPU initialization */ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); initializecpu(); /* Initialize CPU registers */ /* make an initial tss so cpu can get interrupt stack on syscall! */ PCPU_SET(common_tss.tss_esp0, (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16); PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); private_tss = 0; PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); ltr(gsel_tss); dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)]; dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 = dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_cr3 = (int)IdlePTD; dblfault_tss.tss_eip = (int)dblfault_handler; dblfault_tss.tss_eflags = PSL_KERNEL; dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL); dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL); dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL); vm86_initialize(); getmemsize(first); /* now running on new page tables, configured,and u/iom is accessible */ /* Map the message buffer. */ for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE) pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off); msgbufinit(msgbufp, MSGBUF_SIZE); /* make a call gate to reenter kernel with */ gdp = &ldt[LSYS5CALLS_SEL].gd; x = (int) &IDTVEC(lcall_syscall); gdp->gd_looffset = x; gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); gdp->gd_stkcpy = 1; gdp->gd_type = SDT_SYS386CGT; gdp->gd_dpl = SEL_UPL; gdp->gd_p = 1; gdp->gd_hioffset = x >> 16; /* XXX does this work? */ ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL]; ldt[LSOL26CALLS_SEL] = ldt[LSYS5CALLS_SEL]; /* transfer to user mode */ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); _udatasel = LSEL(LUDATA_SEL, SEL_UPL); /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = (int)IdlePTD; proc0.p_addr->u_pcb.pcb_ext = 0; proc0.p_frame = &proc0_tf; } #if defined(I586_CPU) && !defined(NO_F00F_HACK) static void f00f_hack(void *unused); SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); static void f00f_hack(void *unused) { struct gate_descriptor *new_idt; #ifndef SMP struct region_descriptor r_idt; #endif vm_offset_t tmp; if (!has_f00f_bug) return; GIANT_REQUIRED; printf("Intel Pentium detected, installing workaround for F00F bug\n"); r_idt.rd_limit = sizeof(idt0) - 1; tmp = kmem_alloc(kernel_map, PAGE_SIZE * 2); if (tmp == 0) panic("kmem_alloc returned 0"); if (((unsigned int)tmp & (PAGE_SIZE-1)) != 0) panic("kmem_alloc returned non-page-aligned memory"); /* Put the first seven entries in the lower page */ new_idt = (struct gate_descriptor*)(tmp + PAGE_SIZE - (7*8)); bcopy(idt, new_idt, sizeof(idt0)); r_idt.rd_base = (int)new_idt; lidt(&r_idt); idt = new_idt; if (vm_map_protect(kernel_map, tmp, tmp + PAGE_SIZE, VM_PROT_READ, FALSE) != KERN_SUCCESS) panic("vm_map_protect failed"); return; } #endif /* defined(I586_CPU) && !NO_F00F_HACK */ int ptrace_set_pc(p, addr) struct proc *p; unsigned long addr; { p->p_frame->tf_eip = addr; return (0); } int ptrace_single_step(p) struct proc *p; { p->p_frame->tf_eflags |= PSL_T; return (0); } int fill_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; regs->r_fs = tp->tf_fs; regs->r_es = tp->tf_es; regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_edi; regs->r_esi = tp->tf_esi; regs->r_ebp = tp->tf_ebp; regs->r_ebx = tp->tf_ebx; regs->r_edx = tp->tf_edx; regs->r_ecx = tp->tf_ecx; regs->r_eax = tp->tf_eax; regs->r_eip = tp->tf_eip; regs->r_cs = tp->tf_cs; regs->r_eflags = tp->tf_eflags; regs->r_esp = tp->tf_esp; regs->r_ss = tp->tf_ss; pcb = &p->p_addr->u_pcb; regs->r_gs = pcb->pcb_gs; return (0); } int set_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; tp->tf_edi = regs->r_edi; tp->tf_esi = regs->r_esi; tp->tf_ebp = regs->r_ebp; tp->tf_ebx = regs->r_ebx; tp->tf_edx = regs->r_edx; tp->tf_ecx = regs->r_ecx; tp->tf_eax = regs->r_eax; tp->tf_eip = regs->r_eip; tp->tf_cs = regs->r_cs; tp->tf_eflags = regs->r_eflags; tp->tf_esp = regs->r_esp; tp->tf_ss = regs->r_ss; pcb = &p->p_addr->u_pcb; pcb->pcb_gs = regs->r_gs; return (0); } #ifdef CPU_ENABLE_SSE static void fill_fpregs_xmm(sv_xmm, sv_87) struct savexmm *sv_xmm; struct save87 *sv_87; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_87->en_cw = penv_xmm->en_cw; penv_87->en_sw = penv_xmm->en_sw; penv_87->en_tw = penv_xmm->en_tw; penv_87->en_fip = penv_xmm->en_fip; penv_87->en_fcs = penv_xmm->en_fcs; penv_87->en_opcode = penv_xmm->en_opcode; penv_87->en_foo = penv_xmm->en_foo; penv_87->en_fos = penv_xmm->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc; sv_87->sv_ex_sw = sv_xmm->sv_ex_sw; } static void set_fpregs_xmm(sv_87, sv_xmm) struct save87 *sv_87; struct savexmm *sv_xmm; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_xmm->en_cw = penv_87->en_cw; penv_xmm->en_sw = penv_87->en_sw; penv_xmm->en_tw = penv_87->en_tw; penv_xmm->en_fip = penv_87->en_fip; penv_xmm->en_fcs = penv_87->en_fcs; penv_xmm->en_opcode = penv_87->en_opcode; penv_xmm->en_foo = penv_87->en_foo; penv_xmm->en_fos = penv_87->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i]; sv_xmm->sv_ex_sw = sv_87->sv_ex_sw; } #endif /* CPU_ENABLE_SSE */ int fill_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { fill_fpregs_xmm(&p->p_addr->u_pcb.pcb_save.sv_xmm, (struct save87 *)fpregs); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(&p->p_addr->u_pcb.pcb_save.sv_87, fpregs, sizeof *fpregs); return (0); } int set_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { set_fpregs_xmm((struct save87 *)fpregs, &p->p_addr->u_pcb.pcb_save.sv_xmm); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(fpregs, &p->p_addr->u_pcb.pcb_save.sv_87, sizeof *fpregs); return (0); } int fill_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; if (p == NULL) { dbregs->dr0 = rdr0(); dbregs->dr1 = rdr1(); dbregs->dr2 = rdr2(); dbregs->dr3 = rdr3(); dbregs->dr4 = rdr4(); dbregs->dr5 = rdr5(); dbregs->dr6 = rdr6(); dbregs->dr7 = rdr7(); } else { pcb = &p->p_addr->u_pcb; dbregs->dr0 = pcb->pcb_dr0; dbregs->dr1 = pcb->pcb_dr1; dbregs->dr2 = pcb->pcb_dr2; dbregs->dr3 = pcb->pcb_dr3; dbregs->dr4 = 0; dbregs->dr5 = 0; dbregs->dr6 = pcb->pcb_dr6; dbregs->dr7 = pcb->pcb_dr7; } return (0); } int set_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; int i; u_int32_t mask1, mask2; if (p == NULL) { load_dr0(dbregs->dr0); load_dr1(dbregs->dr1); load_dr2(dbregs->dr2); load_dr3(dbregs->dr3); load_dr4(dbregs->dr4); load_dr5(dbregs->dr5); load_dr6(dbregs->dr6); load_dr7(dbregs->dr7); } else { /* * Don't let an illegal value for dr7 get set. Specifically, * check for undefined settings. Setting these bit patterns * result in undefined behaviour and can lead to an unexpected * TRCTRAP. */ for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8; i++, mask1 <<= 2, mask2 <<= 2) if ((dbregs->dr7 & mask1) == mask2) return (EINVAL); pcb = &p->p_addr->u_pcb; /* * Don't let a process set a breakpoint that is not within the * process's address space. If a process could do this, it * could halt the system by setting a breakpoint in the kernel * (if ddb was enabled). Thus, we need to check to make sure * that no breakpoints are being enabled for addresses outside * process's address space, unless, perhaps, we were called by * uid 0. * * XXX - what about when the watched area of the user's * address space is written into from within the kernel * ... wouldn't that still cause a breakpoint to be generated * from within kernel mode? */ if (suser(p) != 0) { if (dbregs->dr7 & 0x3) { /* dr0 is enabled */ if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<2)) { /* dr1 is enabled */ if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<4)) { /* dr2 is enabled */ if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<6)) { /* dr3 is enabled */ if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) return (EINVAL); } } pcb->pcb_dr0 = dbregs->dr0; pcb->pcb_dr1 = dbregs->dr1; pcb->pcb_dr2 = dbregs->dr2; pcb->pcb_dr3 = dbregs->dr3; pcb->pcb_dr6 = dbregs->dr6; pcb->pcb_dr7 = dbregs->dr7; pcb->pcb_flags |= PCB_DBREGS; } return (0); } /* * Return > 0 if a hardware breakpoint has been hit, and the * breakpoint was in user space. Return 0, otherwise. */ int user_dbreg_trap(void) { u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */ u_int32_t bp; /* breakpoint bits extracted from dr6 */ int nbp; /* number of breakpoints that triggered */ caddr_t addr[4]; /* breakpoint addresses */ int i; dr7 = rdr7(); if ((dr7 & 0x000000ff) == 0) { /* * all GE and LE bits in the dr7 register are zero, * thus the trap couldn't have been caused by the * hardware debug registers */ return 0; } nbp = 0; dr6 = rdr6(); bp = dr6 & 0x0000000f; if (!bp) { /* * None of the breakpoint bits are set meaning this * trap was not caused by any of the debug registers */ return 0; } /* * at least one of the breakpoints were hit, check to see * which ones and if any of them are user space addresses */ if (bp & 0x01) { addr[nbp++] = (caddr_t)rdr0(); } if (bp & 0x02) { addr[nbp++] = (caddr_t)rdr1(); } if (bp & 0x04) { addr[nbp++] = (caddr_t)rdr2(); } if (bp & 0x08) { addr[nbp++] = (caddr_t)rdr3(); } for (i=0; i /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. Adjust transfer * if needed, and signal errors or early completion. */ int bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel) { struct partition *p = lp->d_partitions + dkpart(bp->bio_dev); int labelsect = lp->d_partitions[0].p_offset; int maxsz = p->p_size, sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect && #endif (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #endif /* beyond partition? */ if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->bio_blkno == maxsz) { bp->bio_resid = bp->bio_bcount; return(0); } /* or truncate if part of it fits */ sz = maxsz - bp->bio_blkno; if (sz <= 0) { bp->bio_error = EINVAL; goto bad; } bp->bio_bcount = sz << DEV_BSHIFT; } bp->bio_pblkno = bp->bio_blkno + p->p_offset; return(1); bad: bp->bio_flags |= BIO_ERROR; return(-1); } #ifdef DDB /* * Provide inb() and outb() as functions. They are normally only * available as macros calling inlined functions, thus cannot be * called inside DDB. * * The actual code is stolen from , and de-inlined. */ #undef inb #undef outb /* silence compiler warnings */ u_char inb(u_int); void outb(u_int, u_char); u_char inb(u_int port) { u_char data; /* * We use %%dx and not %1 here because i/o is done at %dx and not at * %edx, while gcc generates inferior code (movw instead of movl) * if we tell it to load (u_short) port. */ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); return (data); } void outb(u_int port, u_char data) { u_char al; /* * Use an unnecessary assignment to help gcc's register allocator. * This make a large difference for gcc-1.40 and a tiny difference * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for * best results. gcc-2.6.0 can't handle this. */ al = data; __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); } #endif /* DDB */ Index: head/sys/ia64/ia64/machdep.c =================================================================== --- head/sys/ia64/ia64/machdep.c (revision 82392) +++ head/sys/ia64/ia64/machdep.c (revision 82393) @@ -1,1310 +1,1313 @@ /*- * Copyright (c) 2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include "opt_compat.h" #include "opt_ddb.h" #include "opt_simos.h" #include "opt_msgbuf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include u_int64_t cycles_per_usec; u_int32_t cycles_per_sec; int cold = 1; struct bootinfo_kernel bootinfo; struct mtx sched_lock; struct mtx Giant; struct user *proc0paddr; char machine[] = "ia64"; SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); static char cpu_model[128]; SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); #ifdef DDB /* start and end of kernel symbol table */ void *ksym_start, *ksym_end; #endif int ia64_unaligned_print = 1; /* warn about unaligned accesses */ int ia64_unaligned_fix = 1; /* fix up unaligned accesses */ int ia64_unaligned_sigbus = 0; /* don't SIGBUS on fixed-up accesses */ SYSCTL_INT(_machdep, CPU_UNALIGNED_PRINT, unaligned_print, CTLFLAG_RW, &ia64_unaligned_print, 0, ""); SYSCTL_INT(_machdep, CPU_UNALIGNED_FIX, unaligned_fix, CTLFLAG_RW, &ia64_unaligned_fix, 0, ""); SYSCTL_INT(_machdep, CPU_UNALIGNED_SIGBUS, unaligned_sigbus, CTLFLAG_RW, &ia64_unaligned_sigbus, 0, ""); static void cpu_startup __P((void *)); SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL) struct msgbuf *msgbufp=0; int bootverbose = 0, Maxmem = 0; long dumplo; int totalphysmem; /* total amount of physical memory in system */ int physmem; /* physical memory used by NetBSD + some rsvd */ int resvmem; /* amount of memory reserved for PROM */ int unusedmem; /* amount of memory for OS that we don't use */ int unknownmem; /* amount of memory with an unknown use */ int ncpus; /* number of cpus */ vm_offset_t phys_avail[10]; static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ia64_ptob(physmem), req); return (error); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "I", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ia64_ptob(physmem - cnt.v_wire_count), req); return (error); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "I", ""); SYSCTL_INT(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, ""); /* must be 2 less so 0 0 can signal end of chunks */ #define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2) static void identifycpu __P((void)); static vm_offset_t buffer_sva, buffer_eva; vm_offset_t clean_sva, clean_eva; static vm_offset_t pager_sva, pager_eva; static void cpu_startup(dummy) void *dummy; { unsigned int i; caddr_t v; vm_offset_t maxaddr; vm_size_t size = 0; vm_offset_t firstaddr; vm_offset_t minaddr; /* * Good {morning,afternoon,evening,night}. */ identifycpu(); /* startrtclock(); */ #ifdef PERFMON perfmon_init(); #endif printf("real memory = %ld (%ldK bytes)\n", ia64_ptob(Maxmem), ia64_ptob(Maxmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { int size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08lx - 0x%08lx, %d bytes (%d pages)\n", phys_avail[indx], phys_avail[indx + 1] - 1, size1, size1 / PAGE_SIZE); } } /* * Calculate callout wheel size */ for (callwheelsize = 1, callwheelbits = 0; callwheelsize < ncallout; callwheelsize <<= 1, ++callwheelbits) ; callwheelmask = callwheelsize - 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(callout, struct callout, ncallout); valloc(callwheel, struct callout_tailq, callwheelsize); /* * The nominal buffer size (and minimum KVA allocation) is BKVASIZE. * For the first 64MB of ram nominally allocate sufficient buffers to * cover 1/4 of our ram. Beyond the first 64MB allocate additional * buffers to cover 1/20 of our ram over 64MB. */ if (nbuf == 0) { int factor = 4 * BKVASIZE / PAGE_SIZE; nbuf = 50; if (physmem > 1024) nbuf += min((physmem - 1024) / factor, 16384 / factor); if (physmem > 16384) nbuf += (physmem - 16384) * 2 / (factor * 5); } nswbuf = max(min(nbuf/4, 64), 16); valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); v = bufhashinit(v); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (vm_offset_t)kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size); buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, (nbuf*BKVASIZE)); buffer_map->system_map = 1; pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, (nswbuf*MAXPHYS) + pager_map_size); pager_map->system_map = 1; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (16*(ARG_MAX+(PAGE_SIZE*3)))); /* * Finally, allocate mbuf pool. * XXX: Mbuf system machine-specific initializations should * go here, if anywhere. */ /* * Initialize callouts */ SLIST_INIT(&callfree); for (i = 0; i < ncallout; i++) { callout_init(&callout[i], 0); callout[i].c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle); } for (i = 0; i < callwheelsize; i++) { TAILQ_INIT(&callwheel[i]); } mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE); #if defined(USERCONFIG) #if defined(USERCONFIG_BOOT) if (1) #else if (boothowto & RB_CONFIG) #endif { userconfig(); cninit(); /* the preferred console may have changed */ } #endif printf("avail memory = %ld (%ldK bytes)\n", ptoa(cnt.v_free_count), ptoa(cnt.v_free_count) / 1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); } static void identifycpu(void) { /* print cpu type & version */ } extern char kernel_text[], _end[]; #define DEBUG_MD void ia64_init() { int phys_avail_cnt; vm_offset_t kernstart, kernend; vm_offset_t kernstartpfn, kernendpfn, pfn0, pfn1; char *p; EFI_MEMORY_DESCRIPTOR ski_md[2]; /* XXX */ EFI_MEMORY_DESCRIPTOR *mdp; int mdcount, i; /* NO OUTPUT ALLOWED UNTIL FURTHER NOTICE */ /* * TODO: Disable interrupts, floating point etc. * Maybe flush cache and tlb */ __asm __volatile("mov ar.fpsr=%0" :: "r"(IA64_FPSR_DEFAULT)); /* * TODO: Get critical system information (if possible, from the * information provided by the boot program). */ /* * Initalize the (temporary) bootstrap console interface, so * we can use printf until the VM system starts being setup. * The real console is initialized before then. * TODO: I guess we start with a serial console here. */ ssccnattach(); /* OUTPUT NOW ALLOWED */ /* * Find the beginning and end of the kernel. */ kernstart = trunc_page(kernel_text); #ifdef DDBxx ksym_start = (void *)bootinfo.ssym; ksym_end = (void *)bootinfo.esym; kernend = (vm_offset_t)round_page(ksym_end); #else kernend = (vm_offset_t)round_page(_end); #endif /* But if the bootstrap tells us otherwise, believe it! */ if (bootinfo.kernend) kernend = round_page(bootinfo.kernend); preload_metadata = (caddr_t)bootinfo.modptr; - kern_envp = bootinfo.envp; + if (envmode == 1) + kern_envp = static_env; + else + kern_envp = bootinfo.envp; /* Init basic tunables, including hz */ init_param(); p = getenv("kernelname"); if (p) strncpy(kernelname, p, sizeof(kernelname) - 1); kernstartpfn = atop(IA64_RR_MASK(kernstart)); kernendpfn = atop(IA64_RR_MASK(kernend)); /* * Size the memory regions and load phys_avail[] with the results. */ /* * XXX hack for ski. In reality, the loader will probably ask * EFI and pass the results to us. Possibly, we will call EFI * directly. */ ski_md[0].Type = EfiConventionalMemory; ski_md[0].PhysicalStart = 2L*1024*1024; ski_md[0].VirtualStart = 0; ski_md[0].NumberOfPages = (64L*1024*1024)>>12; ski_md[0].Attribute = EFI_MEMORY_WB; ski_md[1].Type = EfiConventionalMemory; ski_md[1].PhysicalStart = 4096L*1024*1024; ski_md[1].VirtualStart = 0; ski_md[1].NumberOfPages = (32L*1024*1024)>>12; ski_md[1].Attribute = EFI_MEMORY_WB; mdcount = 1; /* ignore the high memory for now */ /* * Find out how much memory is available, by looking at * the memory descriptors. */ #ifdef DEBUG_MD printf("Memory descriptor count: %d\n", mdcount); #endif phys_avail_cnt = 0; for (i = 0; i < mdcount; i++) { mdp = &ski_md[i]; #ifdef DEBUG_MD printf("MD %d: type %d pa 0x%lx cnt 0x%lx\n", i, mdp->Type, mdp->PhysicalStart, mdp->NumberOfPages); #endif totalphysmem += mdp->NumberOfPages; if (mdp->Type != EfiConventionalMemory) { resvmem += mdp->NumberOfPages; continue; } /* * We have a memory descriptors available for system * software use. We must determine if this cluster * holds the kernel. */ physmem += mdp->NumberOfPages; pfn0 = atop(mdp->PhysicalStart); pfn1 = pfn0 + mdp->NumberOfPages; if (pfn0 <= kernendpfn && kernstartpfn <= pfn1) { /* * Must compute the location of the kernel * within the segment. */ #ifdef DEBUG_MD printf("Descriptor %d contains kernel\n", i); #endif if (pfn0 < kernstartpfn) { /* * There is a chunk before the kernel. */ #ifdef DEBUG_MD printf("Loading chunk before kernel: " "0x%lx / 0x%lx\n", pfn0, kernstartpfn); #endif phys_avail[phys_avail_cnt] = ia64_ptob(pfn0); phys_avail[phys_avail_cnt+1] = ia64_ptob(kernstartpfn); phys_avail_cnt += 2; } if (kernendpfn < pfn1) { /* * There is a chunk after the kernel. */ #ifdef DEBUG_MD printf("Loading chunk after kernel: " "0x%lx / 0x%lx\n", kernendpfn, pfn1); #endif phys_avail[phys_avail_cnt] = ia64_ptob(kernendpfn); phys_avail[phys_avail_cnt+1] = ia64_ptob(pfn1); phys_avail_cnt += 2; } } else { /* * Just load this cluster as one chunk. */ #ifdef DEBUG_MD printf("Loading descriptor %d: 0x%lx / 0x%lx\n", i, pfn0, pfn1); #endif phys_avail[phys_avail_cnt] = ia64_ptob(pfn0); phys_avail[phys_avail_cnt+1] = ia64_ptob(pfn1); phys_avail_cnt += 2; } } phys_avail[phys_avail_cnt] = 0; Maxmem = physmem; /* * Initialize error message buffer (at end of core). */ { size_t sz = round_page(MSGBUF_SIZE); int i = phys_avail_cnt - 2; /* shrink so that it'll fit in the last segment */ if (phys_avail[i+1] - phys_avail[i] < sz) sz = phys_avail[i+1] - phys_avail[i]; phys_avail[i+1] -= sz; msgbufp = (struct msgbuf*) IA64_PHYS_TO_RR7(phys_avail[i+1]); msgbufinit(msgbufp, sz); /* Remove the last segment if it now has no pages. */ if (phys_avail[i] == phys_avail[i+1]) phys_avail[i] = 0; /* warn if the message buffer had to be shrunk */ if (sz != round_page(MSGBUF_SIZE)) printf("WARNING: %ld bytes not available for msgbuf in last cluster (%ld used)\n", round_page(MSGBUF_SIZE), sz); } /* * Init mapping for u page(s) for proc 0 */ proc0paddr = proc0.p_addr = (struct user *)pmap_steal_memory(UPAGES * PAGE_SIZE); /* * Setup the global data for the bootstrap cpu. */ { size_t sz = round_page(UPAGES * PAGE_SIZE); globalp = (struct globaldata *) pmap_steal_memory(sz); globaldata_init(globalp, 0, sz); ia64_set_k4((u_int64_t) globalp); PCPU_GET(next_asn) = 1; /* 0 used for proc0 pmap */ } /* * Initialize the virtual memory system. */ pmap_bootstrap(); /* * Initialize the rest of proc 0's PCB. * * Set the kernel sp, reserving space for an (empty) trapframe, * and make proc0's trapframe pointer point to it for sanity. * Initialise proc0's backing store to start after u area. */ proc0.p_addr->u_pcb.pcb_sp = (u_int64_t)proc0.p_addr + USPACE - sizeof(struct trapframe) - 16; proc0.p_addr->u_pcb.pcb_bspstore = (u_int64_t) (proc0.p_addr + 1); proc0.p_frame = (struct trapframe *)(proc0.p_addr->u_pcb.pcb_sp + 16); /* Setup curproc so that mutexes work */ PCPU_SET(curproc, &proc0); PCPU_SET(spinlocks, NULL); LIST_INIT(&proc0.p_contested); /* * Initialise mutexes. */ mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE); mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE); mtx_init(&proc0.p_mtx, "process lock", MTX_DEF); mtx_lock(&Giant); /* * Look at arguments passed to us and compute boothowto. */ boothowto = 0; #ifdef KADB boothowto |= RB_KDB; #endif /* boothowto |= RB_KDB | RB_GDB; */ for (p = bootinfo.boot_flags; p && *p != '\0'; p++) { /* * Note that we'd really like to differentiate case here, * but the Ia64 AXP Architecture Reference Manual * says that we shouldn't. */ switch (*p) { case 'a': /* autoboot */ case 'A': boothowto &= ~RB_SINGLE; break; #ifdef DEBUG case 'c': /* crash dump immediately after autoconfig */ case 'C': boothowto |= RB_DUMP; break; #endif #if defined(DDB) case 'd': /* break into the kernel debugger ASAP */ case 'D': boothowto |= RB_KDB; break; case 'g': /* use kernel gdb */ case 'G': boothowto |= RB_GDB; break; #endif case 'h': /* always halt, never reboot */ case 'H': boothowto |= RB_HALT; break; #if 0 case 'm': /* mini root present in memory */ case 'M': boothowto |= RB_MINIROOT; break; #endif case 'n': /* askname */ case 'N': boothowto |= RB_ASKNAME; break; case 's': /* single-user (default, supported for sanity) */ case 'S': boothowto |= RB_SINGLE; break; case 'v': case 'V': boothowto |= RB_VERBOSE; bootverbose = 1; break; default: printf("Unrecognized boot flag '%c'.\n", *p); break; } } /* * Catch case of boot_verbose set in environment. */ if ((p = getenv("boot_verbose")) != NULL) { if (strcmp(p, "yes") == 0 || strcmp(p, "YES") == 0) { boothowto |= RB_VERBOSE; bootverbose = 1; } } /* * Force single-user for a while. */ boothowto |= RB_SINGLE; /* * Initialize debuggers, and break into them if appropriate. */ #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { printf("Boot flags requested debugger\n"); breakpoint(); } #endif } void bzero(void *buf, size_t len) { caddr_t p = buf; while (((vm_offset_t) p & (sizeof(u_long) - 1)) && len) { *p++ = 0; len--; } while (len >= sizeof(u_long) * 8) { *(u_long*) p = 0; *((u_long*) p + 1) = 0; *((u_long*) p + 2) = 0; *((u_long*) p + 3) = 0; len -= sizeof(u_long) * 8; *((u_long*) p + 4) = 0; *((u_long*) p + 5) = 0; *((u_long*) p + 6) = 0; *((u_long*) p + 7) = 0; p += sizeof(u_long) * 8; } while (len >= sizeof(u_long)) { *(u_long*) p = 0; len -= sizeof(u_long); p += sizeof(u_long); } while (len) { *p++ = 0; len--; } } void DELAY(int n) { /* TODO */ } /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ void sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { struct proc *p = curproc; struct trapframe *frame; struct sigacts *psp; struct sigframe sf, *sfp; u_int64_t sbs = 0; int oonstack, rndfsize; PROC_LOCK(p); psp = p->p_sigacts; frame = p->p_frame; oonstack = sigonstack(frame->tf_r[FRAME_SP]); rndfsize = ((sizeof(sf) + 15) / 16) * 16; /* * Make sure that we restore the entire trapframe after a * signal. */ frame->tf_flags &= ~FRAME_SYSCALL; /* save user context */ bzero(&sf, sizeof(struct sigframe)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_flags = IA64_MC_FLAG_ONSTACK; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_nat = 0; /* XXX */ sf.sf_uc.uc_mcontext.mc_sp = frame->tf_r[FRAME_SP]; sf.sf_uc.uc_mcontext.mc_ip = (frame->tf_cr_iip | ((frame->tf_cr_ipsr >> 41) & 3)); sf.sf_uc.uc_mcontext.mc_cfm = frame->tf_cr_ifs & ~(1<<31); sf.sf_uc.uc_mcontext.mc_um = frame->tf_cr_ipsr & 0x1fff; sf.sf_uc.uc_mcontext.mc_ar_rsc = frame->tf_ar_rsc; sf.sf_uc.uc_mcontext.mc_ar_bsp = frame->tf_ar_bspstore; sf.sf_uc.uc_mcontext.mc_ar_rnat = frame->tf_ar_rnat; sf.sf_uc.uc_mcontext.mc_ar_ccv = frame->tf_ar_ccv; sf.sf_uc.uc_mcontext.mc_ar_unat = frame->tf_ar_unat; sf.sf_uc.uc_mcontext.mc_ar_fpsr = frame->tf_ar_fpsr; sf.sf_uc.uc_mcontext.mc_ar_pfs = frame->tf_ar_pfs; sf.sf_uc.uc_mcontext.mc_pr = frame->tf_pr; bcopy(&frame->tf_b[0], &sf.sf_uc.uc_mcontext.mc_br[0], 8 * sizeof(unsigned long)); sf.sf_uc.uc_mcontext.mc_gr[0] = 0; bcopy(&frame->tf_r[0], &sf.sf_uc.uc_mcontext.mc_gr[1], 31 * sizeof(unsigned long)); /* XXX mc_fr[] */ /* * Allocate and validate space for the signal handler * context. Note that if the stack is in P0 space, the * call to grow() is a nop, and the useracc() check * will fail if the process has not already allocated * the space with a `brk'. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sbs = (u_int64_t) p->p_sigstk.ss_sp; sfp = (struct sigframe *)((caddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size - rndfsize); /* * Align sp and bsp. */ sbs = (sbs + 15) & ~15; sfp = (struct sigframe *)((u_int64_t)sfp & ~15); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sfp = (struct sigframe *)(frame->tf_r[FRAME_SP] - rndfsize); PROC_UNLOCK(p); (void)grow_stack(p, (u_long)sfp); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, sig, &sf, sfp); #endif if (!useracc((caddr_t)sfp, sizeof(sf), VM_PROT_WRITE)) { #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): useracc failed on sig %d\n", p->p_pid, sig); #endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } #if 0 /* save the floating-point state, if necessary, then copy it. */ ia64_fpstate_save(p, 1); sf.sf_uc.uc_mcontext.mc_ownedfp = p->p_md.md_flags & MDP_FPUSED; bcopy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)sf.sf_uc.uc_mcontext.mc_fpregs, sizeof(struct fpreg)); sf.sf_uc.uc_mcontext.mc_fp_control = p->p_addr->u_pcb.pcb_fp_control; #endif /* * copy the frame out to userland. */ (void) copyout((caddr_t)&sf, (caddr_t)sfp, sizeof(sf)); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): sig %d sfp %p code %lx\n", p->p_pid, sig, sfp, code); #endif /* * Set up the registers to return to sigcode. */ frame->tf_cr_ipsr &= ~IA64_PSR_RI; frame->tf_cr_iip = PS_STRINGS - (esigcode - sigcode); frame->tf_r[FRAME_R1] = sig; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { frame->tf_r[FRAME_R15] = (u_int64_t)&(sfp->sf_si); /* Fill in POSIX parts */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void*)frame->tf_cr_ifa; } else frame->tf_r[FRAME_R15] = code; PROC_UNLOCK(p); frame->tf_r[FRAME_SP] = (u_int64_t)sfp - 16; frame->tf_r[FRAME_R14] = sig; frame->tf_r[FRAME_R15] = (u_int64_t) &sfp->sf_si; frame->tf_r[FRAME_R16] = (u_int64_t) &sfp->sf_uc; frame->tf_r[FRAME_R17] = (u_int64_t)catcher; frame->tf_r[FRAME_R18] = sbs; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): pc %lx, catcher %lx\n", p->p_pid, frame->tf_cr_iip, frame->tf_regs[FRAME_R4]); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ #ifdef COMPAT_43 int osigreturn(struct proc *p, struct osigreturn_args /* { struct osigcontext *sigcntxp; } */ *uap) { return EOPNOTSUPP; } #endif /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ int sigreturn(struct proc *p, struct sigreturn_args /* { ucontext_t *sigcntxp; } */ *uap) { ucontext_t uc, *ucp; struct pcb *pcb; struct trapframe *frame = p->p_frame; struct __mcontext *mcp; ucp = uap->sigcntxp; pcb = &p->p_addr->u_pcb; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn: pid %d, scp %p\n", p->p_pid, ucp); #endif /* * Fetch the entire context structure at once for speed. * We don't use a normal argument to simplify RSE handling. */ if (copyin((caddr_t)frame->tf_r[FRAME_R4], (caddr_t)&uc, sizeof(ucontext_t))) return (EFAULT); /* * Restore the user-supplied information */ mcp = &uc.uc_mcontext; bcopy(&mcp->mc_br[0], &frame->tf_b[0], 8*sizeof(u_int64_t)); bcopy(&mcp->mc_gr[1], &frame->tf_r[0], 31*sizeof(u_int64_t)); /* XXX mc_fr */ frame->tf_flags &= ~FRAME_SYSCALL; frame->tf_cr_iip = mcp->mc_ip & ~15; frame->tf_cr_ipsr &= ~IA64_PSR_RI; switch (mcp->mc_ip & 15) { case 1: frame->tf_cr_ipsr |= IA64_PSR_RI_1; break; case 2: frame->tf_cr_ipsr |= IA64_PSR_RI_2; break; } frame->tf_cr_ipsr = ((frame->tf_cr_ipsr & ~0x1fff) | (mcp->mc_um & 0x1fff)); frame->tf_pr = mcp->mc_pr; frame->tf_ar_rsc = (mcp->mc_ar_rsc & 3) | 12; /* user, loadrs=0 */ frame->tf_ar_pfs = mcp->mc_ar_pfs; frame->tf_cr_ifs = mcp->mc_cfm | (1UL<<63); frame->tf_ar_bspstore = mcp->mc_ar_bsp; frame->tf_ar_rnat = mcp->mc_ar_rnat; frame->tf_ndirty = 0; /* assumes flushrs in sigcode */ frame->tf_ar_unat = mcp->mc_ar_unat; frame->tf_ar_ccv = mcp->mc_ar_ccv; frame->tf_ar_fpsr = mcp->mc_ar_fpsr; frame->tf_r[FRAME_SP] = mcp->mc_sp; PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (uc.uc_mcontext.mc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif p->p_sigmask = uc.uc_sigmask; SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); /* XXX ksc.sc_ownedfp ? */ ia64_fpstate_drop(p); #if 0 bcopy((struct fpreg *)uc.uc_mcontext.mc_fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); p->p_addr->u_pcb.pcb_fp_control = uc.uc_mcontext.mc_fp_control; #endif #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn(%d): returns\n", p->p_pid); #endif return (EJUSTRETURN); } /* * Machine dependent boot() routine * * I haven't seen anything to put here yet * Possibly some stuff might be grafted back here from boot() */ void cpu_boot(int howto) { } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { /* TODO */ } /* * Clear registers on exec */ void setregs(struct proc *p, u_long entry, u_long stack, u_long ps_strings) { struct trapframe *frame; frame = p->p_frame; /* * Make sure that we restore the entire trapframe after an * execve. */ frame->tf_flags &= ~FRAME_SYSCALL; bzero(frame->tf_r, sizeof(frame->tf_r)); bzero(frame->tf_f, sizeof(frame->tf_f)); frame->tf_cr_iip = entry; frame->tf_cr_ipsr = (IA64_PSR_IC | IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | IA64_PSR_DFH | IA64_PSR_BN | IA64_PSR_CPL_USER); frame->tf_r[FRAME_SP] = stack; frame->tf_r[FRAME_R14] = ps_strings; /* * Setup the new backing store and make sure the new image * starts executing with an empty register stack frame. */ frame->tf_ar_bspstore = p->p_md.md_bspstore; frame->tf_ndirty = 0; frame->tf_cr_ifs = (1L<<63); /* ifm=0, v=1 */ frame->tf_ar_rsc = 0xf; /* user mode rsc */ frame->tf_ar_fpsr = IA64_FPSR_DEFAULT; p->p_md.md_flags &= ~MDP_FPUSED; ia64_fpstate_drop(p); } int ptrace_set_pc(struct proc *p, unsigned long addr) { /* TODO set pc in trapframe */ return 0; } int ptrace_single_step(struct proc *p) { /* TODO arrange for user process to single step */ return 0; } int ia64_pa_access(vm_offset_t pa) { return VM_PROT_READ|VM_PROT_WRITE; } int fill_regs(p, regs) struct proc *p; struct reg *regs; { /* TODO copy trapframe to regs */ return (0); } int set_regs(p, regs) struct proc *p; struct reg *regs; { /* TODO copy regs to trapframe */ return (0); } int fill_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { /* TODO copy fpu state to fpregs */ ia64_fpstate_save(p, 0); #if 0 bcopy(&p->p_addr->u_pcb.pcb_fp, fpregs, sizeof *fpregs); #endif return (0); } int set_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { /* TODO copy fpregs fpu state */ ia64_fpstate_drop(p); #if 0 bcopy(fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof *fpregs); #endif return (0); } #ifndef DDB void Debugger(const char *msg) { printf("Debugger(\"%s\") called.\n", msg); } #endif /* no DDB */ #include /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. Adjust transfer * if needed, and signal errors or early completion. */ int bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel) { #if 0 struct partition *p = lp->d_partitions + dkpart(bp->bio_dev); int labelsect = lp->d_partitions[0].p_offset; int maxsz = p->p_size, sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect && #endif (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #endif /* beyond partition? */ if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->bio_blkno == maxsz) { bp->bio_resid = bp->bio_bcount; return(0); } /* or truncate if part of it fits */ sz = maxsz - bp->bio_blkno; if (sz <= 0) { bp->bio_error = EINVAL; goto bad; } bp->bio_bcount = sz << DEV_BSHIFT; } bp->bio_pblkno = bp->bio_blkno + p->p_offset; return(1); bad: #endif bp->bio_flags |= BIO_ERROR; return(-1); } static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) { int error; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (!error && req->newptr) resettodr(); return (error); } SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 0, ""); SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, &wall_cmos_clock, 0, ""); void ia64_fpstate_check(struct proc *p) { if ((p->p_frame->tf_cr_ipsr & IA64_PSR_DFH) == 0) if (p != PCPU_GET(fpcurproc)) panic("ia64_check_fpcurproc: bogus"); } /* * Save the high floating point state in the pcb. Use this to get * read-only access to the floating point state. If write is true, the * current fp process is cleared so that fp state can safely be * modified. The process will automatically reload the changed state * by generating a disabled fp trap. */ void ia64_fpstate_save(struct proc *p, int write) { if (p == PCPU_GET(fpcurproc)) { /* * Save the state in the pcb. */ savehighfp(p->p_addr->u_pcb.pcb_highfp); if (write) { p->p_frame->tf_cr_ipsr |= IA64_PSR_DFH; PCPU_SET(fpcurproc, NULL); } } } /* * Relinquish ownership of the FP state. This is called instead of * ia64_save_fpstate() if the entire FP state is being changed * (e.g. on sigreturn). */ void ia64_fpstate_drop(struct proc *p) { if (p == PCPU_GET(fpcurproc)) { p->p_frame->tf_cr_ipsr |= IA64_PSR_DFH; PCPU_SET(fpcurproc, NULL); } } /* * Switch the current owner of the fp state to p, reloading the state * from the pcb. */ void ia64_fpstate_switch(struct proc *p) { if (PCPU_GET(fpcurproc)) { /* * Dump the old fp state if its valid. */ savehighfp(PCPU_GET(fpcurproc)->p_addr->u_pcb.pcb_highfp); PCPU_GET(fpcurproc)->p_frame->tf_cr_ipsr |= IA64_PSR_DFH; } /* * Remember the new FP owner and reload its state. */ PCPU_SET(fpcurproc, p); restorehighfp(p->p_addr->u_pcb.pcb_highfp); p->p_frame->tf_cr_ipsr &= ~IA64_PSR_DFH; p->p_md.md_flags |= MDP_FPUSED; } /* * Initialise a struct globaldata. */ void globaldata_init(struct globaldata *globaldata, int cpuid, size_t sz) { bzero(globaldata, sz); globaldata->gd_cpuid = cpuid; globaldata_register(globaldata); } Index: head/sys/pc98/i386/machdep.c =================================================================== --- head/sys/pc98/i386/machdep.c (revision 82392) +++ head/sys/pc98/i386/machdep.c (revision 82393) @@ -1,2598 +1,2600 @@ /*- * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD$ */ #include "opt_atalk.h" #include "opt_compat.h" #include "opt_cpu.h" #include "opt_ddb.h" #include "opt_inet.h" #include "opt_ipx.h" #include "opt_isa.h" #include "opt_maxmem.h" #include "opt_msgbuf.h" #include "opt_npx.h" #include "opt_perfmon.h" #include "opt_upages.h" /* #include "opt_userconfig.h" */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* pcb.h included via sys/user.h */ #include #ifdef PERFMON #include #endif #ifdef SMP #include #endif #include #include #ifdef PC98 #include #include #else #include #endif #include #include #include extern void init386 __P((int first)); extern void dblfault_handler __P((void)); extern void printcpuinfo(void); /* XXX header file */ extern void earlysetcpuclass(void); /* same header file */ extern void finishidentcpu(void); extern void panicifcpuunsupported(void); extern void initializecpu(void); #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) #define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) static void cpu_startup __P((void *)); #ifdef CPU_ENABLE_SSE static void set_fpregs_xmm __P((struct save87 *, struct savexmm *)); static void fill_fpregs_xmm __P((struct savexmm *, struct save87 *)); #endif /* CPU_ENABLE_SSE */ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL) #ifdef PC98 int need_pre_dma_flush; /* If 1, use wbinvd befor DMA transfer. */ int need_post_dma_flush; /* If 1, use invd after DMA transfer. */ #endif int _udatasel, _ucodesel; u_int atdevbase; #if defined(SWTCH_OPTIM_STATS) extern int swtch_optim_stats; SYSCTL_INT(_debug, OID_AUTO, swtch_optim_stats, CTLFLAG_RD, &swtch_optim_stats, 0, ""); SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count, CTLFLAG_RD, &tlb_flush_count, 0, ""); #endif #ifdef PC98 static int ispc98 = 1; #else static int ispc98 = 0; #endif SYSCTL_INT(_machdep, OID_AUTO, ispc98, CTLFLAG_RD, &ispc98, 0, ""); int physmem = 0; int cold = 1; #ifdef COMPAT_43 static void osendsig __P((sig_t catcher, int sig, sigset_t *mask, u_long code)); #endif static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem), req); return (error); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "IU", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem - cnt.v_wire_count), req); return (error); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "IU", ""); static int sysctl_hw_availpages(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, i386_btop(avail_end - avail_start), req); return (error); } SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_availpages, "I", ""); int Maxmem = 0; #ifdef PC98 int Maxmem_under16M = 0; #endif long dumplo; vm_offset_t phys_avail[10]; /* must be 2 less so 0 0 can signal end of chunks */ #define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2) struct kva_md_info kmi; static struct trapframe proc0_tf; #ifndef SMP static struct globaldata __globaldata; #endif struct mtx sched_lock; struct mtx Giant; static void cpu_startup(dummy) void *dummy; { /* * Good {morning,afternoon,evening,night}. */ earlysetcpuclass(); startrtclock(); printcpuinfo(); panicifcpuunsupported(); #ifdef PERFMON perfmon_init(); #endif printf("real memory = %u (%uK bytes)\n", ptoa(Maxmem), ptoa(Maxmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { unsigned int size1; size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08x - 0x%08x, %u bytes (%u pages)\n", phys_avail[indx], phys_avail[indx + 1] - 1, size1, size1 / PAGE_SIZE); } } vm_ksubmap_init(&kmi); #if 0 /* * Calculate callout wheel size */ for (callwheelsize = 1, callwheelbits = 0; callwheelsize < ncallout; callwheelsize <<= 1, ++callwheelbits) ; callwheelmask = callwheelsize - 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(callout, struct callout, ncallout); valloc(callwheel, struct callout_tailq, callwheelsize); /* * Discount the physical memory larger than the size of kernel_map * to avoid eating up all of KVA space. */ if (kernel_map->first_free == NULL) { printf("Warning: no free entries in kernel_map.\n"); physmem_est = physmem; } else { physmem_est = min(physmem, btoc(kernel_map->max_offset - kernel_map->min_offset)); } /* * The nominal buffer size (and minimum KVA allocation) is BKVASIZE. * For the first 64MB of ram nominally allocate sufficient buffers to * cover 1/4 of our ram. Beyond the first 64MB allocate additional * buffers to cover 1/20 of our ram over 64MB. When auto-sizing * the buffer cache we limit the eventual kva reservation to * maxbcache bytes. * * factor represents the 1/4 x ram conversion. */ if (nbuf == 0) { int factor = 4 * BKVASIZE / PAGE_SIZE; nbuf = 50; if (physmem_est > 1024) nbuf += min((physmem_est - 1024) / factor, 16384 / factor); if (physmem_est > 16384) nbuf += (physmem_est - 16384) * 2 / (factor * 5); if (maxbcache && nbuf > maxbcache / BKVASIZE) nbuf = maxbcache / BKVASIZE; } /* * Do not allow the buffer_map to be more then 1/2 the size of the * kernel_map. */ if (nbuf > (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2)) { nbuf = (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2); printf("Warning: nbufs capped at %d\n", nbuf); } nswbuf = max(min(nbuf/4, 256), 16); valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); v = bufhashinit(v); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size); buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, (nbuf*BKVASIZE)); buffer_map->system_map = 1; pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, (nswbuf*MAXPHYS) + pager_map_size); pager_map->system_map = 1; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (16*(ARG_MAX+(PAGE_SIZE*3)))); /* * XXX: Mbuf system machine-specific initializations should * go here, if anywhere. */ /* * Initialize callouts */ SLIST_INIT(&callfree); for (i = 0; i < ncallout; i++) { callout_init(&callout[i], 0); callout[i].c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle); } for (i = 0; i < callwheelsize; i++) { TAILQ_INIT(&callwheel[i]); } mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE); #endif #if defined(USERCONFIG) userconfig(); cninit(); /* the preferred console may have changed */ #endif printf("avail memory = %u (%uK bytes)\n", ptoa(cnt.v_free_count), ptoa(cnt.v_free_count) / 1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); globaldata_register(GLOBALDATA); #ifndef SMP /* For SMP, we delay the cpu_setregs() until after SMP startup. */ cpu_setregs(); #endif } /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ #ifdef COMPAT_43 static void osendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct osigframe sf; struct osigframe *fp; struct proc *p; struct sigacts *psp; struct trapframe *regs; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct osigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct osigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else fp = (struct osigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *fp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)fp) == 0 || !useracc((caddr_t)fp, sizeof(*fp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; } else { /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* Save most if not all of trap frame. */ sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax; sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx; sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx; sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx; sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi; sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi; sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs; sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds; sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss; sf.sf_siginfo.si_sc.sc_es = regs->tf_es; sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs; sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; /* Build the signal context to be used by osigreturn(). */ sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0; SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags; sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno; sf.sf_siginfo.si_sc.sc_err = regs->tf_err; /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs; sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs; sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es; sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* See sendsig() for comments. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, fp, sizeof(*fp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)fp; regs->tf_eip = PS_STRINGS - szosigcode; regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; load_gs(_udatasel); regs->tf_ss = _udatasel; } #endif void sendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct sigframe sf; struct proc *p; struct sigacts *psp; struct trapframe *regs; struct sigframe *sfp; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { PROC_UNLOCK(p); osendsig(catcher, sig, mask, code); return; } #endif regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_gs = rgs(); bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct sigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sfp = (struct sigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *sfp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)sfp) == 0 || !useracc((caddr_t)sfp, sizeof(*sfp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG printf("process %d has trashed its stack\n", p->p_pid); #endif PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_ucontext = (register_t)&sfp->sf_uc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_siginfo = (register_t)&sfp->sf_si; sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; /* Fill siginfo structure. */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void *)regs->tf_err; } else { /* Old FreeBSD-style arguments. */ sf.sf_siginfo = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_uc.uc_mcontext.mc_eflags = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 * mode. It may be set here if we deliver a signal before * getting to vm86 mode, so turn it off. * * Clear PSL_NT to inhibit T_TSSFLT faults on return from * syscalls made by the signal handler. This just avoids * wasting time for our lazy fixup of such faults. PSL_NT * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_ss = _udatasel; } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ #ifdef COMPAT_43 int osigreturn(p, uap) struct proc *p; struct osigreturn_args /* { struct osigcontext *sigcntxp; } */ *uap; { struct trapframe *regs; struct osigcontext *scp; int eflags; regs = p->p_frame; scp = uap->sigcntxp; if (!useracc((caddr_t)scp, sizeof(*scp), VM_PROT_READ)) return (EFAULT); eflags = scp->sc_ps; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } tf->tf_vm86_ds = scp->sc_ds; tf->tf_vm86_es = scp->sc_es; tf->tf_vm86_fs = scp->sc_fs; tf->tf_vm86_gs = scp->sc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ if (!CS_SECURE(scp->sc_cs)) { trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } regs->tf_ds = scp->sc_ds; regs->tf_es = scp->sc_es; regs->tf_fs = scp->sc_fs; } /* Restore remaining registers. */ regs->tf_eax = scp->sc_eax; regs->tf_ebx = scp->sc_ebx; regs->tf_ecx = scp->sc_ecx; regs->tf_edx = scp->sc_edx; regs->tf_esi = scp->sc_esi; regs->tf_edi = scp->sc_edi; regs->tf_cs = scp->sc_cs; regs->tf_ss = scp->sc_ss; regs->tf_isp = scp->sc_isp; PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (scp->sc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif SIGSETOLD(p->p_sigmask, scp->sc_mask); SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; regs->tf_eflags = eflags; return (EJUSTRETURN); } #endif int sigreturn(p, uap) struct proc *p; struct sigreturn_args /* { ucontext_t *sigcntxp; } */ *uap; { struct trapframe *regs; ucontext_t *ucp; int cs, eflags; ucp = uap->sigcntxp; #ifdef COMPAT_43 if (!useracc((caddr_t)ucp, sizeof(struct osigcontext), VM_PROT_READ)) return (EFAULT); if (((struct osigcontext *)ucp)->sc_trapno == 0x01d516) return (osigreturn(p, (struct osigreturn_args *)uap)); /* * Since ucp is not an osigcontext but a ucontext_t, we have to * check again if all of it is accessible. A ucontext_t is * much larger, so instead of just checking for the pointer * being valid for the size of an osigcontext, now check for * it being valid for a whole, new-style ucontext_t. */ #endif if (!useracc((caddr_t)ucp, sizeof(*ucp), VM_PROT_READ)) return (EFAULT); regs = p->p_frame; eflags = ucp->uc_mcontext.mc_eflags; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); tf->tf_eflags = eflags; tf->tf_vm86_ds = tf->tf_ds; tf->tf_vm86_es = tf->tf_es; tf->tf_vm86_fs = tf->tf_fs; tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { printf("sigreturn: eflags = 0x%x\n", eflags); return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ cs = ucp->uc_mcontext.mc_cs; if (!CS_SECURE(cs)) { printf("sigreturn: cs = 0x%x\n", cs); trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); } PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (ucp->uc_mcontext.mc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif p->p_sigmask = ucp->uc_sigmask; SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); return (EJUSTRETURN); } /* * Machine dependent boot() routine * * I haven't seen anything to put here yet * Possibly some stuff might be grafted back here from boot() */ void cpu_boot(int howto) { } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { for (;;) __asm__ ("hlt"); } /* * Hook to idle the CPU when possible. This currently only works in * the !SMP case, as there is no clean way to ensure that a CPU will be * woken when there is work available for it. */ static int cpu_idle_hlt = 1; SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, &cpu_idle_hlt, 0, "Idle loop HLT enable"); /* * Note that we have to be careful here to avoid a race between checking * procrunnable() and actually halting. If we don't do this, we may waste * the time between calling hlt and the next interrupt even though there * is a runnable process. */ void cpu_idle(void) { #ifndef SMP if (cpu_idle_hlt) { disable_intr(); if (procrunnable()) enable_intr(); else { enable_intr(); __asm __volatile("hlt"); } } #endif } /* * Clear registers on exec */ void setregs(p, entry, stack, ps_strings) struct proc *p; u_long entry; u_long stack; u_long ps_strings; { struct trapframe *regs = p->p_frame; struct pcb *pcb = &p->p_addr->u_pcb; if (pcb->pcb_ldt) user_ldt_free(pcb); bzero((char *)regs, sizeof(struct trapframe)); regs->tf_eip = entry; regs->tf_esp = stack; regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T); regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_cs = _ucodesel; /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */ regs->tf_ebx = ps_strings; /* reset %gs as well */ if (pcb == PCPU_GET(curpcb)) load_gs(_udatasel); else pcb->pcb_gs = _udatasel; /* * Reset the hardware debug registers if they were in use. * They won't have any meaning for the newly exec'd process. */ if (pcb->pcb_flags & PCB_DBREGS) { pcb->pcb_dr0 = 0; pcb->pcb_dr1 = 0; pcb->pcb_dr2 = 0; pcb->pcb_dr3 = 0; pcb->pcb_dr6 = 0; pcb->pcb_dr7 = 0; if (pcb == PCPU_GET(curpcb)) { /* * Clear the debug registers on the running * CPU, otherwise they will end up affecting * the next process we switch to. */ reset_dbregs(); } pcb->pcb_flags &= ~PCB_DBREGS; } /* * Initialize the math emulator (if any) for the current process. * Actually, just clear the bit that says that the emulator has * been initialized. Initialization is delayed until the process * traps to the emulator (if it is done at all) mainly because * emulators don't provide an entry point for initialization. */ p->p_addr->u_pcb.pcb_flags &= ~FP_SOFTFP; /* * Arrange to trap the next npx or `fwait' instruction (see npx.c * for why fwait must be trapped at least if there is an npx or an * emulator). This is mainly to handle the case where npx0 is not * configured, since the npx routines normally set up the trap * otherwise. It should be done only at boot time, but doing it * here allows modifying `npx_exists' for testing the emulator on * systems with an npx. */ load_cr0(rcr0() | CR0_MP | CR0_TS); #ifdef DEV_NPX /* Initialize the npx (if any) for the current process. */ npxinit(__INITIAL_NPXCW__); #endif /* * XXX - Linux emulator * Make sure sure edx is 0x0 on entry. Linux binaries depend * on it. */ p->p_retval[1] = 0; } void cpu_setregs(void) { unsigned int cr0; cr0 = rcr0(); cr0 |= CR0_NE; /* Done by npxinit() */ cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */ #ifndef I386_CPU cr0 |= CR0_WP | CR0_AM; #endif load_cr0(cr0); load_gs(_udatasel); } static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) { int error; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (!error && req->newptr) resettodr(); return (error); } SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 0, ""); SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo, CTLFLAG_RD, &bootinfo, bootinfo, ""); SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, &wall_cmos_clock, 0, ""); /* * Initialize 386 and configure to run kernel */ /* * Initialize segments & interrupt table */ int _default_ldt; union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ static struct gate_descriptor idt0[NIDT]; struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ #ifdef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif int private_tss; /* flag indicating private tss */ #if defined(I586_CPU) && !defined(NO_F00F_HACK) extern int has_f00f_bug; #endif static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; extern struct user *proc0paddr; /* software prototypes -- in more palatable form */ struct soft_segment_descriptor gdt_segs[] = { /* GNULL_SEL 0 Null Descriptor */ { 0x0, /* segment base address */ 0x0, /* length */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GCODE_SEL 1 Code Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GDATA_SEL 2 Data Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPRIV_SEL 3 SMP Per-Processor Private Data Descriptor */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPROC0_SEL 4 Proc 0 Tss Descriptor */ { 0x0, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GLDT_SEL 5 LDT Descriptor */ { (int) ldt, /* segment base address */ sizeof(ldt)-1, /* length - all address space */ SDT_SYSLDT, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GUSERLDT_SEL 6 User LDT Descriptor per process */ { (int) ldt, /* segment base address */ (512 * sizeof(union descriptor)-1), /* length */ SDT_SYSLDT, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GTGATE_SEL 7 Null Descriptor - Placeholder */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSLOWMEM_SEL 8 BIOS access to realmode segment 0x40, must be #8 in GDT */ { 0x400, /* segment base address */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPANIC_SEL 9 Panic Tss Descriptor */ { (int) &dblfault_tss, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE32_SEL 10 BIOS 32-bit interface (32bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE16_SEL 11 BIOS 32-bit interface (16bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSDATA_SEL 12 BIOS 32-bit interface (Data) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSUTIL_SEL 13 BIOS 16-bit interface (Utility) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSARGS_SEL 14 BIOS 16-bit interface (Arguments) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Code Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Data Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; void setidt(idx, func, typ, dpl, selec) int idx; inthand_t *func; int typ; int dpl; int selec; { struct gate_descriptor *ip; ip = idt + idx; ip->gd_looffset = (int)func; ip->gd_selector = selec; ip->gd_stkcpy = 0; ip->gd_xx = 0; ip->gd_type = typ; ip->gd_dpl = dpl; ip->gd_p = 1; ip->gd_hioffset = ((int)func)>>16 ; } #define IDTVEC(name) __CONCAT(X,name) extern inthand_t IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); void sdtossd(sd, ssd) struct segment_descriptor *sd; struct soft_segment_descriptor *ssd; { ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; ssd->ssd_type = sd->sd_type; ssd->ssd_dpl = sd->sd_dpl; ssd->ssd_p = sd->sd_p; ssd->ssd_def32 = sd->sd_def32; ssd->ssd_gran = sd->sd_gran; } #define PHYSMAP_SIZE (2 * 8) /* * Populate the (physmap) array with base/bound pairs describing the * available physical memory in the system, then test this memory and * build the phys_avail array describing the actually-available memory. * * If we cannot accurately determine the physical memory map, then use * value from the 0xE801 call, and failing that, the RTC. * * Total memory size may be set by the kernel environment variable * hw.physmem or the compile-time define MAXMEM. */ static void getmemsize(int first) { int i, physmap_idx, pa_indx; u_int basemem, extmem; #ifdef PC98 int pg_n; u_int under16; #else struct vm86frame vmf; struct vm86context vmc; #endif vm_offset_t pa, physmap[PHYSMAP_SIZE]; pt_entry_t pte; const char *cp; #ifndef PC98 struct bios_smap *smap; #endif #ifdef PC98 /* XXX - some of EPSON machines can't use PG_N */ pg_n = PG_N; if (pc98_machine_type & M_EPSON_PC98) { switch (epson_machine_id) { #ifdef WB_CACHE default: #endif case 0x34: /* PC-486HX */ case 0x35: /* PC-486HG */ case 0x3B: /* PC-486HA */ pg_n = 0; break; } } #else bzero(&vmf, sizeof(struct vm86frame)); #endif bzero(physmap, sizeof(physmap)); /* * Perform "base memory" related probes & setup */ #ifdef PC98 under16 = pc98_getmemsize(&basemem, &extmem); #else vm86_intcall(0x12, &vmf); basemem = vmf.vmf_ax; #endif if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); basemem = 640; } /* * XXX if biosbasemem is now < 640, there is a `hole' * between the end of base memory and the start of * ISA memory. The hole may be empty or it may * contain BIOS code or data. Map it read/write so * that the BIOS can write to it. (Memory from 0 to * the physical end of the kernel is mapped read-only * to begin with and then parts of it are remapped. * The parts that aren't remapped form holes that * remain read-only and are unused by the kernel. * The base memory area is below the physical end of * the kernel and right now forms a read-only hole. * The part of it from PAGE_SIZE to * (trunc_page(biosbasemem * 1024) - 1) will be * remapped and used by the kernel later.) * * This code is similar to the code used in * pmap_mapdev, but since no memory needs to be * allocated we simply change the mapping. */ for (pa = trunc_page(basemem * 1024); pa < ISA_HOLE_START; pa += PAGE_SIZE) { pte = (pt_entry_t)vtopte(pa + KERNBASE); *pte = pa | PG_RW | PG_V; } /* * if basemem != 640, map pages r/w into vm86 page table so * that the bios can scribble on it. */ pte = (pt_entry_t)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; #ifndef PC98 /* * map page 1 R/W into the kernel page table so we can use it * as a buffer. The kernel will unmap this page later. */ pte = (pt_entry_t)vtopte(KERNBASE + (1 << PAGE_SHIFT)); *pte = (1 << PAGE_SHIFT) | PG_RW | PG_V; /* * get memory map with INT 15:E820 */ vmc.npages = 0; smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); physmap_idx = 0; vmf.vmf_ebx = 0; do { vmf.vmf_eax = 0xE820; vmf.vmf_edx = SMAP_SIG; vmf.vmf_ecx = sizeof(struct bios_smap); i = vm86_datacall(0x15, &vmf, &vmc); if (i || vmf.vmf_eax != SMAP_SIG) break; if (boothowto & RB_VERBOSE) printf("SMAP type=%02x base=%08x %08x len=%08x %08x\n", smap->type, *(u_int32_t *)((char *)&smap->base + 4), (u_int32_t)smap->base, *(u_int32_t *)((char *)&smap->length + 4), (u_int32_t)smap->length); if (smap->type != 0x01) goto next_run; if (smap->length == 0) goto next_run; if (smap->base >= 0xffffffff) { printf("%uK of memory above 4GB ignored\n", (u_int)(smap->length / 1024)); goto next_run; } for (i = 0; i <= physmap_idx; i += 2) { if (smap->base < physmap[i + 1]) { if (boothowto & RB_VERBOSE) printf( "Overlapping or non-montonic memory region, ignoring second region\n"); goto next_run; } } if (smap->base == physmap[physmap_idx + 1]) { physmap[physmap_idx + 1] += smap->length; goto next_run; } physmap_idx += 2; if (physmap_idx == PHYSMAP_SIZE) { printf( "Too many segments in the physical address map, giving up\n"); break; } physmap[physmap_idx] = smap->base; physmap[physmap_idx + 1] = smap->base + smap->length; next_run: } while (vmf.vmf_ebx != 0); if (physmap[1] != 0) goto physmap_done; /* * If we failed above, try memory map with INT 15:E801 */ vmf.vmf_ax = 0xE801; if (vm86_intcall(0x15, &vmf) == 0) { extmem = vmf.vmf_cx + vmf.vmf_dx * 64; } else { #if 0 vmf.vmf_ah = 0x88; vm86_intcall(0x15, &vmf); extmem = vmf.vmf_ax; #else /* * Prefer the RTC value for extended memory. */ extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8); #endif } /* * Special hack for chipsets that still remap the 384k hole when * there's 16MB of memory - this really confuses people that * are trying to use bus mastering ISA controllers with the * "16MB limit"; they only have 16MB, but the remapping puts * them beyond the limit. * * If extended memory is between 15-16MB (16-17MB phys address range), * chop it to 15MB. */ if ((extmem > 15 * 1024) && (extmem < 16 * 1024)) extmem = 15 * 1024; #endif physmap[0] = 0; physmap[1] = basemem * 1024; physmap_idx = 2; physmap[physmap_idx] = 0x100000; physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024; #ifdef PC98 if ((under16 != 16 * 1024) && (extmem > 15 * 1024)) { /* 15M - 16M region is cut off, so need to divide chunk */ physmap[physmap_idx + 1] = under16 * 1024; physmap_idx += 2; physmap[physmap_idx] = 0x1000000; physmap[physmap_idx + 1] = physmap[2] + extmem * 1024; } #else physmap_done: #endif /* * Now, physmap contains a map of physical memory. */ #ifdef SMP /* make hole for AP bootstrap code */ physmap[1] = mp_bootaddress(physmap[1] / 1024); /* look for the MP hardware - needed for apic addresses */ i386_mp_probe(); #endif /* * Maxmem isn't the "maximum memory", it's one larger than the * highest page of the physical address space. It should be * called something like "Maxphyspage". We may adjust this * based on ``hw.physmem'' and the results of the memory test. */ Maxmem = atop(physmap[physmap_idx + 1]); #ifdef MAXMEM Maxmem = MAXMEM / 4; #endif /* * hw.physmem is a size in bytes; we also allow k, m, and g suffixes * for the appropriate modifiers. This overrides MAXMEM. */ if ((cp = getenv("hw.physmem")) != NULL) { u_int64_t AllowMem, sanity; char *ep; sanity = AllowMem = strtouq(cp, &ep, 0); if ((ep != cp) && (*ep != 0)) { switch(*ep) { case 'g': case 'G': AllowMem <<= 10; case 'm': case 'M': AllowMem <<= 10; case 'k': case 'K': AllowMem <<= 10; break; default: AllowMem = sanity = 0; } if (AllowMem < sanity) AllowMem = 0; } if (AllowMem == 0) printf("Ignoring invalid memory size of '%s'\n", cp); else Maxmem = atop(AllowMem); } if (atop(physmap[physmap_idx + 1]) != Maxmem && (boothowto & RB_VERBOSE)) printf("Physical memory use set to %uK\n", Maxmem * 4); /* * If Maxmem has been increased beyond what the system has detected, * extend the last memory segment to the new limit. */ if (atop(physmap[physmap_idx + 1]) < Maxmem) physmap[physmap_idx + 1] = ptoa(Maxmem); /* call pmap initialization to make new kernel address space */ pmap_bootstrap(first, 0); /* * Size up each available chunk of physical memory. */ physmap[0] = PAGE_SIZE; /* mask off page 0 */ pa_indx = 0; phys_avail[pa_indx++] = physmap[0]; phys_avail[pa_indx] = physmap[0]; #if 0 pte = (pt_entry_t)vtopte(KERNBASE); #else pte = (pt_entry_t)CMAP1; #endif /* * physmap is in bytes, so when converting to page boundaries, * round up the start address and round down the end address. */ for (i = 0; i <= physmap_idx; i += 2) { vm_offset_t end; end = ptoa(Maxmem); if (physmap[i + 1] < end) end = trunc_page(physmap[i + 1]); for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) { int tmp, page_bad; #if 0 int *ptr = 0; #else int *ptr = (int *)CADDR1; #endif /* * block out kernel memory as not available. */ if (pa >= 0x100000 && pa < first) continue; page_bad = FALSE; /* * map page into kernel: valid, read/write,non-cacheable */ #ifdef PC98 *pte = pa | PG_V | PG_RW | pg_n; #else *pte = pa | PG_V | PG_RW | PG_N; #endif invltlb(); tmp = *(int *)ptr; /* * Test for alternating 1's and 0's */ *(volatile int *)ptr = 0xaaaaaaaa; if (*(volatile int *)ptr != 0xaaaaaaaa) { page_bad = TRUE; } /* * Test for alternating 0's and 1's */ *(volatile int *)ptr = 0x55555555; if (*(volatile int *)ptr != 0x55555555) { page_bad = TRUE; } /* * Test for all 1's */ *(volatile int *)ptr = 0xffffffff; if (*(volatile int *)ptr != 0xffffffff) { page_bad = TRUE; } /* * Test for all 0's */ *(volatile int *)ptr = 0x0; if (*(volatile int *)ptr != 0x0) { page_bad = TRUE; } /* * Restore original value. */ *(int *)ptr = tmp; /* * Adjust array of valid/good pages. */ if (page_bad == TRUE) { continue; } /* * If this good page is a continuation of the * previous set of good pages, then just increase * the end pointer. Otherwise start a new chunk. * Note that "end" points one higher than end, * making the range >= start and < end. * If we're also doing a speculative memory * test and we at or past the end, bump up Maxmem * so that we keep going. The first bad page * will terminate the loop. */ if (phys_avail[pa_indx] == pa) { phys_avail[pa_indx] += PAGE_SIZE; } else { pa_indx++; if (pa_indx == PHYS_AVAIL_ARRAY_END) { printf( "Too many holes in the physical address space, giving up\n"); pa_indx--; break; } phys_avail[pa_indx++] = pa; /* start */ phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */ } physmem++; } } *pte = 0; invltlb(); /* * XXX * The last chunk must contain at least one page plus the message * buffer to avoid complicating other code (message buffer address * calculation, etc.). */ while (phys_avail[pa_indx - 1] + PAGE_SIZE + round_page(MSGBUF_SIZE) >= phys_avail[pa_indx]) { physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]); phys_avail[pa_indx--] = 0; phys_avail[pa_indx--] = 0; } Maxmem = atop(phys_avail[pa_indx]); /* Trim off space for the message buffer. */ phys_avail[pa_indx] -= round_page(MSGBUF_SIZE); avail_end = phys_avail[pa_indx]; } void init386(first) int first; { struct gate_descriptor *gdp; int gsel_tss, metadata_missing, off, x; #ifndef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif proc0.p_addr = proc0paddr; atdevbase = ISA_HOLE_START + KERNBASE; #ifdef PC98 /* * Initialize DMAC */ pc98_init_dmac(); #endif metadata_missing = 0; if (bootinfo.bi_modulep) { preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE; preload_bootstrap_relocate(KERNBASE); } else { metadata_missing = 1; } - if (bootinfo.bi_envp) + if (envmode == 1) + kern_envp = static_env; + else if (bootinfo.bi_envp) kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; /* Init basic tunables, hz etc */ init_param(); /* * make gdt memory segments, the code segment goes up to end of the * page with etext in it, the data segment goes to the end of * the address space */ /* * XXX text protection is temporarily (?) disabled. The limit was * i386_btop(round_page(etext)) - 1. */ gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1); gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1); #ifdef SMP gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct privatespace) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[0]; gdt_segs[GPROC0_SEL].ssd_base = (int) &SMP_prvspace[0].globaldata.gd_common_tss; SMP_prvspace[0].globaldata.gd_prvspace = &SMP_prvspace[0].globaldata; #else gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct globaldata) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &__globaldata; gdt_segs[GPROC0_SEL].ssd_base = (int) &__globaldata.gd_common_tss; __globaldata.gd_prvspace = &__globaldata; #endif for (x = 0; x < NGDT; x++) { #ifdef BDE_DEBUGGER /* avoid overwriting db entries with APM ones */ if (x >= GAPMCODE32_SEL && x <= GAPMDATA_SEL) continue; #endif ssdtosd(&gdt_segs[x], &gdt[x].sd); } r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; r_gdt.rd_base = (int) gdt; lgdt(&r_gdt); /* setup curproc so that mutexes work */ PCPU_SET(curproc, &proc0); PCPU_SET(spinlocks, NULL); LIST_INIT(&proc0.p_contested); /* * Initialize mutexes. */ mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE); mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE); mtx_init(&proc0.p_mtx, "process lock", MTX_DEF); mtx_init(&clock_lock, "clk", MTX_SPIN | MTX_RECURSE); #ifdef SMP mtx_init(&imen_mtx, "imen", MTX_SPIN); #endif mtx_lock(&Giant); /* make ldt memory segments */ /* * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it * should be spelled ...MAX_USER... */ ldt_segs[LUCODE_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); ldt_segs[LUDATA_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++) ssdtosd(&ldt_segs[x], &ldt[x].sd); _default_ldt = GSEL(GLDT_SEL, SEL_KPL); lldt(_default_ldt); PCPU_SET(currentldt, _default_ldt); /* exceptions */ for (x = 0; x < NIDT; x++) setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(1, &IDTVEC(dbg), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(3, &IDTVEC(bpt), SDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL , GSEL(GCODE_SEL, SEL_KPL)); setidt(8, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL)); setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(14, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(18, &IDTVEC(mchk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(19, &IDTVEC(xmm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); r_idt.rd_limit = sizeof(idt0) - 1; r_idt.rd_base = (int) idt; lidt(&r_idt); /* * Initialize the console before we print anything out. */ cninit(); if (metadata_missing) printf("WARNING: loader(8) metadata is missing!\n"); #ifdef DEV_ISA isa_defaultirq(); #endif #ifdef DDB kdb_init(); if (boothowto & RB_KDB) Debugger("Boot flags requested debugger"); #endif finishidentcpu(); /* Final stage of CPU initialization */ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); initializecpu(); /* Initialize CPU registers */ /* make an initial tss so cpu can get interrupt stack on syscall! */ PCPU_SET(common_tss.tss_esp0, (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16); PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); private_tss = 0; PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); ltr(gsel_tss); dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)]; dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 = dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_cr3 = (int)IdlePTD; dblfault_tss.tss_eip = (int)dblfault_handler; dblfault_tss.tss_eflags = PSL_KERNEL; dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL); dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL); dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL); vm86_initialize(); getmemsize(first); /* now running on new page tables, configured,and u/iom is accessible */ /* Map the message buffer. */ for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE) pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off); msgbufinit(msgbufp, MSGBUF_SIZE); /* make a call gate to reenter kernel with */ gdp = &ldt[LSYS5CALLS_SEL].gd; x = (int) &IDTVEC(lcall_syscall); gdp->gd_looffset = x; gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); gdp->gd_stkcpy = 1; gdp->gd_type = SDT_SYS386CGT; gdp->gd_dpl = SEL_UPL; gdp->gd_p = 1; gdp->gd_hioffset = x >> 16; /* XXX does this work? */ ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL]; ldt[LSOL26CALLS_SEL] = ldt[LSYS5CALLS_SEL]; /* transfer to user mode */ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); _udatasel = LSEL(LUDATA_SEL, SEL_UPL); /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = (int)IdlePTD; proc0.p_addr->u_pcb.pcb_ext = 0; proc0.p_frame = &proc0_tf; } #if defined(I586_CPU) && !defined(NO_F00F_HACK) static void f00f_hack(void *unused); SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); static void f00f_hack(void *unused) { struct gate_descriptor *new_idt; #ifndef SMP struct region_descriptor r_idt; #endif vm_offset_t tmp; if (!has_f00f_bug) return; GIANT_REQUIRED; printf("Intel Pentium detected, installing workaround for F00F bug\n"); r_idt.rd_limit = sizeof(idt0) - 1; tmp = kmem_alloc(kernel_map, PAGE_SIZE * 2); if (tmp == 0) panic("kmem_alloc returned 0"); if (((unsigned int)tmp & (PAGE_SIZE-1)) != 0) panic("kmem_alloc returned non-page-aligned memory"); /* Put the first seven entries in the lower page */ new_idt = (struct gate_descriptor*)(tmp + PAGE_SIZE - (7*8)); bcopy(idt, new_idt, sizeof(idt0)); r_idt.rd_base = (int)new_idt; lidt(&r_idt); idt = new_idt; if (vm_map_protect(kernel_map, tmp, tmp + PAGE_SIZE, VM_PROT_READ, FALSE) != KERN_SUCCESS) panic("vm_map_protect failed"); return; } #endif /* defined(I586_CPU) && !NO_F00F_HACK */ int ptrace_set_pc(p, addr) struct proc *p; unsigned long addr; { p->p_frame->tf_eip = addr; return (0); } int ptrace_single_step(p) struct proc *p; { p->p_frame->tf_eflags |= PSL_T; return (0); } int fill_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; regs->r_fs = tp->tf_fs; regs->r_es = tp->tf_es; regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_edi; regs->r_esi = tp->tf_esi; regs->r_ebp = tp->tf_ebp; regs->r_ebx = tp->tf_ebx; regs->r_edx = tp->tf_edx; regs->r_ecx = tp->tf_ecx; regs->r_eax = tp->tf_eax; regs->r_eip = tp->tf_eip; regs->r_cs = tp->tf_cs; regs->r_eflags = tp->tf_eflags; regs->r_esp = tp->tf_esp; regs->r_ss = tp->tf_ss; pcb = &p->p_addr->u_pcb; regs->r_gs = pcb->pcb_gs; return (0); } int set_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; tp->tf_edi = regs->r_edi; tp->tf_esi = regs->r_esi; tp->tf_ebp = regs->r_ebp; tp->tf_ebx = regs->r_ebx; tp->tf_edx = regs->r_edx; tp->tf_ecx = regs->r_ecx; tp->tf_eax = regs->r_eax; tp->tf_eip = regs->r_eip; tp->tf_cs = regs->r_cs; tp->tf_eflags = regs->r_eflags; tp->tf_esp = regs->r_esp; tp->tf_ss = regs->r_ss; pcb = &p->p_addr->u_pcb; pcb->pcb_gs = regs->r_gs; return (0); } #ifdef CPU_ENABLE_SSE static void fill_fpregs_xmm(sv_xmm, sv_87) struct savexmm *sv_xmm; struct save87 *sv_87; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_87->en_cw = penv_xmm->en_cw; penv_87->en_sw = penv_xmm->en_sw; penv_87->en_tw = penv_xmm->en_tw; penv_87->en_fip = penv_xmm->en_fip; penv_87->en_fcs = penv_xmm->en_fcs; penv_87->en_opcode = penv_xmm->en_opcode; penv_87->en_foo = penv_xmm->en_foo; penv_87->en_fos = penv_xmm->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc; sv_87->sv_ex_sw = sv_xmm->sv_ex_sw; } static void set_fpregs_xmm(sv_87, sv_xmm) struct save87 *sv_87; struct savexmm *sv_xmm; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_xmm->en_cw = penv_87->en_cw; penv_xmm->en_sw = penv_87->en_sw; penv_xmm->en_tw = penv_87->en_tw; penv_xmm->en_fip = penv_87->en_fip; penv_xmm->en_fcs = penv_87->en_fcs; penv_xmm->en_opcode = penv_87->en_opcode; penv_xmm->en_foo = penv_87->en_foo; penv_xmm->en_fos = penv_87->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i]; sv_xmm->sv_ex_sw = sv_87->sv_ex_sw; } #endif /* CPU_ENABLE_SSE */ int fill_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { fill_fpregs_xmm(&p->p_addr->u_pcb.pcb_save.sv_xmm, (struct save87 *)fpregs); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(&p->p_addr->u_pcb.pcb_save.sv_87, fpregs, sizeof *fpregs); return (0); } int set_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { set_fpregs_xmm((struct save87 *)fpregs, &p->p_addr->u_pcb.pcb_save.sv_xmm); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(fpregs, &p->p_addr->u_pcb.pcb_save.sv_87, sizeof *fpregs); return (0); } int fill_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; if (p == NULL) { dbregs->dr0 = rdr0(); dbregs->dr1 = rdr1(); dbregs->dr2 = rdr2(); dbregs->dr3 = rdr3(); dbregs->dr4 = rdr4(); dbregs->dr5 = rdr5(); dbregs->dr6 = rdr6(); dbregs->dr7 = rdr7(); } else { pcb = &p->p_addr->u_pcb; dbregs->dr0 = pcb->pcb_dr0; dbregs->dr1 = pcb->pcb_dr1; dbregs->dr2 = pcb->pcb_dr2; dbregs->dr3 = pcb->pcb_dr3; dbregs->dr4 = 0; dbregs->dr5 = 0; dbregs->dr6 = pcb->pcb_dr6; dbregs->dr7 = pcb->pcb_dr7; } return (0); } int set_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; int i; u_int32_t mask1, mask2; if (p == NULL) { load_dr0(dbregs->dr0); load_dr1(dbregs->dr1); load_dr2(dbregs->dr2); load_dr3(dbregs->dr3); load_dr4(dbregs->dr4); load_dr5(dbregs->dr5); load_dr6(dbregs->dr6); load_dr7(dbregs->dr7); } else { /* * Don't let an illegal value for dr7 get set. Specifically, * check for undefined settings. Setting these bit patterns * result in undefined behaviour and can lead to an unexpected * TRCTRAP. */ for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8; i++, mask1 <<= 2, mask2 <<= 2) if ((dbregs->dr7 & mask1) == mask2) return (EINVAL); pcb = &p->p_addr->u_pcb; /* * Don't let a process set a breakpoint that is not within the * process's address space. If a process could do this, it * could halt the system by setting a breakpoint in the kernel * (if ddb was enabled). Thus, we need to check to make sure * that no breakpoints are being enabled for addresses outside * process's address space, unless, perhaps, we were called by * uid 0. * * XXX - what about when the watched area of the user's * address space is written into from within the kernel * ... wouldn't that still cause a breakpoint to be generated * from within kernel mode? */ if (suser(p) != 0) { if (dbregs->dr7 & 0x3) { /* dr0 is enabled */ if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<2)) { /* dr1 is enabled */ if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<4)) { /* dr2 is enabled */ if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<6)) { /* dr3 is enabled */ if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) return (EINVAL); } } pcb->pcb_dr0 = dbregs->dr0; pcb->pcb_dr1 = dbregs->dr1; pcb->pcb_dr2 = dbregs->dr2; pcb->pcb_dr3 = dbregs->dr3; pcb->pcb_dr6 = dbregs->dr6; pcb->pcb_dr7 = dbregs->dr7; pcb->pcb_flags |= PCB_DBREGS; } return (0); } /* * Return > 0 if a hardware breakpoint has been hit, and the * breakpoint was in user space. Return 0, otherwise. */ int user_dbreg_trap(void) { u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */ u_int32_t bp; /* breakpoint bits extracted from dr6 */ int nbp; /* number of breakpoints that triggered */ caddr_t addr[4]; /* breakpoint addresses */ int i; dr7 = rdr7(); if ((dr7 & 0x000000ff) == 0) { /* * all GE and LE bits in the dr7 register are zero, * thus the trap couldn't have been caused by the * hardware debug registers */ return 0; } nbp = 0; dr6 = rdr6(); bp = dr6 & 0x0000000f; if (!bp) { /* * None of the breakpoint bits are set meaning this * trap was not caused by any of the debug registers */ return 0; } /* * at least one of the breakpoints were hit, check to see * which ones and if any of them are user space addresses */ if (bp & 0x01) { addr[nbp++] = (caddr_t)rdr0(); } if (bp & 0x02) { addr[nbp++] = (caddr_t)rdr1(); } if (bp & 0x04) { addr[nbp++] = (caddr_t)rdr2(); } if (bp & 0x08) { addr[nbp++] = (caddr_t)rdr3(); } for (i=0; i /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. Adjust transfer * if needed, and signal errors or early completion. */ int bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel) { struct partition *p = lp->d_partitions + dkpart(bp->bio_dev); int labelsect = lp->d_partitions[0].p_offset; int maxsz = p->p_size, sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect && #endif (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #endif /* beyond partition? */ if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->bio_blkno == maxsz) { bp->bio_resid = bp->bio_bcount; return(0); } /* or truncate if part of it fits */ sz = maxsz - bp->bio_blkno; if (sz <= 0) { bp->bio_error = EINVAL; goto bad; } bp->bio_bcount = sz << DEV_BSHIFT; } bp->bio_pblkno = bp->bio_blkno + p->p_offset; return(1); bad: bp->bio_flags |= BIO_ERROR; return(-1); } #ifdef DDB /* * Provide inb() and outb() as functions. They are normally only * available as macros calling inlined functions, thus cannot be * called inside DDB. * * The actual code is stolen from , and de-inlined. */ #undef inb #undef outb /* silence compiler warnings */ u_char inb(u_int); void outb(u_int, u_char); u_char inb(u_int port) { u_char data; /* * We use %%dx and not %1 here because i/o is done at %dx and not at * %edx, while gcc generates inferior code (movw instead of movl) * if we tell it to load (u_short) port. */ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); return (data); } void outb(u_int port, u_char data) { u_char al; /* * Use an unnecessary assignment to help gcc's register allocator. * This make a large difference for gcc-1.40 and a tiny difference * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for * best results. gcc-2.6.0 can't handle this. */ al = data; __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); } #endif /* DDB */ Index: head/sys/pc98/pc98/machdep.c =================================================================== --- head/sys/pc98/pc98/machdep.c (revision 82392) +++ head/sys/pc98/pc98/machdep.c (revision 82393) @@ -1,2598 +1,2600 @@ /*- * Copyright (c) 1992 Terrence R. Lambert. * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * William Jolitz. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 * $FreeBSD$ */ #include "opt_atalk.h" #include "opt_compat.h" #include "opt_cpu.h" #include "opt_ddb.h" #include "opt_inet.h" #include "opt_ipx.h" #include "opt_isa.h" #include "opt_maxmem.h" #include "opt_msgbuf.h" #include "opt_npx.h" #include "opt_perfmon.h" #include "opt_upages.h" /* #include "opt_userconfig.h" */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* pcb.h included via sys/user.h */ #include #ifdef PERFMON #include #endif #ifdef SMP #include #endif #include #include #ifdef PC98 #include #include #else #include #endif #include #include #include extern void init386 __P((int first)); extern void dblfault_handler __P((void)); extern void printcpuinfo(void); /* XXX header file */ extern void earlysetcpuclass(void); /* same header file */ extern void finishidentcpu(void); extern void panicifcpuunsupported(void); extern void initializecpu(void); #define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) #define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) static void cpu_startup __P((void *)); #ifdef CPU_ENABLE_SSE static void set_fpregs_xmm __P((struct save87 *, struct savexmm *)); static void fill_fpregs_xmm __P((struct savexmm *, struct save87 *)); #endif /* CPU_ENABLE_SSE */ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL) #ifdef PC98 int need_pre_dma_flush; /* If 1, use wbinvd befor DMA transfer. */ int need_post_dma_flush; /* If 1, use invd after DMA transfer. */ #endif int _udatasel, _ucodesel; u_int atdevbase; #if defined(SWTCH_OPTIM_STATS) extern int swtch_optim_stats; SYSCTL_INT(_debug, OID_AUTO, swtch_optim_stats, CTLFLAG_RD, &swtch_optim_stats, 0, ""); SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count, CTLFLAG_RD, &tlb_flush_count, 0, ""); #endif #ifdef PC98 static int ispc98 = 1; #else static int ispc98 = 0; #endif SYSCTL_INT(_machdep, OID_AUTO, ispc98, CTLFLAG_RD, &ispc98, 0, ""); int physmem = 0; int cold = 1; #ifdef COMPAT_43 static void osendsig __P((sig_t catcher, int sig, sigset_t *mask, u_long code)); #endif static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem), req); return (error); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "IU", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, ctob(physmem - cnt.v_wire_count), req); return (error); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "IU", ""); static int sysctl_hw_availpages(SYSCTL_HANDLER_ARGS) { int error = sysctl_handle_int(oidp, 0, i386_btop(avail_end - avail_start), req); return (error); } SYSCTL_PROC(_hw, OID_AUTO, availpages, CTLTYPE_INT|CTLFLAG_RD, 0, 0, sysctl_hw_availpages, "I", ""); int Maxmem = 0; #ifdef PC98 int Maxmem_under16M = 0; #endif long dumplo; vm_offset_t phys_avail[10]; /* must be 2 less so 0 0 can signal end of chunks */ #define PHYS_AVAIL_ARRAY_END ((sizeof(phys_avail) / sizeof(vm_offset_t)) - 2) struct kva_md_info kmi; static struct trapframe proc0_tf; #ifndef SMP static struct globaldata __globaldata; #endif struct mtx sched_lock; struct mtx Giant; static void cpu_startup(dummy) void *dummy; { /* * Good {morning,afternoon,evening,night}. */ earlysetcpuclass(); startrtclock(); printcpuinfo(); panicifcpuunsupported(); #ifdef PERFMON perfmon_init(); #endif printf("real memory = %u (%uK bytes)\n", ptoa(Maxmem), ptoa(Maxmem) / 1024); /* * Display any holes after the first chunk of extended memory. */ if (bootverbose) { int indx; printf("Physical memory chunk(s):\n"); for (indx = 0; phys_avail[indx + 1] != 0; indx += 2) { unsigned int size1; size1 = phys_avail[indx + 1] - phys_avail[indx]; printf("0x%08x - 0x%08x, %u bytes (%u pages)\n", phys_avail[indx], phys_avail[indx + 1] - 1, size1, size1 / PAGE_SIZE); } } vm_ksubmap_init(&kmi); #if 0 /* * Calculate callout wheel size */ for (callwheelsize = 1, callwheelbits = 0; callwheelsize < ncallout; callwheelsize <<= 1, ++callwheelbits) ; callwheelmask = callwheelsize - 1; /* * Allocate space for system data structures. * The first available kernel virtual address is in "v". * As pages of kernel virtual memory are allocated, "v" is incremented. * As pages of memory are allocated and cleared, * "firstaddr" is incremented. * An index into the kernel page table corresponding to the * virtual memory address maintained in "v" is kept in "mapaddr". */ /* * Make two passes. The first pass calculates how much memory is * needed and allocates it. The second pass assigns virtual * addresses to the various data structures. */ firstaddr = 0; again: v = (caddr_t)firstaddr; #define valloc(name, type, num) \ (name) = (type *)v; v = (caddr_t)((name)+(num)) #define valloclim(name, type, num, lim) \ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num))) valloc(callout, struct callout, ncallout); valloc(callwheel, struct callout_tailq, callwheelsize); /* * Discount the physical memory larger than the size of kernel_map * to avoid eating up all of KVA space. */ if (kernel_map->first_free == NULL) { printf("Warning: no free entries in kernel_map.\n"); physmem_est = physmem; } else { physmem_est = min(physmem, btoc(kernel_map->max_offset - kernel_map->min_offset)); } /* * The nominal buffer size (and minimum KVA allocation) is BKVASIZE. * For the first 64MB of ram nominally allocate sufficient buffers to * cover 1/4 of our ram. Beyond the first 64MB allocate additional * buffers to cover 1/20 of our ram over 64MB. When auto-sizing * the buffer cache we limit the eventual kva reservation to * maxbcache bytes. * * factor represents the 1/4 x ram conversion. */ if (nbuf == 0) { int factor = 4 * BKVASIZE / PAGE_SIZE; nbuf = 50; if (physmem_est > 1024) nbuf += min((physmem_est - 1024) / factor, 16384 / factor); if (physmem_est > 16384) nbuf += (physmem_est - 16384) * 2 / (factor * 5); if (maxbcache && nbuf > maxbcache / BKVASIZE) nbuf = maxbcache / BKVASIZE; } /* * Do not allow the buffer_map to be more then 1/2 the size of the * kernel_map. */ if (nbuf > (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2)) { nbuf = (kernel_map->max_offset - kernel_map->min_offset) / (BKVASIZE * 2); printf("Warning: nbufs capped at %d\n", nbuf); } nswbuf = max(min(nbuf/4, 256), 16); valloc(swbuf, struct buf, nswbuf); valloc(buf, struct buf, nbuf); v = bufhashinit(v); /* * End of first pass, size has been calculated so allocate memory */ if (firstaddr == 0) { size = (vm_size_t)(v - firstaddr); firstaddr = (int)kmem_alloc(kernel_map, round_page(size)); if (firstaddr == 0) panic("startup: no room for tables"); goto again; } /* * End of second pass, addresses have been assigned */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); clean_map = kmem_suballoc(kernel_map, &clean_sva, &clean_eva, (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size); buffer_map = kmem_suballoc(clean_map, &buffer_sva, &buffer_eva, (nbuf*BKVASIZE)); buffer_map->system_map = 1; pager_map = kmem_suballoc(clean_map, &pager_sva, &pager_eva, (nswbuf*MAXPHYS) + pager_map_size); pager_map->system_map = 1; exec_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (16*(ARG_MAX+(PAGE_SIZE*3)))); /* * XXX: Mbuf system machine-specific initializations should * go here, if anywhere. */ /* * Initialize callouts */ SLIST_INIT(&callfree); for (i = 0; i < ncallout; i++) { callout_init(&callout[i], 0); callout[i].c_flags = CALLOUT_LOCAL_ALLOC; SLIST_INSERT_HEAD(&callfree, &callout[i], c_links.sle); } for (i = 0; i < callwheelsize; i++) { TAILQ_INIT(&callwheel[i]); } mtx_init(&callout_lock, "callout", MTX_SPIN | MTX_RECURSE); #endif #if defined(USERCONFIG) userconfig(); cninit(); /* the preferred console may have changed */ #endif printf("avail memory = %u (%uK bytes)\n", ptoa(cnt.v_free_count), ptoa(cnt.v_free_count) / 1024); /* * Set up buffers, so they can be used to read disk labels. */ bufinit(); vm_pager_bufferinit(); globaldata_register(GLOBALDATA); #ifndef SMP /* For SMP, we delay the cpu_setregs() until after SMP startup. */ cpu_setregs(); #endif } /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ #ifdef COMPAT_43 static void osendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct osigframe sf; struct osigframe *fp; struct proc *p; struct sigacts *psp; struct trapframe *regs; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct osigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct osigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else fp = (struct osigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *fp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)fp) == 0 || !useracc((caddr_t)fp, sizeof(*fp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; } else { /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* Save most if not all of trap frame. */ sf.sf_siginfo.si_sc.sc_eax = regs->tf_eax; sf.sf_siginfo.si_sc.sc_ebx = regs->tf_ebx; sf.sf_siginfo.si_sc.sc_ecx = regs->tf_ecx; sf.sf_siginfo.si_sc.sc_edx = regs->tf_edx; sf.sf_siginfo.si_sc.sc_esi = regs->tf_esi; sf.sf_siginfo.si_sc.sc_edi = regs->tf_edi; sf.sf_siginfo.si_sc.sc_cs = regs->tf_cs; sf.sf_siginfo.si_sc.sc_ds = regs->tf_ds; sf.sf_siginfo.si_sc.sc_ss = regs->tf_ss; sf.sf_siginfo.si_sc.sc_es = regs->tf_es; sf.sf_siginfo.si_sc.sc_fs = regs->tf_fs; sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; /* Build the signal context to be used by osigreturn(). */ sf.sf_siginfo.si_sc.sc_onstack = (oonstack) ? 1 : 0; SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; sf.sf_siginfo.si_sc.sc_ps = regs->tf_eflags; sf.sf_siginfo.si_sc.sc_trapno = regs->tf_trapno; sf.sf_siginfo.si_sc.sc_err = regs->tf_err; /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { /* XXX confusing names: `tf' isn't a trapframe; `regs' is. */ struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_siginfo.si_sc.sc_gs = tf->tf_vm86_gs; sf.sf_siginfo.si_sc.sc_fs = tf->tf_vm86_fs; sf.sf_siginfo.si_sc.sc_es = tf->tf_vm86_es; sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* See sendsig() for comments. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, fp, sizeof(*fp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)fp; regs->tf_eip = PS_STRINGS - szosigcode; regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; load_gs(_udatasel); regs->tf_ss = _udatasel; } #endif void sendsig(catcher, sig, mask, code) sig_t catcher; int sig; sigset_t *mask; u_long code; { struct sigframe sf; struct proc *p; struct sigacts *psp; struct trapframe *regs; struct sigframe *sfp; int oonstack; p = curproc; PROC_LOCK(p); psp = p->p_sigacts; #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { PROC_UNLOCK(p); osendsig(catcher, sig, mask, code); return; } #endif regs = p->p_frame; oonstack = sigonstack(regs->tf_esp); /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack = p->p_sigstk; sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_gs = rgs(); bcopy(regs, &sf.sf_uc.uc_mcontext.mc_fs, sizeof(*regs)); /* Allocate and validate space for the signal handler context. */ if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe *)(p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct sigframe)); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) p->p_sigstk.ss_flags |= SS_ONSTACK; #endif } else sfp = (struct sigframe *)regs->tf_esp - 1; PROC_UNLOCK(p); /* * grow_stack() will return 0 if *sfp does not fit inside the stack * and the stack can not be grown. * useracc() will return FALSE if access is denied. */ if (grow_stack(p, (int)sfp) == 0 || !useracc((caddr_t)sfp, sizeof(*sfp), VM_PROT_WRITE)) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG printf("process %d has trashed its stack\n", p->p_pid); #endif PROC_LOCK(p); SIGACTION(p, SIGILL) = SIG_DFL; SIGDELSET(p->p_sigignore, SIGILL); SIGDELSET(p->p_sigcatch, SIGILL); SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); PROC_UNLOCK(p); return; } /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_ucontext = (register_t)&sfp->sf_uc; PROC_LOCK(p); if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_siginfo = (register_t)&sfp->sf_si; sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; /* Fill siginfo structure. */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = code; sf.sf_si.si_addr = (void *)regs->tf_err; } else { /* Old FreeBSD-style arguments. */ sf.sf_siginfo = code; sf.sf_addr = regs->tf_err; sf.sf_ahu.sf_handler = catcher; } PROC_UNLOCK(p); /* * If we're a vm86 process, we want to save the segment registers. * We also change eflags to be our emulated eflags, not the actual * eflags. */ if (regs->tf_eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs; sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es; sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) sf.sf_uc.uc_mcontext.mc_eflags = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 * mode. It may be set here if we deliver a signal before * getting to vm86 mode, so turn it off. * * Clear PSL_NT to inhibit T_TSSFLT faults on return from * syscalls made by the signal handler. This just avoids * wasting time for our lazy fixup of such faults. PSL_NT * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); } /* Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(p, SIGILL); /* NOTREACHED */ } regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_ss = _udatasel; } /* * System call to cleanup state after a signal * has been taken. Reset signal mask and * stack state from context left by sendsig (above). * Return to previous pc and psl as specified by * context left by sendsig. Check carefully to * make sure that the user has not modified the * state to gain improper privileges. */ #ifdef COMPAT_43 int osigreturn(p, uap) struct proc *p; struct osigreturn_args /* { struct osigcontext *sigcntxp; } */ *uap; { struct trapframe *regs; struct osigcontext *scp; int eflags; regs = p->p_frame; scp = uap->sigcntxp; if (!useracc((caddr_t)scp, sizeof(*scp), VM_PROT_READ)) return (EFAULT); eflags = scp->sc_ps; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } tf->tf_vm86_ds = scp->sc_ds; tf->tf_vm86_es = scp->sc_es; tf->tf_vm86_fs = scp->sc_fs; tf->tf_vm86_gs = scp->sc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ if (!CS_SECURE(scp->sc_cs)) { trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } regs->tf_ds = scp->sc_ds; regs->tf_es = scp->sc_es; regs->tf_fs = scp->sc_fs; } /* Restore remaining registers. */ regs->tf_eax = scp->sc_eax; regs->tf_ebx = scp->sc_ebx; regs->tf_ecx = scp->sc_ecx; regs->tf_edx = scp->sc_edx; regs->tf_esi = scp->sc_esi; regs->tf_edi = scp->sc_edi; regs->tf_cs = scp->sc_cs; regs->tf_ss = scp->sc_ss; regs->tf_isp = scp->sc_isp; PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (scp->sc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif SIGSETOLD(p->p_sigmask, scp->sc_mask); SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; regs->tf_eflags = eflags; return (EJUSTRETURN); } #endif int sigreturn(p, uap) struct proc *p; struct sigreturn_args /* { ucontext_t *sigcntxp; } */ *uap; { struct trapframe *regs; ucontext_t *ucp; int cs, eflags; ucp = uap->sigcntxp; #ifdef COMPAT_43 if (!useracc((caddr_t)ucp, sizeof(struct osigcontext), VM_PROT_READ)) return (EFAULT); if (((struct osigcontext *)ucp)->sc_trapno == 0x01d516) return (osigreturn(p, (struct osigreturn_args *)uap)); /* * Since ucp is not an osigcontext but a ucontext_t, we have to * check again if all of it is accessible. A ucontext_t is * much larger, so instead of just checking for the pointer * being valid for the size of an osigcontext, now check for * it being valid for a whole, new-style ucontext_t. */ #endif if (!useracc((caddr_t)ucp, sizeof(*ucp), VM_PROT_READ)) return (EFAULT); regs = p->p_frame; eflags = ucp->uc_mcontext.mc_eflags; if (eflags & PSL_VM) { struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; struct vm86_kernel *vm86; /* * if pcb_ext == 0 or vm86_inited == 0, the user hasn't * set up the vm86 area, and we can't enter vm86 mode. */ if (p->p_addr->u_pcb.pcb_ext == 0) return (EINVAL); vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; if (vm86->vm86_inited == 0) return (EINVAL); /* Go back to user mode if both flags are set. */ if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) trapsignal(p, SIGBUS, 0); if (vm86->vm86_has_vme) { eflags = (tf->tf_eflags & ~VME_USERCHANGE) | (eflags & VME_USERCHANGE) | PSL_VM; } else { vm86->vm86_eflags = eflags; /* save VIF, VIP */ eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; } bcopy(&ucp->uc_mcontext.mc_fs, tf, sizeof(struct trapframe)); tf->tf_eflags = eflags; tf->tf_vm86_ds = tf->tf_ds; tf->tf_vm86_es = tf->tf_es; tf->tf_vm86_fs = tf->tf_fs; tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; tf->tf_ds = _udatasel; tf->tf_es = _udatasel; tf->tf_fs = _udatasel; } else { /* * Don't allow users to change privileged or reserved flags. */ /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers * should sometimes set it there too. tf_eflags is kept in * the signal context during signal handling and there is no * other place to remember it, so the PSL_RF bit may be * corrupted by the signal handler without us knowing. * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { printf("sigreturn: eflags = 0x%x\n", eflags); return (EINVAL); } /* * Don't allow users to load a valid privileged %cs. Let the * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ cs = ucp->uc_mcontext.mc_cs; if (!CS_SECURE(cs)) { printf("sigreturn: cs = 0x%x\n", cs); trapsignal(p, SIGBUS, T_PROTFLT); return (EINVAL); } bcopy(&ucp->uc_mcontext.mc_fs, regs, sizeof(*regs)); } PROC_LOCK(p); #if defined(COMPAT_43) || defined(COMPAT_SUNOS) if (ucp->uc_mcontext.mc_onstack & 1) p->p_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigstk.ss_flags &= ~SS_ONSTACK; #endif p->p_sigmask = ucp->uc_sigmask; SIG_CANTMASK(p->p_sigmask); PROC_UNLOCK(p); return (EJUSTRETURN); } /* * Machine dependent boot() routine * * I haven't seen anything to put here yet * Possibly some stuff might be grafted back here from boot() */ void cpu_boot(int howto) { } /* * Shutdown the CPU as much as possible */ void cpu_halt(void) { for (;;) __asm__ ("hlt"); } /* * Hook to idle the CPU when possible. This currently only works in * the !SMP case, as there is no clean way to ensure that a CPU will be * woken when there is work available for it. */ static int cpu_idle_hlt = 1; SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, &cpu_idle_hlt, 0, "Idle loop HLT enable"); /* * Note that we have to be careful here to avoid a race between checking * procrunnable() and actually halting. If we don't do this, we may waste * the time between calling hlt and the next interrupt even though there * is a runnable process. */ void cpu_idle(void) { #ifndef SMP if (cpu_idle_hlt) { disable_intr(); if (procrunnable()) enable_intr(); else { enable_intr(); __asm __volatile("hlt"); } } #endif } /* * Clear registers on exec */ void setregs(p, entry, stack, ps_strings) struct proc *p; u_long entry; u_long stack; u_long ps_strings; { struct trapframe *regs = p->p_frame; struct pcb *pcb = &p->p_addr->u_pcb; if (pcb->pcb_ldt) user_ldt_free(pcb); bzero((char *)regs, sizeof(struct trapframe)); regs->tf_eip = entry; regs->tf_esp = stack; regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T); regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _udatasel; regs->tf_cs = _ucodesel; /* PS_STRINGS value for BSD/OS binaries. It is 0 for non-BSD/OS. */ regs->tf_ebx = ps_strings; /* reset %gs as well */ if (pcb == PCPU_GET(curpcb)) load_gs(_udatasel); else pcb->pcb_gs = _udatasel; /* * Reset the hardware debug registers if they were in use. * They won't have any meaning for the newly exec'd process. */ if (pcb->pcb_flags & PCB_DBREGS) { pcb->pcb_dr0 = 0; pcb->pcb_dr1 = 0; pcb->pcb_dr2 = 0; pcb->pcb_dr3 = 0; pcb->pcb_dr6 = 0; pcb->pcb_dr7 = 0; if (pcb == PCPU_GET(curpcb)) { /* * Clear the debug registers on the running * CPU, otherwise they will end up affecting * the next process we switch to. */ reset_dbregs(); } pcb->pcb_flags &= ~PCB_DBREGS; } /* * Initialize the math emulator (if any) for the current process. * Actually, just clear the bit that says that the emulator has * been initialized. Initialization is delayed until the process * traps to the emulator (if it is done at all) mainly because * emulators don't provide an entry point for initialization. */ p->p_addr->u_pcb.pcb_flags &= ~FP_SOFTFP; /* * Arrange to trap the next npx or `fwait' instruction (see npx.c * for why fwait must be trapped at least if there is an npx or an * emulator). This is mainly to handle the case where npx0 is not * configured, since the npx routines normally set up the trap * otherwise. It should be done only at boot time, but doing it * here allows modifying `npx_exists' for testing the emulator on * systems with an npx. */ load_cr0(rcr0() | CR0_MP | CR0_TS); #ifdef DEV_NPX /* Initialize the npx (if any) for the current process. */ npxinit(__INITIAL_NPXCW__); #endif /* * XXX - Linux emulator * Make sure sure edx is 0x0 on entry. Linux binaries depend * on it. */ p->p_retval[1] = 0; } void cpu_setregs(void) { unsigned int cr0; cr0 = rcr0(); cr0 |= CR0_NE; /* Done by npxinit() */ cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */ #ifndef I386_CPU cr0 |= CR0_WP | CR0_AM; #endif load_cr0(cr0); load_gs(_udatasel); } static int sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS) { int error; error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); if (!error && req->newptr) resettodr(); return (error); } SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW, &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", ""); SYSCTL_INT(_machdep, CPU_DISRTCSET, disable_rtc_set, CTLFLAG_RW, &disable_rtc_set, 0, ""); SYSCTL_STRUCT(_machdep, CPU_BOOTINFO, bootinfo, CTLFLAG_RD, &bootinfo, bootinfo, ""); SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, CTLFLAG_RW, &wall_cmos_clock, 0, ""); /* * Initialize 386 and configure to run kernel */ /* * Initialize segments & interrupt table */ int _default_ldt; union descriptor gdt[NGDT * MAXCPU]; /* global descriptor table */ static struct gate_descriptor idt0[NIDT]; struct gate_descriptor *idt = &idt0[0]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ #ifdef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif int private_tss; /* flag indicating private tss */ #if defined(I586_CPU) && !defined(NO_F00F_HACK) extern int has_f00f_bug; #endif static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; extern struct user *proc0paddr; /* software prototypes -- in more palatable form */ struct soft_segment_descriptor gdt_segs[] = { /* GNULL_SEL 0 Null Descriptor */ { 0x0, /* segment base address */ 0x0, /* length */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GCODE_SEL 1 Code Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GDATA_SEL 2 Data Descriptor for kernel */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPRIV_SEL 3 SMP Per-Processor Private Data Descriptor */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPROC0_SEL 4 Proc 0 Tss Descriptor */ { 0x0, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GLDT_SEL 5 LDT Descriptor */ { (int) ldt, /* segment base address */ sizeof(ldt)-1, /* length - all address space */ SDT_SYSLDT, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GUSERLDT_SEL 6 User LDT Descriptor per process */ { (int) ldt, /* segment base address */ (512 * sizeof(union descriptor)-1), /* length */ SDT_SYSLDT, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GTGATE_SEL 7 Null Descriptor - Placeholder */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSLOWMEM_SEL 8 BIOS access to realmode segment 0x40, must be #8 in GDT */ { 0x400, /* segment base address */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GPANIC_SEL 9 Panic Tss Descriptor */ { (int) &dblfault_tss, /* segment base address */ sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE32_SEL 10 BIOS 32-bit interface (32bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSCODE16_SEL 11 BIOS 32-bit interface (16bit Code) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSDATA_SEL 12 BIOS 32-bit interface (Data) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSUTIL_SEL 13 BIOS 16-bit interface (Utility) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* GBIOSARGS_SEL 14 BIOS 16-bit interface (Arguments) */ { 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Code Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMERA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, /* Null Descriptor - overwritten by call gate */ { 0x0, /* segment base address */ 0x0, /* length - all address space */ 0, /* segment type */ 0, /* segment descriptor priority level */ 0, /* segment descriptor present */ 0, 0, 0, /* default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* Data Descriptor for user */ { 0x0, /* segment base address */ 0xfffff, /* length - all address space */ SDT_MEMRWA, /* segment type */ SEL_UPL, /* segment descriptor priority level */ 1, /* segment descriptor present */ 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, }; void setidt(idx, func, typ, dpl, selec) int idx; inthand_t *func; int typ; int dpl; int selec; { struct gate_descriptor *ip; ip = idt + idx; ip->gd_looffset = (int)func; ip->gd_selector = selec; ip->gd_stkcpy = 0; ip->gd_xx = 0; ip->gd_type = typ; ip->gd_dpl = dpl; ip->gd_p = 1; ip->gd_hioffset = ((int)func)>>16 ; } #define IDTVEC(name) __CONCAT(X,name) extern inthand_t IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl), IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm), IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align), IDTVEC(xmm), IDTVEC(lcall_syscall), IDTVEC(int0x80_syscall); void sdtossd(sd, ssd) struct segment_descriptor *sd; struct soft_segment_descriptor *ssd; { ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; ssd->ssd_type = sd->sd_type; ssd->ssd_dpl = sd->sd_dpl; ssd->ssd_p = sd->sd_p; ssd->ssd_def32 = sd->sd_def32; ssd->ssd_gran = sd->sd_gran; } #define PHYSMAP_SIZE (2 * 8) /* * Populate the (physmap) array with base/bound pairs describing the * available physical memory in the system, then test this memory and * build the phys_avail array describing the actually-available memory. * * If we cannot accurately determine the physical memory map, then use * value from the 0xE801 call, and failing that, the RTC. * * Total memory size may be set by the kernel environment variable * hw.physmem or the compile-time define MAXMEM. */ static void getmemsize(int first) { int i, physmap_idx, pa_indx; u_int basemem, extmem; #ifdef PC98 int pg_n; u_int under16; #else struct vm86frame vmf; struct vm86context vmc; #endif vm_offset_t pa, physmap[PHYSMAP_SIZE]; pt_entry_t pte; const char *cp; #ifndef PC98 struct bios_smap *smap; #endif #ifdef PC98 /* XXX - some of EPSON machines can't use PG_N */ pg_n = PG_N; if (pc98_machine_type & M_EPSON_PC98) { switch (epson_machine_id) { #ifdef WB_CACHE default: #endif case 0x34: /* PC-486HX */ case 0x35: /* PC-486HG */ case 0x3B: /* PC-486HA */ pg_n = 0; break; } } #else bzero(&vmf, sizeof(struct vm86frame)); #endif bzero(physmap, sizeof(physmap)); /* * Perform "base memory" related probes & setup */ #ifdef PC98 under16 = pc98_getmemsize(&basemem, &extmem); #else vm86_intcall(0x12, &vmf); basemem = vmf.vmf_ax; #endif if (basemem > 640) { printf("Preposterous BIOS basemem of %uK, truncating to 640K\n", basemem); basemem = 640; } /* * XXX if biosbasemem is now < 640, there is a `hole' * between the end of base memory and the start of * ISA memory. The hole may be empty or it may * contain BIOS code or data. Map it read/write so * that the BIOS can write to it. (Memory from 0 to * the physical end of the kernel is mapped read-only * to begin with and then parts of it are remapped. * The parts that aren't remapped form holes that * remain read-only and are unused by the kernel. * The base memory area is below the physical end of * the kernel and right now forms a read-only hole. * The part of it from PAGE_SIZE to * (trunc_page(biosbasemem * 1024) - 1) will be * remapped and used by the kernel later.) * * This code is similar to the code used in * pmap_mapdev, but since no memory needs to be * allocated we simply change the mapping. */ for (pa = trunc_page(basemem * 1024); pa < ISA_HOLE_START; pa += PAGE_SIZE) { pte = (pt_entry_t)vtopte(pa + KERNBASE); *pte = pa | PG_RW | PG_V; } /* * if basemem != 640, map pages r/w into vm86 page table so * that the bios can scribble on it. */ pte = (pt_entry_t)vm86paddr; for (i = basemem / 4; i < 160; i++) pte[i] = (i << PAGE_SHIFT) | PG_V | PG_RW | PG_U; #ifndef PC98 /* * map page 1 R/W into the kernel page table so we can use it * as a buffer. The kernel will unmap this page later. */ pte = (pt_entry_t)vtopte(KERNBASE + (1 << PAGE_SHIFT)); *pte = (1 << PAGE_SHIFT) | PG_RW | PG_V; /* * get memory map with INT 15:E820 */ vmc.npages = 0; smap = (void *)vm86_addpage(&vmc, 1, KERNBASE + (1 << PAGE_SHIFT)); vm86_getptr(&vmc, (vm_offset_t)smap, &vmf.vmf_es, &vmf.vmf_di); physmap_idx = 0; vmf.vmf_ebx = 0; do { vmf.vmf_eax = 0xE820; vmf.vmf_edx = SMAP_SIG; vmf.vmf_ecx = sizeof(struct bios_smap); i = vm86_datacall(0x15, &vmf, &vmc); if (i || vmf.vmf_eax != SMAP_SIG) break; if (boothowto & RB_VERBOSE) printf("SMAP type=%02x base=%08x %08x len=%08x %08x\n", smap->type, *(u_int32_t *)((char *)&smap->base + 4), (u_int32_t)smap->base, *(u_int32_t *)((char *)&smap->length + 4), (u_int32_t)smap->length); if (smap->type != 0x01) goto next_run; if (smap->length == 0) goto next_run; if (smap->base >= 0xffffffff) { printf("%uK of memory above 4GB ignored\n", (u_int)(smap->length / 1024)); goto next_run; } for (i = 0; i <= physmap_idx; i += 2) { if (smap->base < physmap[i + 1]) { if (boothowto & RB_VERBOSE) printf( "Overlapping or non-montonic memory region, ignoring second region\n"); goto next_run; } } if (smap->base == physmap[physmap_idx + 1]) { physmap[physmap_idx + 1] += smap->length; goto next_run; } physmap_idx += 2; if (physmap_idx == PHYSMAP_SIZE) { printf( "Too many segments in the physical address map, giving up\n"); break; } physmap[physmap_idx] = smap->base; physmap[physmap_idx + 1] = smap->base + smap->length; next_run: } while (vmf.vmf_ebx != 0); if (physmap[1] != 0) goto physmap_done; /* * If we failed above, try memory map with INT 15:E801 */ vmf.vmf_ax = 0xE801; if (vm86_intcall(0x15, &vmf) == 0) { extmem = vmf.vmf_cx + vmf.vmf_dx * 64; } else { #if 0 vmf.vmf_ah = 0x88; vm86_intcall(0x15, &vmf); extmem = vmf.vmf_ax; #else /* * Prefer the RTC value for extended memory. */ extmem = rtcin(RTC_EXTLO) + (rtcin(RTC_EXTHI) << 8); #endif } /* * Special hack for chipsets that still remap the 384k hole when * there's 16MB of memory - this really confuses people that * are trying to use bus mastering ISA controllers with the * "16MB limit"; they only have 16MB, but the remapping puts * them beyond the limit. * * If extended memory is between 15-16MB (16-17MB phys address range), * chop it to 15MB. */ if ((extmem > 15 * 1024) && (extmem < 16 * 1024)) extmem = 15 * 1024; #endif physmap[0] = 0; physmap[1] = basemem * 1024; physmap_idx = 2; physmap[physmap_idx] = 0x100000; physmap[physmap_idx + 1] = physmap[physmap_idx] + extmem * 1024; #ifdef PC98 if ((under16 != 16 * 1024) && (extmem > 15 * 1024)) { /* 15M - 16M region is cut off, so need to divide chunk */ physmap[physmap_idx + 1] = under16 * 1024; physmap_idx += 2; physmap[physmap_idx] = 0x1000000; physmap[physmap_idx + 1] = physmap[2] + extmem * 1024; } #else physmap_done: #endif /* * Now, physmap contains a map of physical memory. */ #ifdef SMP /* make hole for AP bootstrap code */ physmap[1] = mp_bootaddress(physmap[1] / 1024); /* look for the MP hardware - needed for apic addresses */ i386_mp_probe(); #endif /* * Maxmem isn't the "maximum memory", it's one larger than the * highest page of the physical address space. It should be * called something like "Maxphyspage". We may adjust this * based on ``hw.physmem'' and the results of the memory test. */ Maxmem = atop(physmap[physmap_idx + 1]); #ifdef MAXMEM Maxmem = MAXMEM / 4; #endif /* * hw.physmem is a size in bytes; we also allow k, m, and g suffixes * for the appropriate modifiers. This overrides MAXMEM. */ if ((cp = getenv("hw.physmem")) != NULL) { u_int64_t AllowMem, sanity; char *ep; sanity = AllowMem = strtouq(cp, &ep, 0); if ((ep != cp) && (*ep != 0)) { switch(*ep) { case 'g': case 'G': AllowMem <<= 10; case 'm': case 'M': AllowMem <<= 10; case 'k': case 'K': AllowMem <<= 10; break; default: AllowMem = sanity = 0; } if (AllowMem < sanity) AllowMem = 0; } if (AllowMem == 0) printf("Ignoring invalid memory size of '%s'\n", cp); else Maxmem = atop(AllowMem); } if (atop(physmap[physmap_idx + 1]) != Maxmem && (boothowto & RB_VERBOSE)) printf("Physical memory use set to %uK\n", Maxmem * 4); /* * If Maxmem has been increased beyond what the system has detected, * extend the last memory segment to the new limit. */ if (atop(physmap[physmap_idx + 1]) < Maxmem) physmap[physmap_idx + 1] = ptoa(Maxmem); /* call pmap initialization to make new kernel address space */ pmap_bootstrap(first, 0); /* * Size up each available chunk of physical memory. */ physmap[0] = PAGE_SIZE; /* mask off page 0 */ pa_indx = 0; phys_avail[pa_indx++] = physmap[0]; phys_avail[pa_indx] = physmap[0]; #if 0 pte = (pt_entry_t)vtopte(KERNBASE); #else pte = (pt_entry_t)CMAP1; #endif /* * physmap is in bytes, so when converting to page boundaries, * round up the start address and round down the end address. */ for (i = 0; i <= physmap_idx; i += 2) { vm_offset_t end; end = ptoa(Maxmem); if (physmap[i + 1] < end) end = trunc_page(physmap[i + 1]); for (pa = round_page(physmap[i]); pa < end; pa += PAGE_SIZE) { int tmp, page_bad; #if 0 int *ptr = 0; #else int *ptr = (int *)CADDR1; #endif /* * block out kernel memory as not available. */ if (pa >= 0x100000 && pa < first) continue; page_bad = FALSE; /* * map page into kernel: valid, read/write,non-cacheable */ #ifdef PC98 *pte = pa | PG_V | PG_RW | pg_n; #else *pte = pa | PG_V | PG_RW | PG_N; #endif invltlb(); tmp = *(int *)ptr; /* * Test for alternating 1's and 0's */ *(volatile int *)ptr = 0xaaaaaaaa; if (*(volatile int *)ptr != 0xaaaaaaaa) { page_bad = TRUE; } /* * Test for alternating 0's and 1's */ *(volatile int *)ptr = 0x55555555; if (*(volatile int *)ptr != 0x55555555) { page_bad = TRUE; } /* * Test for all 1's */ *(volatile int *)ptr = 0xffffffff; if (*(volatile int *)ptr != 0xffffffff) { page_bad = TRUE; } /* * Test for all 0's */ *(volatile int *)ptr = 0x0; if (*(volatile int *)ptr != 0x0) { page_bad = TRUE; } /* * Restore original value. */ *(int *)ptr = tmp; /* * Adjust array of valid/good pages. */ if (page_bad == TRUE) { continue; } /* * If this good page is a continuation of the * previous set of good pages, then just increase * the end pointer. Otherwise start a new chunk. * Note that "end" points one higher than end, * making the range >= start and < end. * If we're also doing a speculative memory * test and we at or past the end, bump up Maxmem * so that we keep going. The first bad page * will terminate the loop. */ if (phys_avail[pa_indx] == pa) { phys_avail[pa_indx] += PAGE_SIZE; } else { pa_indx++; if (pa_indx == PHYS_AVAIL_ARRAY_END) { printf( "Too many holes in the physical address space, giving up\n"); pa_indx--; break; } phys_avail[pa_indx++] = pa; /* start */ phys_avail[pa_indx] = pa + PAGE_SIZE; /* end */ } physmem++; } } *pte = 0; invltlb(); /* * XXX * The last chunk must contain at least one page plus the message * buffer to avoid complicating other code (message buffer address * calculation, etc.). */ while (phys_avail[pa_indx - 1] + PAGE_SIZE + round_page(MSGBUF_SIZE) >= phys_avail[pa_indx]) { physmem -= atop(phys_avail[pa_indx] - phys_avail[pa_indx - 1]); phys_avail[pa_indx--] = 0; phys_avail[pa_indx--] = 0; } Maxmem = atop(phys_avail[pa_indx]); /* Trim off space for the message buffer. */ phys_avail[pa_indx] -= round_page(MSGBUF_SIZE); avail_end = phys_avail[pa_indx]; } void init386(first) int first; { struct gate_descriptor *gdp; int gsel_tss, metadata_missing, off, x; #ifndef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; #endif proc0.p_addr = proc0paddr; atdevbase = ISA_HOLE_START + KERNBASE; #ifdef PC98 /* * Initialize DMAC */ pc98_init_dmac(); #endif metadata_missing = 0; if (bootinfo.bi_modulep) { preload_metadata = (caddr_t)bootinfo.bi_modulep + KERNBASE; preload_bootstrap_relocate(KERNBASE); } else { metadata_missing = 1; } - if (bootinfo.bi_envp) + if (envmode == 1) + kern_envp = static_env; + else if (bootinfo.bi_envp) kern_envp = (caddr_t)bootinfo.bi_envp + KERNBASE; /* Init basic tunables, hz etc */ init_param(); /* * make gdt memory segments, the code segment goes up to end of the * page with etext in it, the data segment goes to the end of * the address space */ /* * XXX text protection is temporarily (?) disabled. The limit was * i386_btop(round_page(etext)) - 1. */ gdt_segs[GCODE_SEL].ssd_limit = atop(0 - 1); gdt_segs[GDATA_SEL].ssd_limit = atop(0 - 1); #ifdef SMP gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct privatespace) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[0]; gdt_segs[GPROC0_SEL].ssd_base = (int) &SMP_prvspace[0].globaldata.gd_common_tss; SMP_prvspace[0].globaldata.gd_prvspace = &SMP_prvspace[0].globaldata; #else gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct globaldata) - 1); gdt_segs[GPRIV_SEL].ssd_base = (int) &__globaldata; gdt_segs[GPROC0_SEL].ssd_base = (int) &__globaldata.gd_common_tss; __globaldata.gd_prvspace = &__globaldata; #endif for (x = 0; x < NGDT; x++) { #ifdef BDE_DEBUGGER /* avoid overwriting db entries with APM ones */ if (x >= GAPMCODE32_SEL && x <= GAPMDATA_SEL) continue; #endif ssdtosd(&gdt_segs[x], &gdt[x].sd); } r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; r_gdt.rd_base = (int) gdt; lgdt(&r_gdt); /* setup curproc so that mutexes work */ PCPU_SET(curproc, &proc0); PCPU_SET(spinlocks, NULL); LIST_INIT(&proc0.p_contested); /* * Initialize mutexes. */ mtx_init(&Giant, "Giant", MTX_DEF | MTX_RECURSE); mtx_init(&sched_lock, "sched lock", MTX_SPIN | MTX_RECURSE); mtx_init(&proc0.p_mtx, "process lock", MTX_DEF); mtx_init(&clock_lock, "clk", MTX_SPIN | MTX_RECURSE); #ifdef SMP mtx_init(&imen_mtx, "imen", MTX_SPIN); #endif mtx_lock(&Giant); /* make ldt memory segments */ /* * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it * should be spelled ...MAX_USER... */ ldt_segs[LUCODE_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); ldt_segs[LUDATA_SEL].ssd_limit = atop(VM_MAXUSER_ADDRESS - 1); for (x = 0; x < sizeof ldt_segs / sizeof ldt_segs[0]; x++) ssdtosd(&ldt_segs[x], &ldt[x].sd); _default_ldt = GSEL(GLDT_SEL, SEL_KPL); lldt(_default_ldt); PCPU_SET(currentldt, _default_ldt); /* exceptions */ for (x = 0; x < NIDT; x++) setidt(x, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(1, &IDTVEC(dbg), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(3, &IDTVEC(bpt), SDT_SYS386IGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL , GSEL(GCODE_SEL, SEL_KPL)); setidt(8, 0, SDT_SYSTASKGT, SEL_KPL, GSEL(GPANIC_SEL, SEL_KPL)); setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(14, &IDTVEC(page), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(17, &IDTVEC(align), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(18, &IDTVEC(mchk), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(19, &IDTVEC(xmm), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(0x80, &IDTVEC(int0x80_syscall), SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL)); r_idt.rd_limit = sizeof(idt0) - 1; r_idt.rd_base = (int) idt; lidt(&r_idt); /* * Initialize the console before we print anything out. */ cninit(); if (metadata_missing) printf("WARNING: loader(8) metadata is missing!\n"); #ifdef DEV_ISA isa_defaultirq(); #endif #ifdef DDB kdb_init(); if (boothowto & RB_KDB) Debugger("Boot flags requested debugger"); #endif finishidentcpu(); /* Final stage of CPU initialization */ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); initializecpu(); /* Initialize CPU registers */ /* make an initial tss so cpu can get interrupt stack on syscall! */ PCPU_SET(common_tss.tss_esp0, (int) proc0.p_addr + UPAGES*PAGE_SIZE - 16); PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); private_tss = 0; PCPU_SET(tss_gdt, &gdt[GPROC0_SEL].sd); PCPU_SET(common_tssd, *PCPU_GET(tss_gdt)); PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); ltr(gsel_tss); dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int)&dblfault_stack[sizeof(dblfault_stack)]; dblfault_tss.tss_ss = dblfault_tss.tss_ss0 = dblfault_tss.tss_ss1 = dblfault_tss.tss_ss2 = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_cr3 = (int)IdlePTD; dblfault_tss.tss_eip = (int)dblfault_handler; dblfault_tss.tss_eflags = PSL_KERNEL; dblfault_tss.tss_ds = dblfault_tss.tss_es = dblfault_tss.tss_gs = GSEL(GDATA_SEL, SEL_KPL); dblfault_tss.tss_fs = GSEL(GPRIV_SEL, SEL_KPL); dblfault_tss.tss_cs = GSEL(GCODE_SEL, SEL_KPL); dblfault_tss.tss_ldt = GSEL(GLDT_SEL, SEL_KPL); vm86_initialize(); getmemsize(first); /* now running on new page tables, configured,and u/iom is accessible */ /* Map the message buffer. */ for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE) pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off); msgbufinit(msgbufp, MSGBUF_SIZE); /* make a call gate to reenter kernel with */ gdp = &ldt[LSYS5CALLS_SEL].gd; x = (int) &IDTVEC(lcall_syscall); gdp->gd_looffset = x; gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL); gdp->gd_stkcpy = 1; gdp->gd_type = SDT_SYS386CGT; gdp->gd_dpl = SEL_UPL; gdp->gd_p = 1; gdp->gd_hioffset = x >> 16; /* XXX does this work? */ ldt[LBSDICALLS_SEL] = ldt[LSYS5CALLS_SEL]; ldt[LSOL26CALLS_SEL] = ldt[LSYS5CALLS_SEL]; /* transfer to user mode */ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL); _udatasel = LSEL(LUDATA_SEL, SEL_UPL); /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = (int)IdlePTD; proc0.p_addr->u_pcb.pcb_ext = 0; proc0.p_frame = &proc0_tf; } #if defined(I586_CPU) && !defined(NO_F00F_HACK) static void f00f_hack(void *unused); SYSINIT(f00f_hack, SI_SUB_INTRINSIC, SI_ORDER_FIRST, f00f_hack, NULL); static void f00f_hack(void *unused) { struct gate_descriptor *new_idt; #ifndef SMP struct region_descriptor r_idt; #endif vm_offset_t tmp; if (!has_f00f_bug) return; GIANT_REQUIRED; printf("Intel Pentium detected, installing workaround for F00F bug\n"); r_idt.rd_limit = sizeof(idt0) - 1; tmp = kmem_alloc(kernel_map, PAGE_SIZE * 2); if (tmp == 0) panic("kmem_alloc returned 0"); if (((unsigned int)tmp & (PAGE_SIZE-1)) != 0) panic("kmem_alloc returned non-page-aligned memory"); /* Put the first seven entries in the lower page */ new_idt = (struct gate_descriptor*)(tmp + PAGE_SIZE - (7*8)); bcopy(idt, new_idt, sizeof(idt0)); r_idt.rd_base = (int)new_idt; lidt(&r_idt); idt = new_idt; if (vm_map_protect(kernel_map, tmp, tmp + PAGE_SIZE, VM_PROT_READ, FALSE) != KERN_SUCCESS) panic("vm_map_protect failed"); return; } #endif /* defined(I586_CPU) && !NO_F00F_HACK */ int ptrace_set_pc(p, addr) struct proc *p; unsigned long addr; { p->p_frame->tf_eip = addr; return (0); } int ptrace_single_step(p) struct proc *p; { p->p_frame->tf_eflags |= PSL_T; return (0); } int fill_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; regs->r_fs = tp->tf_fs; regs->r_es = tp->tf_es; regs->r_ds = tp->tf_ds; regs->r_edi = tp->tf_edi; regs->r_esi = tp->tf_esi; regs->r_ebp = tp->tf_ebp; regs->r_ebx = tp->tf_ebx; regs->r_edx = tp->tf_edx; regs->r_ecx = tp->tf_ecx; regs->r_eax = tp->tf_eax; regs->r_eip = tp->tf_eip; regs->r_cs = tp->tf_cs; regs->r_eflags = tp->tf_eflags; regs->r_esp = tp->tf_esp; regs->r_ss = tp->tf_ss; pcb = &p->p_addr->u_pcb; regs->r_gs = pcb->pcb_gs; return (0); } int set_regs(p, regs) struct proc *p; struct reg *regs; { struct pcb *pcb; struct trapframe *tp; tp = p->p_frame; if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; tp->tf_es = regs->r_es; tp->tf_ds = regs->r_ds; tp->tf_edi = regs->r_edi; tp->tf_esi = regs->r_esi; tp->tf_ebp = regs->r_ebp; tp->tf_ebx = regs->r_ebx; tp->tf_edx = regs->r_edx; tp->tf_ecx = regs->r_ecx; tp->tf_eax = regs->r_eax; tp->tf_eip = regs->r_eip; tp->tf_cs = regs->r_cs; tp->tf_eflags = regs->r_eflags; tp->tf_esp = regs->r_esp; tp->tf_ss = regs->r_ss; pcb = &p->p_addr->u_pcb; pcb->pcb_gs = regs->r_gs; return (0); } #ifdef CPU_ENABLE_SSE static void fill_fpregs_xmm(sv_xmm, sv_87) struct savexmm *sv_xmm; struct save87 *sv_87; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_87->en_cw = penv_xmm->en_cw; penv_87->en_sw = penv_xmm->en_sw; penv_87->en_tw = penv_xmm->en_tw; penv_87->en_fip = penv_xmm->en_fip; penv_87->en_fcs = penv_xmm->en_fcs; penv_87->en_opcode = penv_xmm->en_opcode; penv_87->en_foo = penv_xmm->en_foo; penv_87->en_fos = penv_xmm->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc; sv_87->sv_ex_sw = sv_xmm->sv_ex_sw; } static void set_fpregs_xmm(sv_87, sv_xmm) struct save87 *sv_87; struct savexmm *sv_xmm; { register struct env87 *penv_87 = &sv_87->sv_env; register struct envxmm *penv_xmm = &sv_xmm->sv_env; int i; /* FPU control/status */ penv_xmm->en_cw = penv_87->en_cw; penv_xmm->en_sw = penv_87->en_sw; penv_xmm->en_tw = penv_87->en_tw; penv_xmm->en_fip = penv_87->en_fip; penv_xmm->en_fcs = penv_87->en_fcs; penv_xmm->en_opcode = penv_87->en_opcode; penv_xmm->en_foo = penv_87->en_foo; penv_xmm->en_fos = penv_87->en_fos; /* FPU registers */ for (i = 0; i < 8; ++i) sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i]; sv_xmm->sv_ex_sw = sv_87->sv_ex_sw; } #endif /* CPU_ENABLE_SSE */ int fill_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { fill_fpregs_xmm(&p->p_addr->u_pcb.pcb_save.sv_xmm, (struct save87 *)fpregs); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(&p->p_addr->u_pcb.pcb_save.sv_87, fpregs, sizeof *fpregs); return (0); } int set_fpregs(p, fpregs) struct proc *p; struct fpreg *fpregs; { #ifdef CPU_ENABLE_SSE if (cpu_fxsr) { set_fpregs_xmm((struct save87 *)fpregs, &p->p_addr->u_pcb.pcb_save.sv_xmm); return (0); } #endif /* CPU_ENABLE_SSE */ bcopy(fpregs, &p->p_addr->u_pcb.pcb_save.sv_87, sizeof *fpregs); return (0); } int fill_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; if (p == NULL) { dbregs->dr0 = rdr0(); dbregs->dr1 = rdr1(); dbregs->dr2 = rdr2(); dbregs->dr3 = rdr3(); dbregs->dr4 = rdr4(); dbregs->dr5 = rdr5(); dbregs->dr6 = rdr6(); dbregs->dr7 = rdr7(); } else { pcb = &p->p_addr->u_pcb; dbregs->dr0 = pcb->pcb_dr0; dbregs->dr1 = pcb->pcb_dr1; dbregs->dr2 = pcb->pcb_dr2; dbregs->dr3 = pcb->pcb_dr3; dbregs->dr4 = 0; dbregs->dr5 = 0; dbregs->dr6 = pcb->pcb_dr6; dbregs->dr7 = pcb->pcb_dr7; } return (0); } int set_dbregs(p, dbregs) struct proc *p; struct dbreg *dbregs; { struct pcb *pcb; int i; u_int32_t mask1, mask2; if (p == NULL) { load_dr0(dbregs->dr0); load_dr1(dbregs->dr1); load_dr2(dbregs->dr2); load_dr3(dbregs->dr3); load_dr4(dbregs->dr4); load_dr5(dbregs->dr5); load_dr6(dbregs->dr6); load_dr7(dbregs->dr7); } else { /* * Don't let an illegal value for dr7 get set. Specifically, * check for undefined settings. Setting these bit patterns * result in undefined behaviour and can lead to an unexpected * TRCTRAP. */ for (i = 0, mask1 = 0x3<<16, mask2 = 0x2<<16; i < 8; i++, mask1 <<= 2, mask2 <<= 2) if ((dbregs->dr7 & mask1) == mask2) return (EINVAL); pcb = &p->p_addr->u_pcb; /* * Don't let a process set a breakpoint that is not within the * process's address space. If a process could do this, it * could halt the system by setting a breakpoint in the kernel * (if ddb was enabled). Thus, we need to check to make sure * that no breakpoints are being enabled for addresses outside * process's address space, unless, perhaps, we were called by * uid 0. * * XXX - what about when the watched area of the user's * address space is written into from within the kernel * ... wouldn't that still cause a breakpoint to be generated * from within kernel mode? */ if (suser(p) != 0) { if (dbregs->dr7 & 0x3) { /* dr0 is enabled */ if (dbregs->dr0 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<2)) { /* dr1 is enabled */ if (dbregs->dr1 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<4)) { /* dr2 is enabled */ if (dbregs->dr2 >= VM_MAXUSER_ADDRESS) return (EINVAL); } if (dbregs->dr7 & (0x3<<6)) { /* dr3 is enabled */ if (dbregs->dr3 >= VM_MAXUSER_ADDRESS) return (EINVAL); } } pcb->pcb_dr0 = dbregs->dr0; pcb->pcb_dr1 = dbregs->dr1; pcb->pcb_dr2 = dbregs->dr2; pcb->pcb_dr3 = dbregs->dr3; pcb->pcb_dr6 = dbregs->dr6; pcb->pcb_dr7 = dbregs->dr7; pcb->pcb_flags |= PCB_DBREGS; } return (0); } /* * Return > 0 if a hardware breakpoint has been hit, and the * breakpoint was in user space. Return 0, otherwise. */ int user_dbreg_trap(void) { u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */ u_int32_t bp; /* breakpoint bits extracted from dr6 */ int nbp; /* number of breakpoints that triggered */ caddr_t addr[4]; /* breakpoint addresses */ int i; dr7 = rdr7(); if ((dr7 & 0x000000ff) == 0) { /* * all GE and LE bits in the dr7 register are zero, * thus the trap couldn't have been caused by the * hardware debug registers */ return 0; } nbp = 0; dr6 = rdr6(); bp = dr6 & 0x0000000f; if (!bp) { /* * None of the breakpoint bits are set meaning this * trap was not caused by any of the debug registers */ return 0; } /* * at least one of the breakpoints were hit, check to see * which ones and if any of them are user space addresses */ if (bp & 0x01) { addr[nbp++] = (caddr_t)rdr0(); } if (bp & 0x02) { addr[nbp++] = (caddr_t)rdr1(); } if (bp & 0x04) { addr[nbp++] = (caddr_t)rdr2(); } if (bp & 0x08) { addr[nbp++] = (caddr_t)rdr3(); } for (i=0; i /* * Determine the size of the transfer, and make sure it is * within the boundaries of the partition. Adjust transfer * if needed, and signal errors or early completion. */ int bounds_check_with_label(struct bio *bp, struct disklabel *lp, int wlabel) { struct partition *p = lp->d_partitions + dkpart(bp->bio_dev); int labelsect = lp->d_partitions[0].p_offset; int maxsz = p->p_size, sz = (bp->bio_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; /* overwriting disk label ? */ /* XXX should also protect bootstrap in first 8K */ if (bp->bio_blkno + p->p_offset <= LABELSECTOR + labelsect && #if LABELSECTOR != 0 bp->bio_blkno + p->p_offset + sz > LABELSECTOR + labelsect && #endif (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #if defined(DOSBBSECTOR) && defined(notyet) /* overwriting master boot record? */ if (bp->bio_blkno + p->p_offset <= DOSBBSECTOR && (bp->bio_cmd == BIO_WRITE) && wlabel == 0) { bp->bio_error = EROFS; goto bad; } #endif /* beyond partition? */ if (bp->bio_blkno < 0 || bp->bio_blkno + sz > maxsz) { /* if exactly at end of disk, return an EOF */ if (bp->bio_blkno == maxsz) { bp->bio_resid = bp->bio_bcount; return(0); } /* or truncate if part of it fits */ sz = maxsz - bp->bio_blkno; if (sz <= 0) { bp->bio_error = EINVAL; goto bad; } bp->bio_bcount = sz << DEV_BSHIFT; } bp->bio_pblkno = bp->bio_blkno + p->p_offset; return(1); bad: bp->bio_flags |= BIO_ERROR; return(-1); } #ifdef DDB /* * Provide inb() and outb() as functions. They are normally only * available as macros calling inlined functions, thus cannot be * called inside DDB. * * The actual code is stolen from , and de-inlined. */ #undef inb #undef outb /* silence compiler warnings */ u_char inb(u_int); void outb(u_int, u_char); u_char inb(u_int port) { u_char data; /* * We use %%dx and not %1 here because i/o is done at %dx and not at * %edx, while gcc generates inferior code (movw instead of movl) * if we tell it to load (u_short) port. */ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); return (data); } void outb(u_int port, u_char data) { u_char al; /* * Use an unnecessary assignment to help gcc's register allocator. * This make a large difference for gcc-1.40 and a tiny difference * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for * best results. gcc-2.6.0 can't handle this. */ al = data; __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); } #endif /* DDB */ Index: head/sys/sys/systm.h =================================================================== --- head/sys/sys/systm.h (revision 82392) +++ head/sys/sys/systm.h (revision 82393) @@ -1,286 +1,288 @@ /*- * Copyright (c) 1982, 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)systm.h 8.7 (Berkeley) 3/29/95 * $FreeBSD$ */ #ifndef _SYS_SYSTM_H_ #define _SYS_SYSTM_H_ #include #include #include extern int securelevel; /* system security level (see init(8)) */ extern int cold; /* nonzero if we are doing a cold boot */ extern const char *panicstr; /* panic message */ extern int dumping; /* system is dumping */ extern char version[]; /* system version */ extern char copyright[]; /* system copyright */ extern int nswap; /* size of swap space */ extern struct cv selwait; /* select conditional variable */ extern int physmem; /* physical memory */ extern dev_t dumpdev; /* dump device */ extern long dumplo; /* offset into dumpdev */ extern dev_t rootdev; /* root device */ extern dev_t rootdevs[2]; /* possible root devices */ extern char *rootdevnames[2]; /* names of possible root devices */ extern struct vnode *rootvp; /* vnode equivalent to above */ extern int boothowto; /* reboot flags, from console subsystem */ extern int bootverbose; /* nonzero to print verbose messages */ extern int maxusers; /* system tune hint */ #ifdef INVARIANTS /* The option is always available */ #define KASSERT(exp,msg) do { if (!(exp)) panic msg; } while (0) #else #define KASSERT(exp,msg) #endif /* * General function declarations. */ struct clockframe; struct malloc_type; struct mtx; struct proc; struct timeval; struct tty; struct ucred; struct uio; struct _jmp_buf; int setjmp __P((struct _jmp_buf *)); void longjmp __P((struct _jmp_buf *, int)) __dead2; void Debugger __P((const char *msg)); int dumpstatus __P((vm_offset_t addr, long count)); int nullop __P((void)); int eopnotsupp __P((void)); int einval __P((void)); int seltrue __P((dev_t dev, int which, struct proc *p)); int ureadc __P((int, struct uio *)); void *hashinit __P((int count, struct malloc_type *type, u_long *hashmask)); void *phashinit __P((int count, struct malloc_type *type, u_long *nentries)); void cpu_boot __P((int)); void cpu_rootconf __P((void)); void init_param __P((void)); void tablefull __P((const char *)); int kvprintf __P((char const *, void (*)(int, void*), void *, int, _BSD_VA_LIST_)) __printflike(1, 0); void log __P((int, const char *, ...)) __printflike(2, 3); void log_console __P((struct uio *)); int printf __P((const char *, ...)) __printflike(1, 2); int snprintf __P((char *, size_t, const char *, ...)) __printflike(3, 4); int sprintf __P((char *buf, const char *, ...)) __printflike(2, 3); int uprintf __P((const char *, ...)) __printflike(1, 2); int vprintf __P((const char *, _BSD_VA_LIST_)) __printflike(1, 0); int vsnprintf __P((char *, size_t, const char *, _BSD_VA_LIST_)) __printflike(3, 0); int vsprintf __P((char *buf, const char *, _BSD_VA_LIST_)) __printflike(2, 0); int ttyprintf __P((struct tty *, const char *, ...)) __printflike(2, 3); int sscanf __P((const char *, char const *, ...)); int vsscanf __P((const char *, char const *, _BSD_VA_LIST_)); long strtol __P((const char *, char **, int)); u_long strtoul __P((const char *, char **, int)); quad_t strtoq __P((const char *, char **, int)); u_quad_t strtouq __P((const char *, char **, int)); void tprintf __P((struct proc *p, int pri, const char *, ...)) __printflike(3, 4); void bcopy __P((const void *from, void *to, size_t len)); void ovbcopy __P((const void *from, void *to, size_t len)); #ifdef __i386__ extern void (*bzero) __P((void *buf, size_t len)); #else void bzero __P((void *buf, size_t len)); #endif void *memcpy __P((void *to, const void *from, size_t len)); int copystr __P((const void *kfaddr, void *kdaddr, size_t len, size_t *lencopied)); int copyinstr __P((const void *udaddr, void *kaddr, size_t len, size_t *lencopied)); int copyin __P((const void *udaddr, void *kaddr, size_t len)); int copyout __P((const void *kaddr, void *udaddr, size_t len)); int fubyte __P((const void *base)); int subyte __P((void *base, int byte)); int suibyte __P((void *base, int byte)); long fuword __P((const void *base)); int suword __P((void *base, long word)); int fusword __P((void *base)); int susword __P((void *base, int word)); void realitexpire __P((void *)); void hardclock __P((struct clockframe *frame)); void hardclock_process __P((struct proc *p, int user)); void softclock __P((void *)); void statclock __P((struct clockframe *frame)); void statclock_process __P((struct proc *p, register_t pc, int user)); void startprofclock __P((struct proc *)); void stopprofclock __P((struct proc *)); void setstatclockrate __P((int hzrate)); /* flags for suser_xxx() */ #define PRISON_ROOT 1 int suser __P((struct proc *)); int suser_xxx __P((struct ucred *cred, struct proc *proc, int flag)); int u_cansee __P((struct ucred *u1, struct ucred *u2)); char *getenv __P((const char *name)); int getenv_int __P((const char *name, int *data)); quad_t getenv_quad __P((const char *name, quad_t *data)); extern char *kern_envp; +extern char *static_env; +extern int envmode; #ifdef APM_FIXUP_CALLTODO void adjust_timeout_calltodo __P((struct timeval *time_change)); #endif /* APM_FIXUP_CALLTODO */ #include /* Initialize the world */ void consinit __P((void)); void cpu_initclocks __P((void)); void usrinfoinit __P((void)); /* Finalize the world. */ void shutdown_nice __P((int)); /* * Kernel to clock driver interface. */ void inittodr __P((time_t base)); void resettodr __P((void)); void startrtclock __P((void)); /* Timeouts */ typedef void timeout_t __P((void *)); /* timeout function type */ #define CALLOUT_HANDLE_INITIALIZER(handle) \ { NULL } void callout_handle_init __P((struct callout_handle *)); struct callout_handle timeout __P((timeout_t *, void *, int)); void untimeout __P((timeout_t *, void *, struct callout_handle)); caddr_t kern_timeout_callwheel_alloc __P((caddr_t v)); void kern_timeout_callwheel_init __P((void)); /* Stubs for obsolete functions that used to be for interrupt management */ static __inline void spl0(void) { return; } static __inline intrmask_t splbio(void) { return 0; } static __inline intrmask_t splcam(void) { return 0; } static __inline intrmask_t splclock(void) { return 0; } static __inline intrmask_t splhigh(void) { return 0; } static __inline intrmask_t splimp(void) { return 0; } static __inline intrmask_t splnet(void) { return 0; } static __inline intrmask_t splsoftcam(void) { return 0; } static __inline intrmask_t splsoftclock(void) { return 0; } static __inline intrmask_t splsofttty(void) { return 0; } static __inline intrmask_t splsoftvm(void) { return 0; } static __inline intrmask_t splsofttq(void) { return 0; } static __inline intrmask_t splstatclock(void) { return 0; } static __inline intrmask_t spltty(void) { return 0; } static __inline intrmask_t splvm(void) { return 0; } static __inline void splx(intrmask_t ipl) { return; } /* * Various callout lists. */ /* Exit callout list declarations. */ typedef void (*exitlist_fn) __P((struct proc *procp)); int at_exit __P((exitlist_fn function)); int rm_at_exit __P((exitlist_fn function)); /* Fork callout list declarations. */ typedef void (*forklist_fn) __P((struct proc *parent, struct proc *child, int flags)); int at_fork __P((forklist_fn function)); int rm_at_fork __P((forklist_fn function)); /* * Not exactly a callout LIST, but a callout entry. * Allow an external module to define a hardware watchdog tickler. * Normally a process would do this, but there are times when the * kernel needs to be able to hold off the watchdog, when the process * is not active, e.g., when dumping core. */ typedef void (*watchdog_tickle_fn) __P((void)); extern watchdog_tickle_fn wdog_tickler; /* * Common `proc' functions are declared here so that proc.h can be included * less often. */ int msleep __P((void *chan, struct mtx *mtx, int pri, const char *wmesg, int timo)); #define tsleep(chan, pri, wmesg, timo) msleep(chan, NULL, pri, wmesg, timo) void wakeup __P((void *chan)); void wakeup_one __P((void *chan)); /* * Common `dev_t' stuff are declared here to avoid #include poisoning */ int major(dev_t x); int minor(dev_t x); dev_t makedev(int x, int y); udev_t dev2udev(dev_t x); dev_t udev2dev(udev_t x, int b); int uminor(udev_t dev); int umajor(udev_t dev); udev_t makeudev(int x, int y); /* XXX: Should be void nanodelay(u_int nsec); */ void DELAY __P((int usec)); #endif /* !_SYS_SYSTM_H_ */ Index: head/usr.sbin/config/config.h =================================================================== --- head/usr.sbin/config/config.h (revision 82392) +++ head/usr.sbin/config/config.h (revision 82393) @@ -1,158 +1,160 @@ /* * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)config.h 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ /* * Config. */ #include #include #include struct file_list { struct file_list *f_next; char *f_fn; /* the name */ int f_type; /* type or count */ u_char f_flags; /* see below */ char *f_compilewith; /* special make rule if present */ char *f_depends; /* additional dependancies */ char *f_clean; /* File list to add to clean rule */ char *f_needs; char *f_warn; /* warning message */ }; /* * Types. */ #define NORMAL 1 #define INVISIBLE 2 #define PROFILING 3 #define NODEPEND 4 #define LOCAL 5 #define DEVDONE 0x80000000 #define TYPEMASK 0x7fffffff /* * Attributes (flags). */ #define NO_IMPLCT_RULE 1 #define NO_OBJ 2 #define BEFORE_DEPEND 4 #define NEED_COUNT 8 #define ISDUP 16 struct device { int d_done; /* processed */ char *d_name; /* name of device (e.g. rk11) */ int d_count; /* device count */ #define UNKNOWN -2 /* -2 means not set yet */ struct device *d_next; /* Next one in list */ }; struct config { char *s_sysname; }; /* * Config has a global notion of which machine type is * being used. It uses the name of the machine in choosing * files and directories. Thus if the name of the machine is ``i386'', * it will build from ``Makefile.i386'' and use ``../i386/inline'' * in the makerules, etc. */ char *machinename; /* * For each machine, a set of CPU's may be specified as supported. * These and the options (below) are put in the C flags in the makefile. */ struct cputype { char *cpu_name; struct cputype *cpu_next; } *cputype; /* * A set of options may also be specified which are like CPU types, * but which may also specify values for the options. * A separate set of options may be defined for make-style options. */ struct opt { char *op_name; char *op_value; int op_ownfile; /* true = own file, false = makefile */ struct opt *op_next; } *opt, *mkopt; struct opt_list { char *o_name; char *o_file; struct opt_list *o_next; } *otab; extern char *ident; +extern char *env; extern char *hints; extern int do_trace; +extern int envmode; extern int hintmode; char *get_word(FILE *); char *get_quoted_word(FILE *); char *path(const char *); char *raisestr(char *); void remember(const char *); void moveifchanged(const char *, const char *); int yyparse(void); int yylex(void); void options(void); void makefile(void); void headers(void); extern struct device *dtab; extern char errbuf[80]; extern int yyline; extern const char *yyfile; extern struct file_list *ftab; extern int profiling; extern int debugging; extern int maxusers; extern char *PREFIX; /* Config file name - for error messages */ extern char srcdir[]; /* root of the kernel source tree */ #define eq(a,b) (!strcmp(a,b)) #define ns(s) strdup(s) Index: head/usr.sbin/config/config.y =================================================================== --- head/usr.sbin/config/config.y (revision 82392) +++ head/usr.sbin/config/config.y (revision 82393) @@ -1,283 +1,291 @@ %union { char *str; int val; struct file_list *file; } %token ARCH %token COMMA %token CONFIG %token CPU %token DEVICE +%token ENV %token EQUALS %token HINTS %token IDENT %token MAXUSERS %token PROFILE %token OPTIONS %token MAKEOPTIONS %token SEMICOLON %token INCLUDE %token ID %token NUMBER %type Save_id %type Opt_value %type Dev %{ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)config.y 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ #include #include #include #include #include "config.h" static struct device *curp = 0; struct device *dtab; char *ident; +char *env; +int envmode; char *hints; int hintmode; int yyline; const char *yyfile; struct file_list *ftab; char errbuf[80]; int maxusers; #define ns(s) strdup(s) int include(const char *, int); void yyerror(const char *s); static char * devopt(char *dev) { char *ret = malloc(strlen(dev) + 5); sprintf(ret, "DEV_%s", dev); raisestr(ret); return ret; } %} %% Configuration: Many_specs ; Many_specs: Many_specs Spec | /* lambda */ ; Spec: Device_spec SEMICOLON | Config_spec SEMICOLON | SEMICOLON | error SEMICOLON ; Config_spec: ARCH Save_id = { machinename = $2; } | CPU Save_id = { struct cputype *cp = (struct cputype *)malloc(sizeof (struct cputype)); memset(cp, 0, sizeof(*cp)); cp->cpu_name = $2; cp->cpu_next = cputype; cputype = cp; } | OPTIONS Opt_list | MAKEOPTIONS Mkopt_list | IDENT ID = { ident = $2; } | System_spec | MAXUSERS NUMBER = { maxusers = $2; } | PROFILE NUMBER = { profiling = $2; } | + ENV ID + = { + env = $2; + envmode = 1; + } | HINTS ID = { hints = $2; hintmode = 1; } | INCLUDE ID = { include($2, 0); }; System_spec: CONFIG System_id System_parameter_list = { errx(1, "%s:%d: root/dump/swap specifications obsolete", yyfile, yyline);} | CONFIG System_id ; System_id: Save_id = { newopt(&mkopt, ns("KERNEL"), $1); }; System_parameter_list: System_parameter_list ID | ID ; Opt_list: Opt_list COMMA Option | Option ; Option: Save_id = { char *s; newopt(&opt, $1, NULL); if ((s = strchr($1, '='))) errx(1, "%s:%d: The `=' in options should not be " "quoted", yyfile, yyline); } | Save_id EQUALS Opt_value = { newopt(&opt, $1, $3); } ; Opt_value: ID = { $$ = $1; } | NUMBER = { char buf[80]; (void) snprintf(buf, sizeof(buf), "%d", $1); $$ = ns(buf); } ; Save_id: ID = { $$ = $1; } ; Mkopt_list: Mkopt_list COMMA Mkoption | Mkoption ; Mkoption: Save_id EQUALS Opt_value = { newopt(&mkopt, $1, $3); } ; Dev: ID = { $$ = $1; } ; Device_spec: DEVICE Dev = { newopt(&opt, devopt($2), ns("1")); /* and the device part */ newdev($2, UNKNOWN); } | DEVICE Dev NUMBER = { newopt(&opt, devopt($2), ns("1")); /* and the device part */ newdev($2, $3); if ($3 == 0) errx(1, "%s:%d: devices with zero units are not " "likely to be correct", yyfile, yyline); } ; %% void yyerror(const char *s) { errx(1, "%s:%d: %s", yyfile, yyline + 1, s); } /* * add a device to the list of devices */ static void newdev(char *name, int count) { struct device *np; np = (struct device *) malloc(sizeof *np); memset(np, 0, sizeof(*np)); np->d_name = name; np->d_count = count; np->d_next = 0; if (curp == 0) dtab = np; else curp->d_next = np; curp = np; } static void newopt(struct opt **list, char *name, char *value) { struct opt *op; op = (struct opt *)malloc(sizeof (struct opt)); memset(op, 0, sizeof(*op)); op->op_name = name; op->op_ownfile = 0; op->op_value = value; op->op_next = *list; *list = op; } Index: head/usr.sbin/config/configvers.h =================================================================== --- head/usr.sbin/config/configvers.h (revision 82392) +++ head/usr.sbin/config/configvers.h (revision 82393) @@ -1,11 +1,11 @@ /* * 6 digits of version. The most significant are branch indicators * (eg: RELENG_2_2 = 22, -current presently = 50 etc). The least * significant digits are incremented for each incompatible change. * * The numbering scheme is inspired by the sys/conf/newvers.sh RELDATE * and system. * * $FreeBSD$ */ -#define CONFIGVERS 500007 +#define CONFIGVERS 500008 Index: head/usr.sbin/config/lang.l =================================================================== --- head/usr.sbin/config/lang.l (revision 82392) +++ head/usr.sbin/config/lang.l (revision 82393) @@ -1,273 +1,274 @@ %{ /*- * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)lang.l 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ #include #include #include #include "y.tab.h" #include "config.h" #define YY_NO_UNPUT /* * Data for returning to previous files from include files. */ struct incl { struct incl *in_prev; /* previous includes in effect, if any */ YY_BUFFER_STATE in_buf; /* previous lex state */ const char *in_fname; /* previous file name */ int in_lineno; /* previous line number */ int in_ateof; /* token to insert at EOF */ }; static struct incl *inclp; static const char *lastfile; /* * Key word table */ struct kt { const char *kt_name; int kt_val; } key_words[] = { { "config", CONFIG }, { "cpu", CPU }, { "device", DEVICE }, + { "env", ENV }, { "hints", HINTS }, { "ident", IDENT }, { "machine", ARCH }, /* MACHINE is defined in /sys/param.h */ { "makeoptions", MAKEOPTIONS }, { "maxusers", MAXUSERS }, { "profile", PROFILE }, { "option", OPTIONS }, { "options", OPTIONS }, { "include", INCLUDE }, { 0, 0 }, }; static int endinclude(void); int include(const char *, int); int kw_lookup(char *); int octal(char *); int hex(char *); int yyerror(const char *); %} WORD [A-Za-z_][-A-Za-z_]* ID [A-Za-z_][-A-Za-z_0-9]* %START NONUM TOEOL %% {WORD} { int i; BEGIN 0; if ((i = kw_lookup(yytext)) == -1) { yylval.str = strdup(yytext); return ID; } return i; } {WORD}/[0-9]* { int i; if ((i = kw_lookup(yytext)) == -1) REJECT; if (i == DEVICE) BEGIN NONUM; return i; } {ID} { BEGIN 0; yylval.str = strdup(yytext); return ID; } \\\"[^"]+\\\" { BEGIN 0; yytext[yyleng-2] = '"'; yytext[yyleng-1] = '\0'; yylval.str = strdup(yytext + 1); return ID; } \"[^"]+\" { BEGIN 0; yytext[yyleng-1] = '\0'; yylval.str = strdup(yytext + 1); return ID; } [^# \t\n]* { BEGIN 0; yylval.str = strdup(yytext); return ID; } 0[0-7]* { yylval.val = octal(yytext); return NUMBER; } 0x[0-9a-fA-F]+ { yylval.val = hex(yytext); return NUMBER; } -?[1-9][0-9]* { yylval.val = atoi(yytext); return NUMBER; } "?" { yylval.val = -1; return NUMBER; } \n/[ \t] { yyline++; } \n { yyline++; return SEMICOLON; } #.* { /* Ignored (comment) */; } [ \t\f]* { /* Ignored (white space) */; } ";" { return SEMICOLON; } "," { return COMMA; } "=" { BEGIN TOEOL; return EQUALS; } <> { int tok; if (inclp == NULL) return YY_NULL; tok = endinclude(); if (tok != 0) return tok; /* otherwise continue scanning */ } . { return yytext[0]; } %% /* * kw_lookup * Look up a string in the keyword table. Returns a -1 if the * string is not a keyword otherwise it returns the keyword number */ int kw_lookup(char *word) { struct kt *kp; for (kp = key_words; kp->kt_name != 0; kp++) if (eq(word, kp->kt_name)) return kp->kt_val; return -1; } /* * Number conversion routines */ int octal(char *str) { int num; (void) sscanf(str, "%o", &num); return num; } int hex(char *str) { int num; (void) sscanf(str+2, "%x", &num); return num; } /* * Open the named file for inclusion at the current point. Returns 0 on * success (file opened and previous state pushed), nonzero on failure * (fopen failed, complaint made). The `ateof' parameter controls the * token to be inserted at the end of the include file. If ateof == 0, * then nothing is inserted. */ int include(const char *fname, int ateof) { FILE *fp; struct incl *in; fp = fopen(fname, "r"); if (fp == NULL) { yyerror("cannot open file"); return (-1); } in = malloc(sizeof(*in)); assert(in != NULL); in->in_prev = inclp; in->in_buf = YY_CURRENT_BUFFER; in->in_fname = yyfile; in->in_lineno = yyline; in->in_ateof = ateof; inclp = in; yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); yyfile = fname; yyline = 0; return (0); } /* * Terminate the most recent inclusion. */ static int endinclude() { struct incl *in; int ateof; in = inclp; assert(in != NULL); inclp = in->in_prev; lastfile = yyfile; yy_delete_buffer(YY_CURRENT_BUFFER); (void)fclose(yyin); yy_switch_to_buffer(in->in_buf); yyfile = in->in_fname; yyline = in->in_lineno; ateof = in->in_ateof; free(in); return (ateof); } Index: head/usr.sbin/config/mkmakefile.c =================================================================== --- head/usr.sbin/config/mkmakefile.c (revision 82392) +++ head/usr.sbin/config/mkmakefile.c (revision 82393) @@ -1,737 +1,773 @@ /* * Copyright (c) 1993, 19801990 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)mkmakefile.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * Build the makefile for the system, from * the information in the files files and the * additional files for the machine being compiled to. */ #include #include #include #include #include #include "y.tab.h" #include "config.h" #include "configvers.h" #define next_word(fp, wd) \ { char *word = get_word(fp); \ if (word == (char *)EOF) \ return; \ else \ wd = word; \ } #define next_quoted_word(fp, wd) \ { char *word = get_quoted_word(fp); \ if (word == (char *)EOF) \ return; \ else \ wd = word; \ } static struct file_list *fcur; static char *tail(char *); static void do_clean(FILE *); static void do_rules(FILE *); static void do_xxfiles(char *, FILE *); static void do_objs(FILE *); static void do_before_depend(FILE *); static int opteq(const char *, const char *); static void read_files(void); /* * Lookup a file, by name. */ static struct file_list * fl_lookup(char *file) { struct file_list *fp; for (fp = ftab ; fp != 0; fp = fp->f_next) { if (eq(fp->f_fn, file)) return (fp); } return (0); } /* * Make a new file list entry */ static struct file_list * new_fent(void) { struct file_list *fp; fp = (struct file_list *) malloc(sizeof *fp); bzero(fp, sizeof *fp); if (fcur == 0) fcur = ftab = fp; else fcur->f_next = fp; fcur = fp; return (fp); } /* * Build the makefile from the skeleton */ void makefile(void) { FILE *ifp, *ofp; char line[BUFSIZ]; struct opt *op; int versreq; char *s; read_files(); snprintf(line, sizeof(line), "../../conf/Makefile.%s", machinename); ifp = fopen(line, "r"); if (ifp == 0) { snprintf(line, sizeof(line), "Makefile.%s", machinename); ifp = fopen(line, "r"); } if (ifp == 0) err(1, "%s", line); ofp = fopen(path("Makefile.new"), "w"); if (ofp == 0) err(1, "%s", path("Makefile.new")); fprintf(ofp, "KERN_IDENT=%s\n", raisestr(ident)); fprintf(ofp, "IDENT="); if (profiling) fprintf(ofp, " -DGPROF"); if (cputype == 0) { printf("cpu type must be specified\n"); exit(1); } fprintf(ofp, "\n"); for (op = mkopt; op; op = op->op_next) fprintf(ofp, "%s=%s\n", op->op_name, op->op_value); if (debugging) fprintf(ofp, "DEBUG=-g\n"); if (profiling) { fprintf(ofp, "PROF=-pg\n"); fprintf(ofp, "PROFLEVEL=%d\n", profiling); } if (*srcdir != '\0') fprintf(ofp,"S=%s\n", srcdir); while (fgets(line, BUFSIZ, ifp) != 0) { if (*line != '%') { fprintf(ofp, "%s", line); continue; } if (eq(line, "%BEFORE_DEPEND\n")) do_before_depend(ofp); else if (eq(line, "%OBJS\n")) do_objs(ofp); else if (strncmp(line, "%FILES.", 7) == 0) do_xxfiles(line, ofp); else if (eq(line, "%RULES\n")) do_rules(ofp); else if (eq(line, "%CLEAN\n")) do_clean(ofp); else if (strncmp(line, "%VERSREQ=", sizeof("%VERSREQ=") - 1) == 0) { versreq = atoi(line + sizeof("%VERSREQ=") - 1); if (versreq != CONFIGVERS) { fprintf(stderr, "ERROR: version of config(8) does not match kernel!\n"); fprintf(stderr, "config version = %d, ", CONFIGVERS); fprintf(stderr, "version required = %d\n\n", versreq); fprintf(stderr, "Make sure that /usr/src/usr.sbin/config is in sync\n"); fprintf(stderr, "with your /usr/src/sys and install a new config binary\n"); fprintf(stderr, "before trying this again.\n\n"); fprintf(stderr, "If running the new config fails check your config\n"); fprintf(stderr, "file against the GENERIC or LINT config files for\n"); fprintf(stderr, "changes in config syntax, or option/device naming\n"); fprintf(stderr, "conventions\n\n"); exit(1); } } else fprintf(stderr, "Unknown %% construct in generic makefile: %s", line); } (void) fclose(ifp); (void) fclose(ofp); moveifchanged(path("Makefile.new"), path("Makefile")); if (hints) { ifp = fopen(hints, "r"); if (ifp == NULL) err(1, "%s", hints); } else { ifp = NULL; } ofp = fopen(path("hints.c.new"), "w"); if (ofp == NULL) err(1, "%s", path("hints.c.new")); -#if 0 - /* - * This is causing more pain than it is worth. And besides, the - * release has been fixed so that this isn't necessary anymore. - * The boot floppies load hints now. - */ - if (hintmode == 0) { - snprintf(line, sizeof(line), "%s.hints", PREFIX); - ifp = fopen(line, "r"); - if (ifp) - hintmode = 2; - } -#endif fprintf(ofp, "int hintmode = %d;\n", hintmode); fprintf(ofp, "char static_hints[] = {\n"); if (ifp) { while (fgets(line, BUFSIZ, ifp) != 0) { /* zap trailing CR and/or LF */ while ((s = rindex(line, '\n')) != NULL) *s = '\0'; while ((s = rindex(line, '\r')) != NULL) *s = '\0'; /* remove # comments */ s = index(line, '#'); if (s) *s = '\0'; /* remove any whitespace and " characters */ s = line; while (*s) { if (*s == ' ' || *s == '\t' || *s == '"') { while (*s) { s[0] = s[1]; s++; } /* start over */ s = line; continue; } s++; } /* anything left? */ if (*line == '\0') continue; fprintf(ofp, "\"%s\\0\"\n", line); } } fprintf(ofp, "\"\\0\"\n};\n"); if (ifp) fclose(ifp); fclose(ofp); moveifchanged(path("hints.c.new"), path("hints.c")); + + if (env) { + ifp = fopen(env, "r"); + if (ifp == NULL) + err(1, "%s", env); + } else { + ifp = NULL; + } + ofp = fopen(path("env.c.new"), "w"); + if (ofp == NULL) + err(1, "%s", path("env.c.new")); + fprintf(ofp, "int envmode = %d;\n", envmode); + fprintf(ofp, "char static_env[] = {\n"); + if (ifp) { + while (fgets(line, BUFSIZ, ifp) != 0) { + /* zap trailing CR and/or LF */ + while ((s = rindex(line, '\n')) != NULL) + *s = '\0'; + while ((s = rindex(line, '\r')) != NULL) + *s = '\0'; + /* remove # comments */ + s = index(line, '#'); + if (s) + *s = '\0'; + /* remove any whitespace and " characters */ + s = line; + while (*s) { + if (*s == ' ' || *s == '\t' || *s == '"') { + while (*s) { + s[0] = s[1]; + s++; + } + /* start over */ + s = line; + continue; + } + s++; + } + /* anything left? */ + if (*line == '\0') + continue; + fprintf(ofp, "\"%s\\0\"\n", line); + } + } + fprintf(ofp, "\"\\0\"\n};\n"); + if (ifp) + fclose(ifp); + fclose(ofp); + moveifchanged(path("env.c.new"), path("env.c")); } /* * Read in the information about files used in making the system. * Store it in the ftab linked list. */ static void read_files(void) { FILE *fp; struct file_list *tp, *pf; struct device *dp; struct opt *op; char *wd, *this, *needs, *compilewith, *depends, *clean, *warning; char fname[MAXPATHLEN]; int nreqs, first = 1, isdup, std, filetype, imp_rule, no_obj, needcount, before_depend, mandatory; ftab = 0; if (ident == NULL) { printf("no ident line specified\n"); exit(1); } (void) snprintf(fname, sizeof(fname), "../../conf/files"); openit: fp = fopen(fname, "r"); if (fp == 0) err(1, "%s", fname); next: /* * filename [ standard | mandatory | optional | count ] * [ dev* | profiling-routine ] [ no-obj ] * [ compile-with "compile rule" [no-implicit-rule] ] * [ dependency "dependency-list"] [ before-depend ] * [ clean "file-list"] [ warning "text warning" ] */ wd = get_word(fp); if (wd == (char *)EOF) { (void) fclose(fp); if (first == 1) { first++; (void) snprintf(fname, sizeof(fname), "../../conf/files.%s", machinename); fp = fopen(fname, "r"); if (fp != 0) goto next; (void) snprintf(fname, sizeof(fname), "files.%s", machinename); goto openit; } return; } if (wd == 0) goto next; if (wd[0] == '#') { while (((wd = get_word(fp)) != (char *)EOF) && wd) ; goto next; } this = ns(wd); next_word(fp, wd); if (wd == 0) { printf("%s: No type for %s.\n", fname, this); exit(1); } if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags)) isdup = ISDUP; else isdup = 0; tp = 0; nreqs = 0; compilewith = 0; depends = 0; clean = 0; warning = 0; needs = 0; std = mandatory = 0; imp_rule = 0; no_obj = 0; needcount = 0; before_depend = 0; filetype = NORMAL; if (eq(wd, "standard")) { std = 1; /* * If an entry is marked "mandatory", config will abort if it's * not called by a configuration line in the config file. Apart * from this, the device is handled like one marked "optional". */ } else if (eq(wd, "mandatory")) { mandatory = 1; } else if (eq(wd, "count")) { needcount = 1; } else if (!eq(wd, "optional")) { printf("%s: %s must be count, optional, mandatory or standard\n", fname, this); exit(1); } nextparam: next_word(fp, wd); if (wd == 0) goto doneparam; if (eq(wd, "no-obj")) { no_obj++; goto nextparam; } if (eq(wd, "no-implicit-rule")) { if (compilewith == 0) { printf("%s: alternate rule required when " "\"no-implicit-rule\" is specified.\n", fname); } imp_rule++; goto nextparam; } if (eq(wd, "before-depend")) { before_depend++; goto nextparam; } if (eq(wd, "dependency")) { next_quoted_word(fp, wd); if (wd == 0) { printf("%s: %s missing compile command string.\n", fname, this); exit(1); } depends = ns(wd); goto nextparam; } if (eq(wd, "clean")) { next_quoted_word(fp, wd); if (wd == 0) { printf("%s: %s missing clean file list.\n", fname, this); exit(1); } clean = ns(wd); goto nextparam; } if (eq(wd, "compile-with")) { next_quoted_word(fp, wd); if (wd == 0) { printf("%s: %s missing compile command string.\n", fname, this); exit(1); } compilewith = ns(wd); goto nextparam; } if (eq(wd, "warning")) { next_quoted_word(fp, wd); if (wd == 0) { printf("%s: %s missing warning text string.\n", fname, this); exit(1); } warning = ns(wd); goto nextparam; } nreqs++; if (eq(wd, "local")) { filetype = LOCAL; goto nextparam; } if (eq(wd, "no-depend")) { filetype = NODEPEND; goto nextparam; } if (eq(wd, "profiling-routine")) { filetype = PROFILING; goto nextparam; } if (needs == 0 && nreqs == 1) needs = ns(wd); if (isdup) goto invis; for (dp = dtab; dp != 0; dp = dp->d_next) if (eq(dp->d_name, wd)) { if (std && dp->d_count <= 0) dp->d_count = 1; goto nextparam; } if (mandatory) { printf("%s: mandatory device \"%s\" not found\n", fname, wd); exit(1); } if (std) { printf("standard entry %s has a device keyword - %s!\n", this, wd); exit(1); } for (op = opt; op != 0; op = op->op_next) if (op->op_value == 0 && opteq(op->op_name, wd)) { if (nreqs == 1) { free(needs); needs = 0; } goto nextparam; } invis: while ((wd = get_word(fp)) != 0) ; if (tp == 0) tp = new_fent(); tp->f_fn = this; tp->f_type = INVISIBLE; tp->f_needs = needs; tp->f_flags |= isdup; if (needcount) tp->f_flags |= NEED_COUNT; tp->f_compilewith = compilewith; tp->f_depends = depends; tp->f_clean = clean; tp->f_warn = warning; goto next; doneparam: if (std == 0 && nreqs == 0) { printf("%s: what is %s optional on?\n", fname, this); exit(1); } if (wd) { printf("%s: syntax error describing %s\n", fname, this); exit(1); } if (filetype == PROFILING && profiling == 0) goto next; if (tp == 0) tp = new_fent(); tp->f_fn = this; tp->f_type = filetype; tp->f_flags &= ~ISDUP; if (imp_rule) tp->f_flags |= NO_IMPLCT_RULE; if (no_obj) tp->f_flags |= NO_OBJ; if (before_depend) tp->f_flags |= BEFORE_DEPEND; if (needcount) tp->f_flags |= NEED_COUNT; tp->f_needs = needs; tp->f_compilewith = compilewith; tp->f_depends = depends; tp->f_clean = clean; tp->f_warn = warning; if (pf && pf->f_type == INVISIBLE) pf->f_flags |= ISDUP; /* mark as duplicate */ goto next; } static int opteq(const char *cp, const char *dp) { char c, d; for (; ; cp++, dp++) { if (*cp != *dp) { c = isupper(*cp) ? tolower(*cp) : *cp; d = isupper(*dp) ? tolower(*dp) : *dp; if (c != d) return (0); } if (*cp == 0) return (1); } } static void do_before_depend(FILE *fp) { struct file_list *tp; int lpos, len; fputs("BEFORE_DEPEND=", fp); lpos = 15; for (tp = ftab; tp; tp = tp->f_next) if (tp->f_flags & BEFORE_DEPEND) { len = strlen(tp->f_fn); if ((len = 3 + len) + lpos > 72) { lpos = 8; fputs("\\\n\t", fp); } if (tp->f_flags & NO_IMPLCT_RULE) fprintf(fp, "%s ", tp->f_fn); else fprintf(fp, "$S/%s ", tp->f_fn); lpos += len + 1; } if (lpos != 8) putc('\n', fp); } static void do_objs(FILE *fp) { struct file_list *tp; int lpos, len; char *cp, och, *sp; fprintf(fp, "OBJS="); lpos = 6; for (tp = ftab; tp != 0; tp = tp->f_next) { if (tp->f_type == INVISIBLE || tp->f_flags & NO_OBJ) continue; sp = tail(tp->f_fn); cp = sp + (len = strlen(sp)) - 1; och = *cp; *cp = 'o'; if (len + lpos > 72) { lpos = 8; fprintf(fp, "\\\n\t"); } fprintf(fp, "%s ", sp); lpos += len + 1; *cp = och; } if (lpos != 8) putc('\n', fp); } static void do_xxfiles(char *tag, FILE *fp) { struct file_list *tp; int lpos, len, slen; char *suff, *SUFF; if (tag[strlen(tag) - 1] == '\n') tag[strlen(tag) - 1] = '\0'; suff = ns(tag + 7); SUFF = ns(suff); raisestr(SUFF); slen = strlen(suff); fprintf(fp, "%sFILES=", SUFF); lpos = 8; for (tp = ftab; tp; tp = tp->f_next) if (tp->f_type != INVISIBLE && tp->f_type != NODEPEND) { len = strlen(tp->f_fn); if (tp->f_fn[len - slen - 1] != '.') continue; if (strcasecmp(&tp->f_fn[len - slen], suff) != 0) continue; if ((len = 3 + len) + lpos > 72) { lpos = 8; fputs("\\\n\t", fp); } if (tp->f_type != LOCAL) fprintf(fp, "$S/%s ", tp->f_fn); else fprintf(fp, "%s ", tp->f_fn); lpos += len + 1; } if (lpos != 8) putc('\n', fp); } static char * tail(char *fn) { char *cp; cp = rindex(fn, '/'); if (cp == 0) return (fn); return (cp+1); } /* * Create the makerules for each file * which is part of the system. */ static void do_rules(FILE *f) { char *cp, *np, och, *tp; struct file_list *ftp; char *compilewith; for (ftp = ftab; ftp != 0; ftp = ftp->f_next) { if (ftp->f_type == INVISIBLE) continue; if (ftp->f_warn) printf("WARNING: %s\n", ftp->f_warn); cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1; och = *cp; if (ftp->f_flags & NO_IMPLCT_RULE) { if (ftp->f_depends) fprintf(f, "%s: %s\n", np, ftp->f_depends); else fprintf(f, "%s: \n", np); } else { *cp = '\0'; if (och == 'o') { fprintf(f, "%so:\n\t-cp $S/%so .\n\n", tail(np), np); continue; } if (ftp->f_depends) fprintf(f, "%so: $S/%s%c %s\n", tail(np), np, och, ftp->f_depends); else fprintf(f, "%so: $S/%s%c\n", tail(np), np, och); } tp = tail(np); compilewith = ftp->f_compilewith; if (compilewith == 0) { const char *ftype = NULL; static char cmd[128]; switch (ftp->f_type) { case NORMAL: ftype = "NORMAL"; break; case PROFILING: if (!profiling) continue; ftype = "PROFILE"; break; default: printf("config: don't know rules for %s\n", np); break; } snprintf(cmd, sizeof(cmd), "${%s_%c}", ftype, toupper(och)); compilewith = cmd; } *cp = och; fprintf(f, "\t%s\n\n", compilewith); } } static void do_clean(FILE *fp) { struct file_list *tp; int lpos, len; fputs("CLEAN=", fp); lpos = 7; for (tp = ftab; tp; tp = tp->f_next) if (tp->f_clean) { len = strlen(tp->f_clean); if (len + lpos > 72) { lpos = 8; fputs("\\\n\t", fp); } fprintf(fp, "%s ", tp->f_clean); lpos += len + 1; } if (lpos != 8) putc('\n', fp); } char * raisestr(char *str) { char *cp = str; while (*str) { if (islower(*str)) *str = toupper(*str); str++; } return (cp); }