diff options
163 files changed, 32385 insertions, 8 deletions
diff --git a/sys/arch/amd64/Makefile b/sys/arch/amd64/Makefile new file mode 100644 index 00000000000..8cc23453486 --- /dev/null +++ b/sys/arch/amd64/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 2004/01/28 01:39:38 mickey Exp $ + +NOPROG= noprog +NOMAN= noman + +SUBDIR= stand + +obj: _SUBDIRUSE + +.include <bsd.prog.mk> diff --git a/sys/arch/amd64/amd64/Locore.c b/sys/arch/amd64/amd64/Locore.c new file mode 100644 index 00000000000..91ea15b55ea --- /dev/null +++ b/sys/arch/amd64/amd64/Locore.c @@ -0,0 +1,88 @@ +/* $OpenBSD: Locore.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ + +/* + * Copyright (C) 1995, 1996 Wolfgang Solfrank. + * Copyright (C) 1995, 1996 TooLs GmbH. + * 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 TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ + +/* + * Some additional routines that happened to be in locore.S traditionally, + * but have no need to be coded in assembly. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> + +/* + * Put process p on the run queue, given by its priority. + * Calls should be made at splstatclock(), and p->p_stat should be SRUN. + */ +void +setrunqueue(p) + struct proc *p; +{ + struct prochd *q; + struct proc *oldlast; + int which = p->p_priority >> 2; + +#ifdef DIAGNOSTIC + if (p->p_back) + panic("setrunqueue"); +#endif + q = &qs[which]; + whichqs |= 1 << which; + p->p_forw = (struct proc *)q; + p->p_back = oldlast = q->ph_rlink; + q->ph_rlink = p; + oldlast->p_forw = p; +} + +/* + * Remove process p from its run queue, given by its priority. + * Calls should be made at splstatclock(). + */ +void +remrunqueue(p) + struct proc *p; +{ + int which = p->p_priority >> 2; + struct prochd *q; + +#ifdef DIAGNOSTIC + if (!(whichqs & (1 << which))) + panic("remrunqueue"); +#endif + p->p_forw->p_back = p->p_back; + p->p_back->p_forw = p->p_forw; + p->p_back = NULL; + q = &qs[which]; + if (q->ph_link == (struct proc *)q) + whichqs &= ~(1 << which); +} diff --git a/sys/arch/amd64/amd64/autoconf.c b/sys/arch/amd64/amd64/autoconf.c new file mode 100644 index 00000000000..d4eed4a1134 --- /dev/null +++ b/sys/arch/amd64/amd64/autoconf.c @@ -0,0 +1,606 @@ +/* $OpenBSD: autoconf.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: autoconf.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)autoconf.c 7.1 (Berkeley) 5/9/91 + */ + +/* + * Setup the system to run on the current machine. + * + * Configure() is called at boot time and initializes the vba + * device tables and the memory controller monitoring. Available + * devices are determined (from possibilities mentioned in ioconf.c), + * and the drivers are initialized. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/dkstat.h> +#include <sys/disklabel.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/fcntl.h> +#include <sys/dkio.h> +#include <sys/reboot.h> + +#include <machine/pte.h> +#include <machine/cpu.h> +#include <machine/bootinfo.h> + +#include <dev/cons.h> + +#include "ioapic.h" +#include "lapic.h" + +#if NIOAPIC > 0 +#include <machine/i82093var.h> +#endif + +#if NLAPIC > 0 +#include <machine/i82489var.h> +#endif + +void setroot(void); +void swapconf(void); +void diskconf(void); +int findblkmajor(struct device *); +char *findblkname(int); +static struct device *getdisk(char *, int, int, dev_t *); +struct device * parsedisk(char *, int, int, dev_t *); +static int getstr(char *, int); + +extern struct disklist *x86_64_alldisks; +extern int x86_64_ndisks; + +#if 0 +#include "bios32.h" +#if NBIOS32 > 0 +#include <machine/bios32.h> +#endif +#endif + +int cold = 1; /* if 1, still working on cold-start */ +struct device *booted_device; +int booted_partition; + +/* + * Determine i/o configuration for a machine. + */ +void +cpu_configure(void) +{ +#if NBIOS32 > 0 + bios32_init(); +#endif + + x86_64_proc0_tss_ldt_init(); + + if (config_rootfound("mainbus", NULL) == NULL) + panic("configure: mainbus not configured"); + + startrtclock(); + + intr_printconfig(); + +#if NIOAPIC > 0 + lapic_set_lvt(); + ioapic_enable(); +#endif + +#ifdef MULTIPROCESSOR + cpu_init_idle_pcbs(); +#endif + + lcr8(0); + spl0(); + cold = 0; + + md_diskconf = diskconf; +} + +void +diskconf(void) +{ +printf("setroot\n"); + setroot(); +printf("swapconf\n"); + swapconf(); +printf("dumpconf\n"); + dumpconf(); +} + +void +setroot() +{ + struct swdevt *swp; + struct device *dv; + int len, majdev, unit, part; + dev_t nrootdev, nswapdev = NODEV; + char buf[128]; + dev_t temp; + struct device *bootdv; + struct bootpath *bp; +#if defined(NFSCLIENT) + extern char *nfsbootdevname; +#endif + +#ifdef RAMDISK_HOOKS + bootdv = &fakerdrootdev; +#else + bootdv = booted_device; +#endif + + /* + * (raid) device auto-configuration could have returned + * the root device's id in rootdev. Check this case. + */ + if (rootdev != NODEV) { + majdev = major(rootdev); + unit = DISKUNIT(rootdev); + part = DISKPART(rootdev); + + len = snprintf(buf, sizeof buf, "%s%d", findblkname(majdev), + unit); + if (len >= sizeof(buf)) + panic("setroot: device name too long"); + + bootdv = getdisk(buf, len, part, &rootdev); + } + + /* + * If `swap generic' and we couldn't determine boot device, + * ask the user. + */ + if (mountroot == NULL && bootdv == NULL) + boothowto |= RB_ASKNAME; + + if (boothowto & RB_ASKNAME) { + for (;;) { + printf("root device "); + if (bootdv != NULL) + printf("(default %s%c)", + bootdv->dv_xname, + bootdv->dv_class == DV_DISK + ? booted_partition + 'a' : ' '); + printf(": "); + len = getstr(buf, sizeof(buf)); + if (len == 0 && bootdv != NULL) { + strlcpy(buf, bootdv->dv_xname, sizeof buf); + len = strlen(buf); + } + if (len > 0 && buf[len - 1] == '*') { + buf[--len] = '\0'; + dv = getdisk(buf, len, 1, &nrootdev); + if (dv != NULL) { + bootdv = dv; + nswapdev = nrootdev; + goto gotswap; + } + } + if (len == 4 && strncmp(buf, "exit", 4) == 0) + boot(RB_HALT); + dv = getdisk(buf, len, bp ? booted_partition : 0, + &nrootdev); + if (dv != NULL) { + bootdv = dv; + break; + } + } + + /* + * because swap must be on same device as root, for + * network devices this is easy. + */ + if (bootdv->dv_class == DV_IFNET) { + goto gotswap; + } + for (;;) { + printf("swap device "); + if (bootdv != NULL) + printf("(default %s%c)", + bootdv->dv_xname, + bootdv->dv_class == DV_DISK?'b':' '); + printf(": "); + len = getstr(buf, sizeof(buf)); + if (len == 0 && bootdv != NULL) { + switch (bootdv->dv_class) { + case DV_IFNET: + nswapdev = NODEV; + break; + case DV_DISK: + nswapdev = MAKEDISKDEV(major(nrootdev), + DISKUNIT(nrootdev), 1); + break; + case DV_TAPE: + case DV_TTY: + case DV_DULL: + case DV_CPU: + break; + } + break; + } + if (len == 4 && strncmp(buf, "exit", 4) == 0) + boot(RB_HALT); + dv = getdisk(buf, len, 1, &nswapdev); + if (dv) { + if (dv->dv_class == DV_IFNET) + nswapdev = NODEV; + break; + } + } +gotswap: + rootdev = nrootdev; + dumpdev = nswapdev; + swdevt[0].sw_dev = nswapdev; + swdevt[1].sw_dev = NODEV; + + } else if (mountroot == NULL) { + + /* + * `swap generic': Use the device the ROM told us to use. + */ + majdev = findblkmajor(bootdv); + if (majdev >= 0) { + /* + * Root and swap are on a disk. + * val[2] of the boot device is the partition number. + * Assume swap is on partition b. + */ + part = booted_partition; + unit = bootdv->dv_unit; + rootdev = MAKEDISKDEV(majdev, unit, part); + nswapdev = dumpdev = MAKEDISKDEV(major(rootdev), + DISKUNIT(rootdev), 1); + } else { + /* + * Root and swap are on a net. + */ + nswapdev = dumpdev = NODEV; + } + swdevt[0].sw_dev = nswapdev; + /* swdevt[1].sw_dev = NODEV; */ + + } else { + + /* + * `root DEV swap DEV': honour rootdev/swdevt. + * rootdev/swdevt/mountroot already properly set. + */ + if (bootdv->dv_class == DV_DISK) + printf("root on %s%c\n", bootdv->dv_xname, + part + 'a'); + majdev = major(rootdev); + unit = DISKUNIT(rootdev); + part = DISKPART(rootdev); + return; + } + + switch (bootdv->dv_class) { +#if defined(NFSCLIENT) + case DV_IFNET: + mountroot = nfs_mountroot; + nfsbootdevname = bootdv->dv_xname; + return; +#endif + case DV_DISK: + mountroot = dk_mountroot; + majdev = major(rootdev); + unit = DISKUNIT(rootdev); + part = DISKPART(rootdev); + printf("root on %s%c\n", bootdv->dv_xname, + part + 'a'); + break; + default: + printf("can't figure root, hope your kernel is right\n"); + return; + } + + /* + * Make the swap partition on the root drive the primary swap. + */ + temp = NODEV; + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (majdev == major(swp->sw_dev) && + unit == DISKUNIT(swp->sw_dev)) { + temp = swdevt[0].sw_dev; + swdevt[0].sw_dev = swp->sw_dev; + swp->sw_dev = temp; + break; + } + } + if (swp->sw_dev != NODEV) { + /* + * If dumpdev was the same as the old primary swap device, + * move it to the new primary swap device. + */ + if (temp == dumpdev) + dumpdev = swdevt[0].sw_dev; + } +} + +void +swapconf(void) +{ + struct swdevt *swp; + int nblks; + + for (swp = swdevt; swp->sw_dev != NODEV; swp++) { + if (bdevsw[major(swp->sw_dev)].d_psize) { + nblks = + (*bdevsw[major(swp->sw_dev)].d_psize)(swp->sw_dev); + if (nblks != -1 && + (swp->sw_nblks == 0 || swp->sw_nblks > nblks)) + swp->sw_nblks = nblks; + swp->sw_nblks = ctod(dtoc(swp->sw_nblks)); + } + } +} + +static struct device * +getdisk(str, len, defpart, devp) + char *str; + int len, defpart; + dev_t *devp; +{ + struct device *dv; + + if ((dv = parsedisk(str, len, defpart, devp)) == NULL) { + printf("use one of: exit"); +#ifdef RAMDISK_HOOKS + printf(" %s[a-p]", fakerdrootdev.dv_xname); +#endif + for (dv = alldevs.tqh_first; dv != NULL; + dv = dv->dv_list.tqe_next) { + if (dv->dv_class == DV_DISK) + printf(" %s[a-p]", dv->dv_xname); +#ifdef NFSCLIENT + if (dv->dv_class == DV_IFNET) + printf(" %s", dv->dv_xname); +#endif + } + printf("\n"); + } + return (dv); +} + +struct device * +parsedisk(str, len, defpart, devp) + char *str; + int len, defpart; + dev_t *devp; +{ + struct device *dv; + char *cp, c; + int majdev, unit, part; + + if (len == 0) + return (NULL); + cp = str + len - 1; + c = *cp; + if (c >= 'a' && (c - 'a') < MAXPARTITIONS) { + part = c - 'a'; + *cp = '\0'; + } else + part = defpart; + +#ifdef RAMDISK_HOOKS + if (strcmp(str, fakerdrootdev.dv_xname) == 0) { + dv = &fakerdrootdev; + goto gotdisk; + } +#endif + + for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) { + if (dv->dv_class == DV_DISK && + strcmp(str, dv->dv_xname) == 0) { +#ifdef RAMDISK_HOOKS +gotdisk: +#endif + majdev = findblkmajor(dv); + unit = dv->dv_unit; + if (majdev < 0) + panic("parsedisk"); + *devp = MAKEDISKDEV(majdev, unit, part); + break; + } +#ifdef NFSCLIENT + if (dv->dv_class == DV_IFNET && + strcmp(str, dv->dv_xname) == 0) { + *devp = NODEV; + break; + } +#endif + } + + *cp = c; + return (dv); +} + +static int +getstr(cp, size) + char *cp; + int size; +{ + char *lp; + int c; + int len; + + lp = cp; + len = 0; + for (;;) { + c = cngetc(); + switch (c) { + case '\n': + case '\r': + printf("\n"); + *lp++ = '\0'; + return (len); + case '\b': + case '\177': + case '#': + if (len) { + --len; + --lp; + printf("\b \b"); + } + continue; + case '@': + case 'u'&037: + len = 0; + lp = cp; + printf("\n"); + continue; + default: + if (len + 1 >= size || c < ' ') { + printf("\007"); + continue; + } + printf("%c", c); + ++len; + *lp++ = c; + } + } +} + +#include "pci.h" + +#include <dev/isa/isavar.h> +#if NPCI > 0 +#include <dev/pci/pcivar.h> +#endif + +void +device_register(struct device *dev, void *aux) +{ + /* + * Handle network interfaces here, the attachment information is + * not available driver independantly later. + * For disks, there is nothing useful available at attach time. + */ + if (dev->dv_class == DV_IFNET) { + struct btinfo_netif *bin = lookup_bootinfo(BTINFO_NETIF); + if (bin == NULL) + return; + + /* + * We don't check the driver name against the device name + * passed by the boot ROM. The ROM should stay usable + * if the driver gets obsoleted. + * The physical attachment information (checked below) + * must be sufficient to identify the device. + */ + + if (bin->bus == BI_BUS_ISA && + !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name, + "isa")) { + struct isa_attach_args *iaa = aux; + + /* compare IO base address */ + /* XXXJRT what about multiple I/O addrs? */ + if (iaa->ipa_nio > 0 && + bin->addr.iobase == iaa->ipa_io[0].base) + goto found; + } +#if NPCI > 0 + if (bin->bus == BI_BUS_PCI && + !strcmp(dev->dv_parent->dv_cfdata->cf_driver->cd_name, + "pci")) { + struct pci_attach_args *paa = aux; + int b, d, f; + + /* + * Calculate BIOS representation of: + * + * <bus,device,function> + * + * and compare. + */ + pci_decompose_tag(paa->pa_pc, paa->pa_tag, &b, &d, &f); + if (bin->addr.tag == ((b << 8) | (d << 3) | f)) + goto found; + } +#endif + } + return; + +found: + if (booted_device) { + /* XXX should be a "panic()" */ + printf("warning: double match for boot device (%s, %s)\n", + booted_device->dv_xname, dev->dv_xname); + return; + } + booted_device = dev; +} + +/* XXX */ +static struct nam2blk { + char *name; + int maj; +} nam2blk[] = { + { "wd", 0 }, /* 0 = wd */ + { "sd", 4 }, /* 2 = sd */ + { "raid", 19 }, /* 19 = raid */ +}; + +int +findblkmajor(struct device *dv) +{ + char *name = dv->dv_xname; + int i; + + for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); ++i) + if (strncmp(name, nam2blk[i].name, strlen(nam2blk[i].name)) == 0) + return (nam2blk[i].maj); + return (-1); +} + +char * +findblkname(maj) + int maj; +{ + int i; + + for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); i++) + if (nam2blk[i].maj == maj) + return (nam2blk[i].name); + return (NULL); +} diff --git a/sys/arch/amd64/amd64/bus_dma.c b/sys/arch/amd64/amd64/bus_dma.c new file mode 100644 index 00000000000..17863c33031 --- /dev/null +++ b/sys/arch/amd64/amd64/bus_dma.c @@ -0,0 +1,709 @@ +/* $NetBSD: bus_dma.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * 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. + */ + +#include <sys/cdefs.h> + +/* + * The following is included because _bus_dma_uiomove is derived from + * uiomove() in kern_subr.c. + */ + +/* + * Copyright (c) 1982, 1986, 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. + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/proc.h> + +#define _X86_BUS_DMA_PRIVATE +#include <machine/bus.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +#include <uvm/uvm_extern.h> + +#include "ioapic.h" + +#if NIOAPIC > 0 +#include <machine/i82093var.h> +#include <machine/mpbiosvar.h> +#endif + +extern paddr_t avail_end; + +int _bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, + struct proc *, int, paddr_t *, int *, int); + +#define IDTVEC(name) __CONCAT(X,name) +typedef void (vector)(void); +extern vector *IDTVEC(intr)[]; + +/* + * Common function for DMA map creation. May be called by bus-specific + * DMA map creation functions. + */ +int +_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp) + bus_dma_tag_t t; + bus_size_t size; + int nsegments; + bus_size_t maxsegsz; + bus_size_t boundary; + int flags; + bus_dmamap_t *dmamp; +{ + struct x86_bus_dmamap *map; + void *mapstore; + size_t mapsize; + + /* + * Allocate and initialize the DMA map. The end of the map + * is a variable-sized array of segments, so we allocate enough + * room for them in one shot. + * + * Note we don't preserve the WAITOK or NOWAIT flags. Preservation + * of ALLOCNOW notifies others that we've reserved these resources, + * and they are not to be freed. + * + * The bus_dmamap_t includes one bus_dma_segment_t, hence + * the (nsegments - 1). + */ + mapsize = sizeof(struct x86_bus_dmamap) + + (sizeof(bus_dma_segment_t) * (nsegments - 1)); + if ((mapstore = malloc(mapsize, M_DEVBUF, + (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) + return (ENOMEM); + + bzero(mapstore, mapsize); + map = (struct x86_bus_dmamap *)mapstore; + map->_dm_size = size; + map->_dm_segcnt = nsegments; + map->_dm_maxsegsz = maxsegsz; + map->_dm_boundary = boundary; + map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT); + map->dm_mapsize = 0; /* no valid mappings */ + map->dm_nsegs = 0; + + *dmamp = map; + return (0); +} + +/* + * Common function for DMA map destruction. May be called by bus-specific + * DMA map destruction functions. + */ +void +_bus_dmamap_destroy(t, map) + bus_dma_tag_t t; + bus_dmamap_t map; +{ + + free(map, M_DEVBUF); +} + +/* + * Common function for loading a DMA map with a linear buffer. May + * be called by bus-specific DMA map load functions. + */ +int +_bus_dmamap_load(t, map, buf, buflen, p, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + void *buf; + bus_size_t buflen; + struct proc *p; + int flags; +{ + bus_addr_t lastaddr; + int seg, error; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + if (buflen > map->_dm_size) + return (EINVAL); + + seg = 0; + error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, + &lastaddr, &seg, 1); + if (error == 0) { + map->dm_mapsize = buflen; + map->dm_nsegs = seg + 1; + } + return (error); +} + +/* + * Like _bus_dmamap_load(), but for mbufs. + */ +int +_bus_dmamap_load_mbuf(t, map, m0, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + struct mbuf *m0; + int flags; +{ + paddr_t lastaddr; + int seg, error, first; + struct mbuf *m; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + +#ifdef DIAGNOSTIC + if ((m0->m_flags & M_PKTHDR) == 0) + panic("_bus_dmamap_load_mbuf: no packet header"); +#endif + + if (m0->m_pkthdr.len > map->_dm_size) + return (EINVAL); + + first = 1; + seg = 0; + error = 0; + for (m = m0; m != NULL && error == 0; m = m->m_next) { + error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len, + NULL, flags, &lastaddr, &seg, first); + first = 0; + } + if (error == 0) { + map->dm_mapsize = m0->m_pkthdr.len; + map->dm_nsegs = seg + 1; + } + return (error); +} + +/* + * Like _bus_dmamap_load(), but for uios. + */ +int +_bus_dmamap_load_uio(t, map, uio, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + struct uio *uio; + int flags; +{ + paddr_t lastaddr; + int seg, i, error, first; + bus_size_t minlen, resid; + struct proc *p = NULL; + struct iovec *iov; + caddr_t addr; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + resid = uio->uio_resid; + iov = uio->uio_iov; + + if (uio->uio_segflg == UIO_USERSPACE) { + p = uio->uio_procp; +#ifdef DIAGNOSTIC + if (p == NULL) + panic("_bus_dmamap_load_uio: USERSPACE but no proc"); +#endif + } + + first = 1; + seg = 0; + error = 0; + for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { + /* + * Now at the first iovec to load. Load each iovec + * until we have exhausted the residual count. + */ + minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len; + addr = (caddr_t)iov[i].iov_base; + + error = _bus_dmamap_load_buffer(t, map, addr, minlen, + p, flags, &lastaddr, &seg, first); + first = 0; + + resid -= minlen; + } + if (error == 0) { + map->dm_mapsize = uio->uio_resid; + map->dm_nsegs = seg + 1; + } + return (error); +} + +/* + * Like _bus_dmamap_load(), but for raw memory allocated with + * bus_dmamem_alloc(). + */ +int +_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + bus_dma_segment_t *segs; + int nsegs; + bus_size_t size; + int flags; +{ + if (nsegs > map->_dm_segcnt || size > map->_dm_size) + return (EINVAL); + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary) { + bus_addr_t bmask = ~(map->_dm_boundary - 1); + int i; + + for (i = 0; i < nsegs; i++) { + if (segs[i].ds_len > map->_dm_maxsegsz) + return (EINVAL); + if ((segs[i].ds_addr & bmask) != + ((segs[i].ds_addr + segs[i].ds_len - 1) & bmask)) + return (EINVAL); + } + } + + bcopy(segs, map->dm_segs, nsegs * sizeof(*segs)); + map->dm_nsegs = nsegs; + return (0); +} + +/* + * Common function for unloading a DMA map. May be called by + * bus-specific DMA map unload functions. + */ +void +_bus_dmamap_unload(t, map) + bus_dma_tag_t t; + bus_dmamap_t map; +{ + + /* + * No resources to free; just mark the mappings as + * invalid. + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; +} + +/* + * Common function for DMA map synchronization. May be called + * by bus-specific DMA map synchronization functions. + */ +void +_bus_dmamap_sync(t, map, addr, size, op) + bus_dma_tag_t t; + bus_dmamap_t map; + bus_addr_t addr; + bus_size_t size; + int op; +{ + + /* Nothing to do here. */ +} + +/* + * Common function for DMA-safe memory allocation. May be called + * by bus-specific DMA memory allocation functions. + */ +int +_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags) + bus_dma_tag_t t; + bus_size_t size, alignment, boundary; + bus_dma_segment_t *segs; + int nsegs; + int *rsegs; + int flags; +{ + + return (_bus_dmamem_alloc_range(t, size, alignment, boundary, + segs, nsegs, rsegs, flags, 0, trunc_page(avail_end))); +} + +/* + * Common function for freeing DMA-safe memory. May be called by + * bus-specific DMA memory free functions. + */ +void +_bus_dmamem_free(t, segs, nsegs) + bus_dma_tag_t t; + bus_dma_segment_t *segs; + int nsegs; +{ + struct vm_page *m; + bus_addr_t addr; + struct pglist mlist; + int curseg; + + /* + * Build a list of pages to free back to the VM system. + */ + TAILQ_INIT(&mlist); + for (curseg = 0; curseg < nsegs; curseg++) { + for (addr = segs[curseg].ds_addr; + addr < (segs[curseg].ds_addr + segs[curseg].ds_len); + addr += PAGE_SIZE) { + m = PHYS_TO_VM_PAGE(addr); + TAILQ_INSERT_TAIL(&mlist, m, pageq); + } + } + + uvm_pglistfree(&mlist); +} + +/* + * Common function for mapping DMA-safe memory. May be called by + * bus-specific DMA memory map functions. + */ +int +_bus_dmamem_map(t, segs, nsegs, size, kvap, flags) + bus_dma_tag_t t; + bus_dma_segment_t *segs; + int nsegs; + size_t size; + caddr_t *kvap; + int flags; +{ + vaddr_t va; + bus_addr_t addr; + int curseg; + + size = round_page(size); + va = uvm_km_valloc(kernel_map, size); + if (va == 0) + return (ENOMEM); + + *kvap = (caddr_t)va; + + for (curseg = 0; curseg < nsegs; curseg++) { + for (addr = segs[curseg].ds_addr; + addr < (segs[curseg].ds_addr + segs[curseg].ds_len); + addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) { + if (size == 0) + panic("_bus_dmamem_map: size botch"); + pmap_enter(pmap_kernel(), va, addr, + VM_PROT_READ | VM_PROT_WRITE, + VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED); + } + } + pmap_update(pmap_kernel()); + + return (0); +} + +/* + * Common function for unmapping DMA-safe memory. May be called by + * bus-specific DMA memory unmapping functions. + */ +void +_bus_dmamem_unmap(t, kva, size) + bus_dma_tag_t t; + caddr_t kva; + size_t size; +{ + +#ifdef DIAGNOSTIC + if ((u_long)kva & PGOFSET) + panic("_bus_dmamem_unmap"); +#endif + + size = round_page(size); + uvm_km_free(kernel_map, (vaddr_t)kva, size); +} + +/* + * Common functin for mmap(2)'ing DMA-safe memory. May be called by + * bus-specific DMA mmap(2)'ing functions. + */ +paddr_t +_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags) + bus_dma_tag_t t; + bus_dma_segment_t *segs; + int nsegs; + off_t off; + int prot, flags; +{ + int i; + + for (i = 0; i < nsegs; i++) { +#ifdef DIAGNOSTIC + if (off & PGOFSET) + panic("_bus_dmamem_mmap: offset unaligned"); + if (segs[i].ds_addr & PGOFSET) + panic("_bus_dmamem_mmap: segment unaligned"); + if (segs[i].ds_len & PGOFSET) + panic("_bus_dmamem_mmap: segment size not multiple" + " of page size"); +#endif + if (off >= segs[i].ds_len) { + off -= segs[i].ds_len; + continue; + } + + return (x86_btop((caddr_t)segs[i].ds_addr + off)); + } + + /* Page not found. */ + return (-1); +} + +/********************************************************************** + * DMA utility functions + **********************************************************************/ +/* + * Utility function to load a linear buffer. lastaddrp holds state + * between invocations (for multiple-buffer loads). segp contains + * the starting segment on entrace, and the ending segment on exit. + * first indicates if this is the first invocation of this function. + */ +int +_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first) + bus_dma_tag_t t; + bus_dmamap_t map; + void *buf; + bus_size_t buflen; + struct proc *p; + int flags; + paddr_t *lastaddrp; + int *segp; + int first; +{ + bus_size_t sgsize; + bus_addr_t curaddr, lastaddr, baddr, bmask; + vaddr_t vaddr = (vaddr_t)buf; + int seg; + pmap_t pmap; + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + lastaddr = *lastaddrp; + bmask = ~(map->_dm_boundary - 1); + + for (seg = *segp; buflen > 0 ; ) { + /* + * Get the physical address for this segment. + */ + pmap_extract(pmap, vaddr, (paddr_t *)&curaddr); + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET); + if (buflen < sgsize) + sgsize = buflen; + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary > 0) { + baddr = (curaddr + map->_dm_boundary) & bmask; + if (sgsize > (baddr - curaddr)) + sgsize = (baddr - curaddr); + } + + /* + * Insert chunk into a segment, coalescing with + * previous segment if possible. + */ + if (first) { + map->dm_segs[seg].ds_addr = curaddr; + map->dm_segs[seg].ds_len = sgsize; + first = 0; + } else { + if (curaddr == lastaddr && + (map->dm_segs[seg].ds_len + sgsize) <= + map->_dm_maxsegsz && + (map->_dm_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + (curaddr & bmask))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + break; + map->dm_segs[seg].ds_addr = curaddr; + map->dm_segs[seg].ds_len = sgsize; + } + } + + lastaddr = curaddr + sgsize; + vaddr += sgsize; + buflen -= sgsize; + } + + *segp = seg; + *lastaddrp = lastaddr; + + /* + * Did we fit? + */ + if (buflen != 0) + return (EFBIG); /* XXX better return value here? */ + return (0); +} + +/* + * Allocate physical memory from the given physical address range. + * Called by DMA-safe memory allocation methods. + */ +int +_bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs, + flags, low, high) + bus_dma_tag_t t; + bus_size_t size, alignment, boundary; + bus_dma_segment_t *segs; + int nsegs; + int *rsegs; + int flags; + paddr_t low; + paddr_t high; +{ + paddr_t curaddr, lastaddr; + struct vm_page *m; + struct pglist mlist; + int curseg, error; + + /* Always round the size. */ + size = round_page(size); + + /* + * Allocate pages from the VM system. + */ + TAILQ_INIT(&mlist); + error = uvm_pglistalloc(size, low, high, + alignment, boundary, &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0); + if (error) + return (error); + + /* + * Compute the location, size, and number of segments actually + * returned by the VM code. + */ + m = TAILQ_FIRST(&mlist); + curseg = 0; + lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m); + segs[curseg].ds_len = PAGE_SIZE; + + for (m = TAILQ_NEXT(m, pageq); m != NULL; m = TAILQ_NEXT(m, pageq)) { + curaddr = VM_PAGE_TO_PHYS(m); +#ifdef DIAGNOSTIC + if (curseg == nsegs) { + printf("uvm_pglistalloc returned too many\n"); + panic("_bus_dmamem_alloc_range"); + } + if (curaddr < low || curaddr >= high) { + printf("uvm_pglistalloc returned non-sensical" + " address 0x%lx\n", curaddr); + panic("_bus_dmamem_alloc_range"); + } +#endif + if (curaddr == (lastaddr + PAGE_SIZE)) + segs[curseg].ds_len += PAGE_SIZE; + else { + curseg++; + segs[curseg].ds_addr = curaddr; + segs[curseg].ds_len = PAGE_SIZE; + } + lastaddr = curaddr; + } + + *rsegs = curseg + 1; + + return (0); +} + diff --git a/sys/arch/amd64/amd64/bus_space.c b/sys/arch/amd64/amd64/bus_space.c new file mode 100644 index 00000000000..a99b33dcd7c --- /dev/null +++ b/sys/arch/amd64/amd64/bus_space.c @@ -0,0 +1,473 @@ +/* $OpenBSD: bus_space.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: bus_space.c,v 1.2 2003/03/14 18:47:53 christos Exp $ */ + +/*- + * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/extent.h> + +#include <uvm/uvm_extern.h> + +#define _X86_BUS_DMA_PRIVATE +#include <machine/bus.h> + +#include <dev/isa/isareg.h> +#include <machine/isa_machdep.h> + +/* + * Extent maps to manage I/O and memory space. Allocate + * storage for 8 regions in each, initially. Later, ioport_malloc_safe + * will indicate that it's safe to use malloc() to dynamically allocate + * region descriptors. + * + * N.B. At least two regions are _always_ allocated from the iomem + * extent map; (0 -> ISA hole) and (end of ISA hole -> end of RAM). + * + * The extent maps are not static! Machine-dependent ISA and EISA + * routines need access to them for bus address space allocation. + */ +static long ioport_ex_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof(long)]; +static long iomem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(8) / sizeof(long)]; +struct extent *ioport_ex; +struct extent *iomem_ex; +static int ioport_malloc_safe; + +int x86_mem_add_mapping(bus_addr_t, bus_size_t, + int, bus_space_handle_t *); + +void +x86_bus_space_init() +{ + /* + * Initialize the I/O port and I/O mem extent maps. + * Note: we don't have to check the return value since + * creation of a fixed extent map will never fail (since + * descriptor storage has already been allocated). + * + * N.B. The iomem extent manages _all_ physical addresses + * on the machine. When the amount of RAM is found, the two + * extents of RAM are allocated from the map (0 -> ISA hole + * and end of ISA hole -> end of RAM). + */ + ioport_ex = extent_create("ioport", 0x0, 0xffff, M_DEVBUF, + (caddr_t)ioport_ex_storage, sizeof(ioport_ex_storage), + EX_NOCOALESCE|EX_NOWAIT); + iomem_ex = extent_create("iomem", 0x0, 0xffffffff, M_DEVBUF, + (caddr_t)iomem_ex_storage, sizeof(iomem_ex_storage), + EX_NOCOALESCE|EX_NOWAIT); +} + +void +x86_bus_space_mallocok() +{ + + ioport_malloc_safe = 1; +} + +int +x86_memio_map(t, bpa, size, flags, bshp) + bus_space_tag_t t; + bus_addr_t bpa; + bus_size_t size; + int flags; + bus_space_handle_t *bshp; +{ + int error; + struct extent *ex; + + /* + * Pick the appropriate extent map. + */ + if (t == X86_BUS_SPACE_IO) { + ex = ioport_ex; + } else if (t == X86_BUS_SPACE_MEM) + ex = iomem_ex; + else + panic("x86_memio_map: bad bus space tag"); + + /* + * Before we go any further, let's make sure that this + * region is available. + */ + error = extent_alloc_region(ex, bpa, size, + EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0)); + if (error) + return (error); + + /* + * For I/O space, that's all she wrote. + */ + if (t == X86_BUS_SPACE_IO) { + *bshp = bpa; + return (0); + } + + if (bpa >= IOM_BEGIN && (bpa + size) <= IOM_END) { + *bshp = (bus_space_handle_t)ISA_HOLE_VADDR(bpa); + return(0); + } + + /* + * For memory space, map the bus physical address to + * a kernel virtual address. + */ + error = x86_mem_add_mapping(bpa, size, 0, bshp); + if (error) { + if (extent_free(ex, bpa, size, EX_NOWAIT | + (ioport_malloc_safe ? EX_MALLOCOK : 0))) { + printf("x86_memio_map: pa 0x%lx, size 0x%lx\n", + bpa, size); + printf("x86_memio_map: can't free region\n"); + } + } + + return (error); +} + +int +_x86_memio_map(t, bpa, size, flags, bshp) + bus_space_tag_t t; + bus_addr_t bpa; + bus_size_t size; + int flags; + bus_space_handle_t *bshp; +{ + + /* + * For I/O space, just fill in the handle. + */ + if (t == X86_BUS_SPACE_IO) { + *bshp = bpa; + return (0); + } + + /* + * For memory space, map the bus physical address to + * a kernel virtual address. + */ + return (x86_mem_add_mapping(bpa, size, 0, bshp)); +} + +int +x86_memio_alloc(t, rstart, rend, size, alignment, boundary, flags, + bpap, bshp) + bus_space_tag_t t; + bus_addr_t rstart, rend; + bus_size_t size, alignment, boundary; + int flags; + bus_addr_t *bpap; + bus_space_handle_t *bshp; +{ + struct extent *ex; + u_long bpa; + int error; + + /* + * Pick the appropriate extent map. + */ + if (t == X86_BUS_SPACE_IO) { + ex = ioport_ex; + } else if (t == X86_BUS_SPACE_MEM) + ex = iomem_ex; + else + panic("x86_memio_alloc: bad bus space tag"); + + /* + * Sanity check the allocation against the extent's boundaries. + */ + if (rstart < ex->ex_start || rend > ex->ex_end) + panic("x86_memio_alloc: bad region start/end"); + + /* + * Do the requested allocation. + */ + error = extent_alloc_subregion(ex, rstart, rend, size, alignment, + 0, boundary, + EX_FAST | EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0), + &bpa); + + if (error) + return (error); + + /* + * For I/O space, that's all she wrote. + */ + if (t == X86_BUS_SPACE_IO) { + *bshp = *bpap = bpa; + return (0); + } + + /* + * For memory space, map the bus physical address to + * a kernel virtual address. + */ + error = x86_mem_add_mapping(bpa, size, 0, bshp); + if (error) { + if (extent_free(iomem_ex, bpa, size, EX_NOWAIT | + (ioport_malloc_safe ? EX_MALLOCOK : 0))) { + printf("x86_memio_alloc: pa 0x%lx, size 0x%lx\n", + bpa, size); + printf("x86_memio_alloc: can't free region\n"); + } + } + + *bpap = bpa; + + return (error); +} + +int +x86_mem_add_mapping(bpa, size, cacheable, bshp) + bus_addr_t bpa; + bus_size_t size; + int cacheable; + bus_space_handle_t *bshp; +{ + u_long pa, endpa; + vaddr_t va; + pt_entry_t *pte; + int32_t cpumask = 0; + + pa = x86_trunc_page(bpa); + endpa = x86_round_page(bpa + size); + +#ifdef DIAGNOSTIC + if (endpa <= pa) + panic("x86_mem_add_mapping: overflow"); +#endif + + va = uvm_km_valloc(kernel_map, endpa - pa); + if (va == 0) + return (ENOMEM); + + *bshp = (bus_space_handle_t)(va + (bpa & PGOFSET)); + + for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) { + pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE); + + /* + * PG_N doesn't exist on 386's, so we assume that + * the mainboard has wired up device space non-cacheable + * on those machines. + * + * Note that it's not necessary to use atomic ops to + * fiddle with the PTE here, because we don't care + * about mod/ref information. + * + * XXX should hand this bit to pmap_kenter_pa to + * save the extra invalidate! + * + * XXX extreme paranoia suggests tlb shootdown belongs here. + */ + if (pmap_cpu_has_pg_n()) { + pte = kvtopte(va); + if (cacheable) + *pte &= ~PG_N; + else + *pte |= PG_N; + pmap_tlb_shootdown(pmap_kernel(), va, *pte, + &cpumask); + } + } + + pmap_tlb_shootnow(cpumask); + pmap_update(pmap_kernel()); + + return 0; +} + +/* + * void _x86_memio_unmap(bus_space_tag bst, bus_space_handle bsh, + * bus_size_t size, bus_addr_t *adrp) + * + * This function unmaps memory- or io-space mapped by the function + * _x86_memio_map(). This function works nearly as same as + * x86_memio_unmap(), but this function does not ask kernel + * built-in extents and returns physical address of the bus space, + * for the convenience of the extra extent manager. + */ +void +_x86_memio_unmap(t, bsh, size, adrp) + bus_space_tag_t t; + bus_space_handle_t bsh; + bus_size_t size; + bus_addr_t *adrp; +{ + u_long va, endva; + bus_addr_t bpa; + + /* + * Find the correct extent and bus physical address. + */ + if (t == X86_BUS_SPACE_IO) { + bpa = bsh; + } else if (t == X86_BUS_SPACE_MEM) { + if (bsh >= atdevbase && (bsh + size) <= (atdevbase + IOM_SIZE)) { + bpa = (bus_addr_t)ISA_PHYSADDR(bsh); + } else { + + va = x86_trunc_page(bsh); + endva = x86_round_page(bsh + size); + +#ifdef DIAGNOSTIC + if (endva <= va) { + panic("_x86_memio_unmap: overflow"); + } +#endif + + if (pmap_extract(pmap_kernel(), va, &bpa) == FALSE) { + panic("_x86_memio_unmap:" + " wrong virtual address"); + } + bpa += (bsh & PGOFSET); + + pmap_kremove(va, endva - va); + /* + * Free the kernel virtual mapping. + */ + uvm_km_free(kernel_map, va, endva - va); + } + } else { + panic("_x86_memio_unmap: bad bus space tag"); + } + + if (adrp != NULL) { + *adrp = bpa; + } +} + +void +x86_memio_unmap(t, bsh, size) + bus_space_tag_t t; + bus_space_handle_t bsh; + bus_size_t size; +{ + struct extent *ex; + u_long va, endva; + bus_addr_t bpa; + + /* + * Find the correct extent and bus physical address. + */ + if (t == X86_BUS_SPACE_IO) { + ex = ioport_ex; + bpa = bsh; + } else if (t == X86_BUS_SPACE_MEM) { + ex = iomem_ex; + + if (bsh >= atdevbase && + (bsh + size) <= (atdevbase + IOM_SIZE)) { + bpa = (bus_addr_t)ISA_PHYSADDR(bsh); + goto ok; + } + + va = x86_trunc_page(bsh); + endva = x86_round_page(bsh + size); + +#ifdef DIAGNOSTIC + if (endva <= va) + panic("x86_memio_unmap: overflow"); +#endif + + (void) pmap_extract(pmap_kernel(), va, &bpa); + bpa += (bsh & PGOFSET); + + pmap_kremove(va, endva - va); + /* + * Free the kernel virtual mapping. + */ + uvm_km_free(kernel_map, va, endva - va); + } else + panic("x86_memio_unmap: bad bus space tag"); + +ok: + if (extent_free(ex, bpa, size, + EX_NOWAIT | (ioport_malloc_safe ? EX_MALLOCOK : 0))) { + printf("x86_memio_unmap: %s 0x%lx, size 0x%lx\n", + (t == X86_BUS_SPACE_IO) ? "port" : "pa", bpa, size); + printf("x86_memio_unmap: can't free region\n"); + } +} + +void +x86_memio_free(t, bsh, size) + bus_space_tag_t t; + bus_space_handle_t bsh; + bus_size_t size; +{ + + /* x86_memio_unmap() does all that we need to do. */ + x86_memio_unmap(t, bsh, size); +} + +int +x86_memio_subregion(t, bsh, offset, size, nbshp) + bus_space_tag_t t; + bus_space_handle_t bsh; + bus_size_t offset, size; + bus_space_handle_t *nbshp; +{ + + *nbshp = bsh + offset; + return (0); +} + +paddr_t +x86_memio_mmap(t, addr, off, prot, flags) + bus_space_tag_t t; + bus_addr_t addr; + off_t off; + int prot; + int flags; +{ + + /* Can't mmap I/O space. */ + if (t == X86_BUS_SPACE_IO) + return (-1); + + /* + * "addr" is the base address of the device we're mapping. + * "off" is the offset into that device. + * + * Note we are called for each "page" in the device that + * the upper layers want to map. + */ + return (x86_btop(addr + off)); +} diff --git a/sys/arch/amd64/amd64/cacheinfo.c b/sys/arch/amd64/amd64/cacheinfo.c new file mode 100644 index 00000000000..813825c4d44 --- /dev/null +++ b/sys/arch/amd64/amd64/cacheinfo.c @@ -0,0 +1,237 @@ +#include <sys/param.h> +#include <sys/systm.h> + +#include <machine/cpu.h> +#include <machine/specialreg.h> + +static char *print_cache_config(struct cpu_info *, int, char *, char *); +static char *print_tlb_config(struct cpu_info *, int, char *, char *); + +static char * +print_cache_config(struct cpu_info *ci, int cache_tag, char *name, char *sep) +{ + struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag]; + + if (cai->cai_totalsize == 0) + return sep; + + if (sep == NULL) + printf("%s: ", ci->ci_dev->dv_xname); + else + printf("%s", sep); + if (name != NULL) + printf("%s ", name); + + if (cai->cai_string != NULL) { + printf("%s ", cai->cai_string); + } else { + printf("%d %db/line ", cai->cai_totalsize, cai->cai_linesize); + } + switch (cai->cai_associativity) { + case 0: + printf("disabled"); + break; + case 1: + printf("direct-mapped"); + break; + case 0xff: + printf("fully associative"); + break; + default: + printf("%d-way", cai->cai_associativity); + break; + } + return ", "; +} + +static char * +print_tlb_config(struct cpu_info *ci, int cache_tag, char *name, char *sep) +{ + struct x86_cache_info *cai = &ci->ci_cinfo[cache_tag]; + + if (cai->cai_totalsize == 0) + return sep; + + if (sep == NULL) + printf("%s: ", ci->ci_dev->dv_xname); + else + printf("%s", sep); + if (name != NULL) + printf("%s ", name); + + if (cai->cai_string != NULL) { + printf("%s", cai->cai_string); + } else { + printf("%d %d entries ", cai->cai_totalsize, cai->cai_linesize); + switch (cai->cai_associativity) { + case 0: + printf("disabled"); + break; + case 1: + printf("direct-mapped"); + break; + case 0xff: + printf("fully associative"); + break; + default: + printf("%d-way", cai->cai_associativity); + break; + } + } + return ", "; +} + +const struct x86_cache_info * +cache_info_lookup(const struct x86_cache_info *cai, u_int8_t desc) +{ + int i; + + for (i = 0; cai[i].cai_desc != 0; i++) { + if (cai[i].cai_desc == desc) + return (&cai[i]); + } + + return (NULL); +} + + +static const struct x86_cache_info amd_cpuid_l2cache_assoc_info[] = { + { 0, 0x01, 1 }, + { 0, 0x02, 2 }, + { 0, 0x04, 4 }, + { 0, 0x06, 8 }, + { 0, 0x08, 16 }, + { 0, 0x0f, 0xff }, + { 0, 0x00, 0 }, +}; + +void +amd_cpu_cacheinfo(struct cpu_info *ci) +{ + const struct x86_cache_info *cp; + struct x86_cache_info *cai; + int family, model; + u_int descs[4]; + u_int lfunc; + + family = (ci->ci_signature >> 8) & 15; + model = CPUID2MODEL(ci->ci_signature); + + /* + * K5 model 0 has none of this info. + */ + if (family == 5 && model == 0) + return; + + /* + * Get extended values for K8 and up. + */ + if (family == 0xf) { + family += (ci->ci_signature >> 20) & 0xff; + model += (ci->ci_signature >> 16) & 0xf; + } + + /* + * Determine the largest extended function value. + */ + CPUID(0x80000000, descs[0], descs[1], descs[2], descs[3]); + lfunc = descs[0]; + + /* + * Determine L1 cache/TLB info. + */ + if (lfunc < 0x80000005) { + /* No L1 cache info available. */ + return; + } + + CPUID(0x80000005, descs[0], descs[1], descs[2], descs[3]); + + /* + * K6-III and higher have large page TLBs. + */ + if ((family == 5 && model >= 9) || family >= 6) { + cai = &ci->ci_cinfo[CAI_ITLB2]; + cai->cai_totalsize = AMD_L1_EAX_ITLB_ENTRIES(descs[0]); + cai->cai_associativity = AMD_L1_EAX_ITLB_ASSOC(descs[0]); + cai->cai_linesize = (4 * 1024 * 1024); + + cai = &ci->ci_cinfo[CAI_DTLB2]; + cai->cai_totalsize = AMD_L1_EAX_DTLB_ENTRIES(descs[0]); + cai->cai_associativity = AMD_L1_EAX_DTLB_ASSOC(descs[0]); + cai->cai_linesize = (4 * 1024 * 1024); + } + + cai = &ci->ci_cinfo[CAI_ITLB]; + cai->cai_totalsize = AMD_L1_EBX_ITLB_ENTRIES(descs[1]); + cai->cai_associativity = AMD_L1_EBX_ITLB_ASSOC(descs[1]); + cai->cai_linesize = (4 * 1024); + + cai = &ci->ci_cinfo[CAI_DTLB]; + cai->cai_totalsize = AMD_L1_EBX_DTLB_ENTRIES(descs[1]); + cai->cai_associativity = AMD_L1_EBX_DTLB_ASSOC(descs[1]); + cai->cai_linesize = (4 * 1024); + + cai = &ci->ci_cinfo[CAI_DCACHE]; + cai->cai_totalsize = AMD_L1_ECX_DC_SIZE(descs[2]); + cai->cai_associativity = AMD_L1_ECX_DC_ASSOC(descs[2]); + cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[2]); + + cai = &ci->ci_cinfo[CAI_ICACHE]; + cai->cai_totalsize = AMD_L1_EDX_IC_SIZE(descs[3]); + cai->cai_associativity = AMD_L1_EDX_IC_ASSOC(descs[3]); + cai->cai_linesize = AMD_L1_EDX_IC_LS(descs[3]); + + /* + * Determine L2 cache/TLB info. + */ + if (lfunc < 0x80000006) { + /* No L2 cache info available. */ + return; + } + + CPUID(0x80000006, descs[0], descs[1], descs[2], descs[3]); + + cai = &ci->ci_cinfo[CAI_L2CACHE]; + cai->cai_totalsize = AMD_L2_ECX_C_SIZE(descs[2]); + cai->cai_associativity = AMD_L2_ECX_C_ASSOC(descs[2]); + cai->cai_linesize = AMD_L2_ECX_C_LS(descs[2]); + + cp = cache_info_lookup(amd_cpuid_l2cache_assoc_info, + cai->cai_associativity); + if (cp != NULL) + cai->cai_associativity = cp->cai_associativity; + else + cai->cai_associativity = 0; /* XXX Unknown/reserved */ +} + +void +x86_print_cacheinfo(struct cpu_info *ci) +{ + char *sep; + + if (ci->ci_cinfo[CAI_ICACHE].cai_totalsize != 0 || + ci->ci_cinfo[CAI_DCACHE].cai_totalsize != 0) { + sep = print_cache_config(ci, CAI_ICACHE, "I-cache", NULL); + sep = print_cache_config(ci, CAI_DCACHE, "D-cache", sep); + if (sep != NULL) + printf("\n"); + } + if (ci->ci_cinfo[CAI_L2CACHE].cai_totalsize != 0) { + sep = print_cache_config(ci, CAI_L2CACHE, "L2 cache", NULL); + if (sep != NULL) + printf("\n"); + } + if (ci->ci_cinfo[CAI_ITLB].cai_totalsize != 0) { + sep = print_tlb_config(ci, CAI_ITLB, "ITLB", NULL); + sep = print_tlb_config(ci, CAI_ITLB2, NULL, sep); + if (sep != NULL) + printf("\n"); + } + if (ci->ci_cinfo[CAI_DTLB].cai_totalsize != 0) { + sep = print_tlb_config(ci, CAI_DTLB, "DTLB", NULL); + sep = print_tlb_config(ci, CAI_DTLB2, NULL, sep); + if (sep != NULL) + printf("\n"); + } +} diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c new file mode 100644 index 00000000000..cb6c91516c1 --- /dev/null +++ b/sys/arch/amd64/amd64/conf.c @@ -0,0 +1,455 @@ +/* $OpenBSD: conf.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ + +/* + * Copyright (c) 1994, 1995 Charles M. Hannum. 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 Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/vnode.h> + +#include <machine/conf.h> + +#include "inet.h" + +#include "wd.h" +bdev_decl(wd); +#include "fdc.h" +#include "fd.h" +bdev_decl(fd); +#include "wt.h" +bdev_decl(wt); +#include "sd.h" +#include "ses.h" +#include "st.h" +#include "cd.h" +#include "uk.h" +#include "mcd.h" +bdev_decl(mcd); +#include "vnd.h" +#include "ccd.h" +#include "raid.h" +#include "rd.h" + +struct bdevsw bdevsw[] = +{ + bdev_disk_init(NWD,wd), /* 0: ST506/ESDI/IDE disk */ + bdev_swap_init(1,sw), /* 1: swap pseudo-device */ + bdev_disk_init(NFD,fd), /* 2: floppy diskette */ + bdev_tape_init(NWT,wt), /* 3: QIC-02/QIC-36 tape */ + bdev_disk_init(NSD,sd), /* 4: SCSI disk */ + bdev_tape_init(NST,st), /* 5: SCSI tape */ + bdev_disk_init(NCD,cd), /* 6: SCSI CD-ROM */ + bdev_disk_init(NMCD,mcd), /* 7: Mitsumi CD-ROM */ + bdev_lkm_dummy(), /* 8 */ + bdev_lkm_dummy(), /* 9 */ + bdev_lkm_dummy(), /* 10 */ + bdev_lkm_dummy(), /* 11 */ + bdev_lkm_dummy(), /* 12 */ + bdev_lkm_dummy(), /* 13 */ + bdev_disk_init(NVND,vnd), /* 14: vnode disk driver */ + bdev_lkm_dummy(), /* 15: Sony CD-ROM */ + bdev_disk_init(NCCD,ccd), /* 16: concatenated disk driver */ + bdev_disk_init(NRD,rd), /* 17: ram disk driver */ + bdev_lkm_dummy(), /* 18 */ + bdev_disk_init(NRAID,raid), /* 19: RAIDframe disk driver */ +}; +int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]); + +/* open, close, read, write, ioctl, tty, mmap */ +#define cdev_pc_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \ + dev_init(c,n,write), dev_init(c,n,ioctl), dev_init(c,n,stop), \ + dev_init(c,n,tty), ttselect, dev_init(c,n,mmap), D_TTY } + +/* open, close, read, ioctl */ +#define cdev_joy_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, seltrue, \ + (dev_type_mmap((*))) enodev } + +/* open, close, ioctl -- XXX should be a generic device */ +#define cdev_oci_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, seltrue, \ + (dev_type_mmap((*))) enodev, 0 } + +/* open, close, ioctl, select -- XXX should be a generic device */ +#define cdev_ocis_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, dev_init(c,n,select), \ + (dev_type_mmap((*))) enodev, 0 } + +/* open, close, read, ioctl */ +#define cdev_wdt_init(c, n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, seltrue, (dev_type_mmap((*))) enodev } + + +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); +cdev_decl(wd); +#include "systrace.h" +#include "bio.h" +#include "pty.h" +#include "com.h" +cdev_decl(com); +cdev_decl(fd); +cdev_decl(wt); +cdev_decl(scd); +#include "ss.h" +#include "lpt.h" +cdev_decl(lpt); +#include "ch.h" +#include "bpfilter.h" +#if 0 +#include "pcmcia.h" +cdev_decl(pcmcia); +#endif +#include "spkr.h" +cdev_decl(spkr); +#if 0 /* old (non-wsmouse) drivers */ +#include "mms.h" +cdev_decl(mms); +#include "lms.h" +cdev_decl(lms); +#include "opms.h" +cdev_decl(pms); +#endif +#include "cy.h" +cdev_decl(cy); +cdev_decl(mcd); +#include "tun.h" +#include "audio.h" +#include "midi.h" +#include "sequencer.h" +cdev_decl(music); +#include "iop.h" +#ifdef XFS +#include <xfs/nxfs.h> +cdev_decl(xfs_dev); +#endif +#include "bktr.h" +#include "wdt.h" +cdev_decl(wdt); +#include "ksyms.h" +#include "usb.h" +#include "uhid.h" +#include "ugen.h" +#include "ulpt.h" +#include "urio.h" +#include "ucom.h" +#include "uscanner.h" +#include "cz.h" +cdev_decl(cztty); +#include "radio.h" + +#include "wsdisplay.h" +#include "wskbd.h" +#include "wsmouse.h" +#include "wsmux.h" + +#ifdef USER_PCICONF +#include "pci.h" +cdev_decl(pci); +#endif + +#include "pf.h" + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_ctty_init(1,ctty), /* 1: controlling terminal */ + cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */ + cdev_disk_init(NWD,wd), /* 3: ST506/ESDI/IDE disk */ + cdev_swap_init(1,sw), /* 4: /dev/drum (swap pseudo-device) */ + cdev_tty_init(NPTY,pts), /* 5: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 6: pseudo-tty master */ + cdev_log_init(1,log), /* 7: /dev/klog */ + cdev_tty_init(NCOM,com), /* 8: serial port */ + cdev_disk_init(NFD,fd), /* 9: floppy disk */ + cdev_tape_init(NWT,wt), /* 10: QIC-02/QIC-36 tape */ + cdev_lkm_dummy(), /* 11: Sony CD-ROM */ + cdev_wsdisplay_init(NWSDISPLAY, /* 12: frame buffers, etc. */ + wsdisplay), + cdev_disk_init(NSD,sd), /* 13: SCSI disk */ + cdev_tape_init(NST,st), /* 14: SCSI tape */ + cdev_disk_init(NCD,cd), /* 15: SCSI CD-ROM */ + cdev_lpt_init(NLPT,lpt), /* 16: parallel printer */ + cdev_ch_init(NCH,ch), /* 17: SCSI autochanger */ + cdev_disk_init(NCCD,ccd), /* 18: concatenated disk driver */ + cdev_ss_init(NSS,ss), /* 19: SCSI scanner */ + cdev_uk_init(NUK,uk), /* 20: unknown SCSI */ + cdev_notdef(), /* 21 */ + cdev_fd_init(1,filedesc), /* 22: file descriptor pseudo-device */ + cdev_bpftun_init(NBPFILTER,bpf),/* 23: Berkeley packet filter */ + cdev_ses_init(NSES,ses), /* 24: SES/SAF-TE SCSI */ +#if 0 + cdev_ocis_init(NPCMCIA,pcmcia), /* 25: PCMCIA Bus */ +#else + cdev_notdef(), /* 25 */ +#endif + cdev_notdef(), /* 26 */ + cdev_spkr_init(NSPKR,spkr), /* 27: PC speaker */ + cdev_lkm_init(NLKM,lkm), /* 28: loadable module driver */ + cdev_lkm_dummy(), /* 29 */ + cdev_lkm_dummy(), /* 30 */ + cdev_lkm_dummy(), /* 31 */ + cdev_lkm_dummy(), /* 32 */ + cdev_lkm_dummy(), /* 33 */ + cdev_lkm_dummy(), /* 34 */ + cdev_notdef(), /* 35: Microsoft mouse */ + cdev_notdef(), /* 36: Logitech mouse */ + cdev_notdef(), /* 37: Extended PS/2 mouse */ + cdev_tty_init(NCY,cy), /* 38: Cyclom serial port */ + cdev_disk_init(NMCD,mcd), /* 39: Mitsumi CD-ROM */ + cdev_bpftun_init(NTUN,tun), /* 40: network tunnel */ + cdev_disk_init(NVND,vnd), /* 41: vnode disk driver */ + cdev_audio_init(NAUDIO,audio), /* 42: generic audio I/O */ +#ifdef COMPAT_SVR4 + cdev_svr4_net_init(1,svr4_net), /* 43: svr4 net pseudo-device */ +#else + cdev_notdef(), /* 43 */ +#endif + cdev_notdef(), /* 44 */ + cdev_random_init(1,random), /* 45: random data source */ + cdev_notdef(), /* 46 */ + cdev_disk_init(NRD,rd), /* 47: ram disk driver */ + cdev_notdef(), /* 48 */ + cdev_bktr_init(NBKTR,bktr), /* 49: Bt848 video capture device */ + cdev_ksyms_init(NKSYMS,ksyms), /* 50: Kernel symbols device */ +#ifdef XFS + cdev_xfs_init(NXFS,xfs_dev), /* 51: xfs communication device */ +#else + cdev_notdef(), /* 51 */ +#endif + cdev_midi_init(NMIDI,midi), /* 52: MIDI I/O */ + cdev_midi_init(NSEQUENCER,sequencer), /* 53: sequencer I/O */ + cdev_disk_init(NRAID,raid), /* 54: RAIDframe disk driver */ + cdev_wdt_init(NWDT,wdt), /* 55: WDT50x watchdog timer */ + /* The following slots are reserved for isdn4bsd. */ + cdev_notdef(), /* 56: i4b main device */ + cdev_notdef(), /* 57: i4b control device */ + cdev_notdef(), /* 58: i4b raw b-channel access */ + cdev_notdef(), /* 59: i4b trace device */ + cdev_notdef(), /* 60: i4b phone device */ + /* End of reserved slots for isdn4bsd. */ + cdev_usb_init(NUSB,usb), /* 61: USB controller */ + cdev_usbdev_init(NUHID,uhid), /* 62: USB generic HID */ + cdev_usbdev_init(NUGEN,ugen), /* 63: USB generic driver */ + cdev_ulpt_init(NULPT,ulpt), /* 64: USB printers */ + cdev_usbdev_init(NURIO,urio), /* 65: USB Diamond Rio 500 */ + cdev_tty_init(NUCOM,ucom), /* 66: USB tty */ + cdev_mouse_init(NWSKBD, wskbd), /* 67: keyboards */ + cdev_mouse_init(NWSMOUSE, /* 68: mice */ + wsmouse), + cdev_mouse_init(NWSMUX, wsmux), /* 69: ws multiplexor */ + cdev_crypto_init(NCRYPTO,crypto), /* 70: /dev/crypto */ + cdev_tty_init(NCZ,cztty), /* 71: Cyclades-Z serial port */ +#ifdef USER_PCICONF + cdev_pci_init(NPCI,pci), /* 72: PCI user */ +#else + cdev_notdef(), +#endif + cdev_pf_init(NPF,pf), /* 73: packet filter */ + cdev_notdef(), /* 74: ALTQ (deprecated) */ + cdev_iop_init(NIOP,iop), /* 75: I2O IOP control interface */ + cdev_radio_init(NRADIO, radio), /* 76: generic radio I/O */ + cdev_usbdev_init(NUSCANNER,uscanner), /* 77: USB scanners */ + cdev_systrace_init(NSYSTRACE,systrace), /* 78: system call tracing */ + cdev_oci_init(NBIO,bio), /* 79: ioctl tunnel */ +}; +int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); + +int mem_no = 2; /* major device number of memory special file */ + +/* + * Swapdev is a fake device implemented + * in sw.c used only internally to get to swstrategy. + * It cannot be provided to the users, because the + * swstrategy routine munches the b_dev and b_blkno entries + * before calling the appropriate driver. This would horribly + * confuse, e.g. the hashing routines. Instead, /dev/drum is + * provided as a character (raw) device. + */ +dev_t swapdev = makedev(1, 0); + +/* + * Returns true if dev is /dev/mem or /dev/kmem. + */ +int +iskmemdev(dev) + dev_t dev; +{ + + return (major(dev) == mem_no && (minor(dev) < 2 || minor(dev) == 14)); +} + +/* + * Returns true if dev is /dev/zero. + */ +int +iszerodev(dev) + dev_t dev; +{ + + return (major(dev) == mem_no && minor(dev) == 12); +} + +dev_t +getnulldev() +{ + return makedev(mem_no, 2); +} + +int chrtoblktbl[] = { + /* XXXX This needs to be dynamic for LKMs. */ + /*VCHR*/ /*VBLK*/ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ 0, + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ NODEV, + /* 9 */ 2, + /* 10 */ 3, + /* 11 */ 15, + /* 12 */ NODEV, + /* 13 */ 4, + /* 14 */ 5, + /* 15 */ 6, + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ 16, + /* 19 */ NODEV, + /* 20 */ NODEV, + /* 21 */ NODEV, + /* 22 */ NODEV, + /* 23 */ NODEV, + /* 24 */ 18, + /* 25 */ NODEV, + /* 26 */ NODEV, + /* 27 */ NODEV, + /* 28 */ NODEV, + /* 29 */ NODEV, + /* 30 */ NODEV, + /* 31 */ NODEV, + /* 32 */ NODEV, + /* 33 */ NODEV, + /* 34 */ NODEV, + /* 35 */ NODEV, + /* 36 */ NODEV, + /* 37 */ NODEV, + /* 38 */ NODEV, + /* 39 */ 7, + /* 40 */ NODEV, + /* 41 */ 14, + /* 42 */ NODEV, + /* 43 */ NODEV, + /* 44 */ NODEV, + /* 45 */ NODEV, + /* 46 */ NODEV, + /* 47 */ 17, + /* 48 */ NODEV, + /* 49 */ NODEV, + /* 50 */ NODEV, + /* 51 */ NODEV, + /* 52 */ NODEV, + /* 53 */ NODEV, + /* 54 */ 19, +}; + +int nchrtoblktbl = sizeof(chrtoblktbl) / sizeof(chrtoblktbl[0]); + +/* + * In order to map BSD bdev numbers of disks to their BIOS equivalents + * we use several heuristics, one being using checksums of the first + * few blocks of a disk to get a signature we can match with /boot's + * computed signatures. To know where from to read, we must provide a + * disk driver name -> bdev major number table, which follows. + * Note: floppies are not included as those are differentiated by the BIOS. + */ +int findblkmajor(struct device *dv); +dev_t dev_rawpart(struct device *); /* XXX */ + +dev_t +dev_rawpart(dv) + struct device *dv; +{ + int majdev; + + majdev = findblkmajor(dv); + + switch (majdev) { + /* add here any device you want to be checksummed on boot */ + case 0: /* wd */ + case 4: /* sd */ + return (MAKEDISKDEV(majdev, dv->dv_unit, RAW_PART)); + break; + default: + ; + } + + return (NODEV); +} + +/* + * This entire table could be autoconfig()ed but that would mean that + * the kernel's idea of the console would be out of sync with that of + * the standalone boot. I think it best that they both use the same + * known algorithm unless we see a pressing need otherwise. + */ +#include <dev/cons.h> + +cons_decl(pc); +cons_decl(com); +cons_decl(ws); + +struct consdev constab[] = { +#if 1 || NWSDISPLAY > 0 + cons_init(ws), +#endif +#if 0 && NCOM > 0 + cons_init(com), +#endif + { 0 }, +}; + diff --git a/sys/arch/amd64/amd64/consinit.c b/sys/arch/amd64/amd64/consinit.c new file mode 100644 index 00000000000..2a167480017 --- /dev/null +++ b/sys/arch/amd64/amd64/consinit.c @@ -0,0 +1,61 @@ +/* $OpenBSD: consinit.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: consinit.c,v 1.2 2003/03/02 18:27:14 fvdl Exp $ */ + +/* + * Copyright (c) 1998 + * Matthias Drochner. 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 ``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 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. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <machine/bus.h> +#include <machine/bootinfo.h> + +#include <dev/cons.h> + +void +consinit() +{ + static int initted; + + if (initted) + return; + initted = 1; + cninit(); +} + +#if (NPCKBC > 0) && (NPCKBD == 0) +/* + * glue code to support old console code with the + * mi keyboard controller driver + */ +int +pckbc_machdep_cnattach(kbctag, kbcslot) + pckbc_tag_t kbctag; + pckbc_slot_t kbcslot; +{ + return (ENXIO); +} +#endif diff --git a/sys/arch/amd64/amd64/copy.S b/sys/arch/amd64/amd64/copy.S new file mode 100644 index 00000000000..6a8a1b3d2cd --- /dev/null +++ b/sys/arch/amd64/amd64/copy.S @@ -0,0 +1,321 @@ +/* $OpenBSD: copy.S,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: copy.S,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#include "assym.h" + +#include <sys/errno.h> +#include <sys/syscall.h> + +#include <machine/asm.h> + +/* + * Copy routines from and to userland, plus a few more. See the + * section 9 manpages for info. Some cases can be optimized more. + * + * I wonder if it's worthwhile to make these use SSE2 registers. + */ + +/* + * XXXfvdl appears only to be used by pccons. + * + * fillw(short pattern, caddr_t addr, size_t len); + * Write len copies of pattern at addr. + * appears to be used by pccons. + */ +ENTRY(fillw) + movl %edi,%eax + movq %rsi,%rdi + movw %ax,%cx + rorl $16,%eax + movw %cx,%ax + cld + movq %rdx,%rcx + shrq %rcx + rep + stosl + movq %rdx,%rcx + andq $1,%rcx + rep + stosw + ret + +ENTRY(kcopy) + movq CPUVAR(CURPCB),%rax + pushq PCB_ONFAULT(%rax) + leaq _C_LABEL(copy_fault)(%rip),%r11 + movq %r11, PCB_ONFAULT(%rax) + + xchgq %rdi,%rsi + movq %rdx,%rcx + + movq %rdi,%rax + subq %rsi,%rax + cmpq %rcx,%rax # overlapping? + jb 1f + cld # nope, copy forward + shrq $3,%rcx # copy by 64-bit words + rep + movsq + + movq %rdx,%rcx + andl $7,%ecx # any bytes left? + rep + movsb + + movq CPUVAR(CURPCB),%rdx + popq PCB_ONFAULT(%rdx) + xorq %rax,%rax + ret + +1: addq %rcx,%rdi # copy backward + addq %rcx,%rsi + std + andq $7,%rcx # any fractional bytes? + decq %rdi + decq %rsi + rep + movsb + movq %rdx,%rcx # copy remainder by 64-bit words + shrq $3,%rcx + subq $7,%rsi + subq $7,%rdi + rep + movsq + cld + + movq CPUVAR(CURPCB),%rdx + popq PCB_ONFAULT(%rdx) + xorq %rax,%rax + ret + +ENTRY(copyout) + pushq $0 + + xchgq %rdi,%rsi + movq %rdx,%rax + + movq %rdi,%rdx + addq %rax,%rdx + jc _C_LABEL(copy_efault) + movq $VM_MAXUSER_ADDRESS,%r8 + cmpq %r8,%rdx + ja _C_LABEL(copy_efault) + + movq CPUVAR(CURPCB),%rdx + leaq _C_LABEL(copy_fault)(%rip),%r11 + movq %r11,PCB_ONFAULT(%rdx) + + cld + movq %rax,%rcx + shrq $3,%rcx + rep + movsq + movb %al,%cl + andb $7,%cl + rep + movsb + + popq PCB_ONFAULT(%rdx) + xorl %eax,%eax + ret + +ENTRY(copyin) + movq CPUVAR(CURPCB),%rax + pushq $0 + leaq _C_LABEL(copy_fault)(%rip),%r11 + movq %r11,PCB_ONFAULT(%rax) + + xchgq %rdi,%rsi + movq %rdx,%rax + + movq %rsi,%rdx + addq %rax,%rdx + jc _C_LABEL(copy_efault) + movq $VM_MAXUSER_ADDRESS,%r8 + cmpq %r8,%rdx + ja _C_LABEL(copy_efault) + +3: /* bcopy(%rsi, %rdi, %rax); */ + cld + movq %rax,%rcx + shrq $3,%rcx + rep + movsq + movb %al,%cl + andb $7,%cl + rep + movsb + + movq CPUVAR(CURPCB),%rdx + popq PCB_ONFAULT(%rdx) + xorl %eax,%eax + ret + +NENTRY(copy_efault) + movq $EFAULT,%rax + +NENTRY(copy_fault) + movq CPUVAR(CURPCB),%rdx + popq PCB_ONFAULT(%rdx) + ret + +ENTRY(copyoutstr) + xchgq %rdi,%rsi + movq %rdx,%r8 + movq %rcx,%r9 + +5: movq CPUVAR(CURPCB),%rax + leaq _C_LABEL(copystr_fault)(%rip),%r11 + movq %r11,PCB_ONFAULT(%rax) + /* + * Get min(%rdx, VM_MAXUSER_ADDRESS-%rdi). + */ + movq $VM_MAXUSER_ADDRESS,%rax + subq %rdi,%rax + cmpq %rdx,%rax + jae 1f + movq %rax,%rdx + movq %rax,%r8 + +1: incq %rdx + cld + +1: decq %rdx + jz 2f + lodsb + stosb + testb %al,%al + jnz 1b + + /* Success -- 0 byte reached. */ + decq %rdx + xorq %rax,%rax + jmp copystr_return + +2: /* rdx is zero -- return EFAULT or ENAMETOOLONG. */ + movq $VM_MAXUSER_ADDRESS,%r11 + cmpq %r11,%rdi + jae _C_LABEL(copystr_efault) + movq $ENAMETOOLONG,%rax + jmp copystr_return + +ENTRY(copyinstr) + xchgq %rdi,%rsi + movq %rdx,%r8 + movq %rcx,%r9 + + movq CPUVAR(CURPCB),%rcx + leaq _C_LABEL(copystr_fault)(%rip),%r11 + movq %r11,PCB_ONFAULT(%rcx) + + /* + * Get min(%rdx, VM_MAXUSER_ADDRESS-%rsi). + */ + movq $VM_MAXUSER_ADDRESS,%rax + subq %rsi,%rax + cmpq %rdx,%rax + jae 1f + movq %rax,%rdx + movq %rax,%r8 + +1: incq %rdx + cld + +1: decq %rdx + jz 2f + lodsb + stosb + testb %al,%al + jnz 1b + + /* Success -- 0 byte reached. */ + decq %rdx + xorq %rax,%rax + jmp copystr_return + +2: /* edx is zero -- return EFAULT or ENAMETOOLONG. */ + movq $VM_MAXUSER_ADDRESS,%r11 + cmpq %r11,%rsi + jae _C_LABEL(copystr_efault) + movq $ENAMETOOLONG,%rax + jmp copystr_return + +ENTRY(copystr_efault) + movl $EFAULT,%eax + +ENTRY(copystr_fault) +copystr_return: + /* Set *lencopied and return %eax. */ + movq CPUVAR(CURPCB),%rcx + movq $0,PCB_ONFAULT(%rcx) + testq %r9,%r9 + jz 8f + subq %rdx,%r8 + movq %r8,(%r9) + +8: ret + +ENTRY(copystr) + xchgq %rdi,%rsi + movq %rdx,%r8 + + incq %rdx + cld + +1: decq %rdx + jz 4f + lodsb + stosb + testb %al,%al + jnz 1b + + /* Success -- 0 byte reached. */ + decq %rdx + xorl %eax,%eax + jmp 6f + +4: /* edx is zero -- return ENAMETOOLONG. */ + movl $ENAMETOOLONG,%eax + +6: /* Set *lencopied and return %eax. */ + testq %rcx,%rcx + jz 7f + subq %rdx,%r8 + movq %r8,(%rcx) + +7: ret diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c new file mode 100644 index 00000000000..d58a8acb3ce --- /dev/null +++ b/sys/arch/amd64/amd64/cpu.c @@ -0,0 +1,699 @@ +/* $OpenBSD: cpu.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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) 1999 Stefan Grefen + * + * 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 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 AND 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. + */ + +#include "lapic.h" +#include "ioapic.h" + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/cpuvar.h> +#include <machine/pmap.h> +#include <machine/vmparam.h> +#include <machine/mpbiosvar.h> +#include <machine/pcb.h> +#include <machine/specialreg.h> +#include <machine/segments.h> +#include <machine/gdt.h> +#include <machine/mtrr.h> +#include <machine/pio.h> + +#if NLAPIC > 0 +#include <machine/apicvar.h> +#include <machine/i82489reg.h> +#include <machine/i82489var.h> +#endif + +#if NIOAPIC > 0 +#include <machine/i82093var.h> +#endif + +#include <dev/ic/mc146818reg.h> +#include <i386/isa/nvram.h> +#include <dev/isa/isareg.h> + +int cpu_match(struct device *, void *, void *); +void cpu_attach(struct device *, struct device *, void *); + +struct cpu_softc { + struct device sc_dev; /* device tree glue */ + struct cpu_info *sc_info; /* pointer to CPU info */ +}; + +int mp_cpu_start(struct cpu_info *); +void mp_cpu_start_cleanup(struct cpu_info *); +struct cpu_functions mp_cpu_funcs = { mp_cpu_start, NULL, + mp_cpu_start_cleanup }; + +struct cfattach cpu_ca = { + sizeof(struct cpu_softc), cpu_match, cpu_attach +}; + +struct cfdriver cpu_cd = { + NULL, "cpu", DV_DULL +}; + +/* + * Statically-allocated CPU info for the primary CPU (or the only + * CPU, on uniprocessors). The CPU info list is initialized to + * point at it. + */ +struct cpu_info cpu_info_primary = { 0, &cpu_info_primary }; + +struct cpu_info *cpu_info_list = &cpu_info_primary; + +u_int32_t cpus_attached = 0; + +#ifdef MULTIPROCESSOR +/* + * Array of CPU info structures. Must be statically-allocated because + * curproc, etc. are used early. + */ +struct cpu_info *cpu_info[X86_MAXPROCS] = { &cpu_info_primary }; + +u_int32_t cpus_running = 0; + +void cpu_hatch(void *); +static void cpu_boot_secondary(struct cpu_info *ci); +static void cpu_start_secondary(struct cpu_info *ci); +static void cpu_copy_trampoline(void); + +/* + * Runs once per boot once multiprocessor goo has been detected and + * the local APIC on the boot processor has been mapped. + * + * Called from lapic_boot_init() (from mpbios_scan()). + */ +void +cpu_init_first() +{ + int cpunum = lapic_cpu_number(); + + if (cpunum != 0) { + cpu_info[0] = NULL; + cpu_info[cpunum] = &cpu_info_primary; + } + + cpu_copy_trampoline(); +} +#endif + +int +cpu_match(struct device *parent, void *match, void *aux) +{ + struct cfdata *cf = match; + struct cpu_attach_args *caa = aux; + + if (strcmp(caa->caa_name, cf->cf_driver->cd_name) == 0) + return 1; + return 0; +} + +static void +cpu_vm_init(struct cpu_info *ci) +{ + int ncolors = 2, i; + + for (i = CAI_ICACHE; i <= CAI_L2CACHE; i++) { + struct x86_cache_info *cai; + int tcolors; + + cai = &ci->ci_cinfo[i]; + + tcolors = atop(cai->cai_totalsize); + switch(cai->cai_associativity) { + case 0xff: + tcolors = 1; /* fully associative */ + break; + case 0: + case 1: + break; + default: + tcolors /= cai->cai_associativity; + } + ncolors = max(ncolors, tcolors); + } + +#ifdef notyet + /* + * Knowing the size of the largest cache on this CPU, re-color + * our pages. + */ + if (ncolors <= uvmexp.ncolors) + return; + printf("%s: %d page colors\n", ci->ci_dev->dv_xname, ncolors); + uvm_page_recolor(ncolors); +#endif +} + + +void +cpu_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct cpu_softc *sc = (void *) self; + struct cpu_attach_args *caa = aux; + struct cpu_info *ci; +#if defined(MULTIPROCESSOR) + int cpunum = caa->cpu_number; + vaddr_t kstack; + struct pcb *pcb; +#endif + + /* + * If we're an Application Processor, allocate a cpu_info + * structure, otherwise use the primary's. + */ + if (caa->cpu_role == CPU_ROLE_AP) { + ci = malloc(sizeof(*ci), M_DEVBUF, M_WAITOK); + memset(ci, 0, sizeof(*ci)); +#if defined(MULTIPROCESSOR) + if (cpu_info[cpunum] != NULL) + panic("cpu at apic id %d already attached?", cpunum); + cpu_info[cpunum] = ci; +#endif +#ifdef TRAPLOG + ci->ci_tlog_base = malloc(sizeof(struct tlog), + M_DEVBUF, M_WAITOK); +#endif + } else { + ci = &cpu_info_primary; +#if defined(MULTIPROCESSOR) + if (cpunum != lapic_cpu_number()) { + panic("%s: running cpu is at apic %d" + " instead of at expected %d", + sc->sc_dev.dv_xname, lapic_cpu_number(), cpunum); + } +#endif + } + + ci->ci_self = ci; + sc->sc_info = ci; + + ci->ci_dev = self; + ci->ci_apicid = caa->cpu_number; +#ifdef MULTIPROCESSOR + ci->ci_cpuid = ci->ci_apicid; +#else + ci->ci_cpuid = 0; /* False for APs, but they're not used anyway */ +#endif + ci->ci_func = caa->cpu_func; + + simple_lock_init(&ci->ci_slock); + +#if defined(MULTIPROCESSOR) + /* + * Allocate UPAGES contiguous pages for the idle PCB and stack. + */ + kstack = uvm_km_alloc (kernel_map, USPACE); + if (kstack == 0) { + if (caa->cpu_role != CPU_ROLE_AP) { + panic("cpu_attach: unable to allocate idle stack for" + " primary"); + } + printf("%s: unable to allocate idle stack\n", + sc->sc_dev.dv_xname); + return; + } + pcb = ci->ci_idle_pcb = (struct pcb *) kstack; + memset(pcb, 0, USPACE); + + pcb->pcb_tss.tss_rsp0 = kstack + USPACE - 16; + pcb->pcb_rbp = pcb->pcb_rsp = kstack + USPACE - 16; + pcb->pcb_tss.tss_ist[0] = kstack + PAGE_SIZE - 16; + pcb->pcb_pmap = pmap_kernel(); + pcb->pcb_cr0 = rcr0(); + pcb->pcb_cr3 = pcb->pcb_pmap->pm_pdirpa; +#endif + + /* further PCB init done later. */ + + printf(": "); + + switch (caa->cpu_role) { + case CPU_ROLE_SP: + printf("(uniprocessor)\n"); + ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY; + cpu_intr_init(ci); + identifycpu(ci); + cpu_init(ci); + break; + + case CPU_ROLE_BP: + printf("apid %d (boot processor)\n", caa->cpu_number); + ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY; + cpu_intr_init(ci); + identifycpu(ci); + cpu_init(ci); + +#if NLAPIC > 0 + /* + * Enable local apic + */ + lapic_enable(); + lapic_calibrate_timer(ci); +#endif +#if NIOAPIC > 0 + ioapic_bsp_id = caa->cpu_number; +#endif + break; + + case CPU_ROLE_AP: + /* + * report on an AP + */ + printf("apid %d (application processor)\n", caa->cpu_number); + +#if defined(MULTIPROCESSOR) + cpu_intr_init(ci); + gdt_alloc_cpu(ci); + cpu_start_secondary(ci); + if (ci->ci_flags & CPUF_PRESENT) { + identifycpu(ci); + ci->ci_next = cpu_info_list->ci_next; + cpu_info_list->ci_next = ci; + } +#else + printf("%s: not started\n", sc->sc_dev.dv_xname); +#endif + break; + + default: + panic("unknown processor type??\n"); + } + cpu_vm_init(ci); + + cpus_attached |= (1 << ci->ci_cpuid); + +#if defined(MULTIPROCESSOR) + if (mp_verbose) { + printf("%s: kstack at 0x%lx for %d bytes\n", + sc->sc_dev.dv_xname, kstack, USPACE); + printf("%s: idle pcb at %p, idle sp at 0x%lx\n", + sc->sc_dev.dv_xname, pcb, pcb->pcb_rsp); + } +#endif +} + +/* + * Initialize the processor appropriately. + */ + +void +cpu_init(ci) + struct cpu_info *ci; +{ + /* configure the CPU if needed */ + if (ci->cpu_setup != NULL) + (*ci->cpu_setup)(ci); + + lcr0(rcr0() | CR0_WP); + lcr4(rcr4() | CR4_PGE | CR4_OSFXSR | CR4_OSXMMEXCPT); + +#ifdef MTRR + if ((ci->ci_flags & CPUF_AP) == 0) + i686_mtrr_init_first(); + mtrr_init_cpu(ci); +#endif + +#ifdef MULTIPROCESSOR + ci->ci_flags |= CPUF_RUNNING; + cpus_running |= 1 << ci->ci_cpuid; +#endif +} + + +#ifdef MULTIPROCESSOR +void +cpu_boot_secondary_processors() +{ + struct cpu_info *ci; + u_long i; + + for (i=0; i < X86_MAXPROCS; i++) { + ci = cpu_info[i]; + if (ci == NULL) + continue; + if (ci->ci_idle_pcb == NULL) + continue; + if ((ci->ci_flags & CPUF_PRESENT) == 0) + continue; + if (ci->ci_flags & (CPUF_BSP|CPUF_SP|CPUF_PRIMARY)) + continue; + cpu_boot_secondary(ci); + } +} + +void +cpu_init_idle_pcbs() +{ + struct cpu_info *ci; + u_long i; + + for (i=0; i < X86_MAXPROCS; i++) { + ci = cpu_info[i]; + if (ci == NULL) + continue; + if (ci->ci_idle_pcb == NULL) + continue; + if ((ci->ci_flags & CPUF_PRESENT) == 0) + continue; + x86_64_init_pcb_tss_ldt(ci); + } +} + +void +cpu_start_secondary (ci) + struct cpu_info *ci; +{ + struct pcb *pcb; + int i; + struct pmap *kmp = pmap_kernel(); + extern u_int64_t mp_pdirpa; + extern vaddr_t lo32_vaddr; + extern paddr_t lo32_paddr; + + /* + * The initial PML4 pointer must be below 4G, so if the + * current one isn't, use a "bounce buffer" + */ + if (kmp->pm_pdirpa > 0xffffffff) { + memcpy((void *)lo32_vaddr, kmp->pm_pdir, PAGE_SIZE); + mp_pdirpa = lo32_paddr; + } else + mp_pdirpa = kmp->pm_pdirpa; + + pcb = ci->ci_idle_pcb; + + ci->ci_flags |= CPUF_AP; + + printf("%s: starting\n", ci->ci_dev->dv_xname); + + CPU_STARTUP(ci); + + /* + * wait for it to become ready + */ + for (i = 100000; (!(ci->ci_flags & CPUF_PRESENT)) && i>0;i--) { + delay(10); + } + if (! (ci->ci_flags & CPUF_PRESENT)) { + printf("%s: failed to become ready\n", ci->ci_dev->dv_xname); +#if defined(MPDEBUG) && defined(DDB) + printf("dropping into debugger; continue from here to resume boot\n"); + Debugger(); +#endif + } + + CPU_START_CLEANUP(ci); +} + +void +cpu_boot_secondary(ci) + struct cpu_info *ci; +{ + int i; + + ci->ci_flags |= CPUF_GO; /* XXX atomic */ + + for (i = 100000; (!(ci->ci_flags & CPUF_RUNNING)) && i>0;i--) { + delay(10); + } + if (! (ci->ci_flags & CPUF_RUNNING)) { + printf("cpu failed to start\n"); +#if defined(MPDEBUG) && defined(DDB) + printf("dropping into debugger; continue from here to resume boot\n"); + Debugger(); +#endif + } +} + +/* + * The CPU ends up here when its ready to run + * This is called from code in mptramp.s; at this point, we are running + * in the idle pcb/idle stack of the new cpu. When this function returns, + * this processor will enter the idle loop and start looking for work. + * + * XXX should share some of this with init386 in machdep.c + */ +void +cpu_hatch(void *v) +{ + struct cpu_info *ci = (struct cpu_info *)v; + int s; + + cpu_init_msrs(ci); + + cpu_probe_features(ci); + cpu_feature &= ci->ci_feature_flags; + +#ifdef DEBUG + if (ci->ci_flags & CPUF_PRESENT) + panic("%s: already running!?", ci->ci_dev->dv_xname); +#endif + + ci->ci_flags |= CPUF_PRESENT; + + lapic_enable(); + lapic_initclocks(); + + while ((ci->ci_flags & CPUF_GO) == 0) + delay(10); +#ifdef DEBUG + if (ci->ci_flags & CPUF_RUNNING) + panic("%s: already running!?", ci->ci_dev->dv_xname); +#endif + + lcr0(ci->ci_idle_pcb->pcb_cr0); + cpu_init_idt(); + lapic_set_lvt(); + gdt_init_cpu(ci); + fpuinit(ci); + + lldt(GSYSSEL(GLDT_SEL, SEL_KPL)); + + cpu_init(ci); + + s = splhigh(); + lcr8(0); + enable_intr(); + + printf("%s: CPU %u running\n",ci->ci_dev->dv_xname, ci->ci_cpuid); +#if defined(I586_CPU) || defined(I686_CPU) + if (ci->ci_feature_flags & CPUID_TSC) + cc_microset(ci); +#endif + microtime(&ci->ci_schedstate.spc_runtime); + splx(s); +} + +#if defined(DDB) + +#include <ddb/db_output.h> +#include <machine/db_machdep.h> + +/* + * Dump cpu information from ddb. + */ +void +cpu_debug_dump(void) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + db_printf("addr dev id flags ipis curproc fpcurproc\n"); + for (CPU_INFO_FOREACH(cii, ci)) { + db_printf("%p %s %u %x %x %10p %10p\n", + ci, + ci->ci_dev == NULL ? "BOOT" : ci->ci_dev->dv_xname, + ci->ci_cpuid, + ci->ci_flags, ci->ci_ipis, + ci->ci_curproc, + ci->ci_fpcurproc); + } +} +#endif + +static void +cpu_copy_trampoline() +{ + /* + * Copy boot code. + */ + extern u_char cpu_spinup_trampoline[]; + extern u_char cpu_spinup_trampoline_end[]; + pmap_kenter_pa((vaddr_t)MP_TRAMPOLINE, /* virtual */ + (paddr_t)MP_TRAMPOLINE, /* physical */ + VM_PROT_ALL); /* protection */ + memcpy((caddr_t)MP_TRAMPOLINE, + cpu_spinup_trampoline, + cpu_spinup_trampoline_end-cpu_spinup_trampoline); +} + +#endif + + +int +mp_cpu_start(struct cpu_info *ci) +{ +#if NLAPIC > 0 + int error; +#endif + unsigned short dwordptr[2]; + + /* + * "The BSP must initialize CMOS shutdown code to 0Ah ..." + */ + + outb(IO_RTC, NVRAM_RESET); + outb(IO_RTC+1, NVRAM_RESET_SOFT); + + /* + * "and the warm reset vector (DWORD based at 40:67) to point + * to the AP startup code ..." + */ + + dwordptr[0] = 0; + dwordptr[1] = MP_TRAMPOLINE >> 4; + + pmap_kenter_pa (0, 0, VM_PROT_READ|VM_PROT_WRITE); + memcpy ((u_int8_t *) 0x467, dwordptr, 4); + pmap_kremove (0, PAGE_SIZE); + +#if NLAPIC > 0 + /* + * ... prior to executing the following sequence:" + */ + + if (ci->ci_flags & CPUF_AP) { + if ((error = x86_ipi_init(ci->ci_apicid)) != 0) + return error; + + delay(10000); + + if (cpu_feature & CPUID_APIC) { + + if ((error = x86_ipi(MP_TRAMPOLINE/PAGE_SIZE, + ci->ci_apicid, + LAPIC_DLMODE_STARTUP)) != 0) + return error; + delay(200); + + if ((error = x86_ipi(MP_TRAMPOLINE/PAGE_SIZE, + ci->ci_apicid, + LAPIC_DLMODE_STARTUP)) != 0) + return error; + delay(200); + } + } +#endif + return 0; +} + +void +mp_cpu_start_cleanup(struct cpu_info *ci) +{ + /* + * Ensure the NVRAM reset byte contains something vaguely sane. + */ + + outb(IO_RTC, NVRAM_RESET); + outb(IO_RTC+1, NVRAM_RESET_RST); +} + +typedef void (vector)(void); +extern vector Xsyscall, Xsyscall32; + +void +cpu_init_msrs(struct cpu_info *ci) +{ + wrmsr(MSR_STAR, + ((uint64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) | + ((uint64_t)LSEL(LSYSRETBASE_SEL, SEL_UPL) << 48)); + wrmsr(MSR_LSTAR, (uint64_t)Xsyscall); + wrmsr(MSR_CSTAR, (uint64_t)Xsyscall32); + wrmsr(MSR_SFMASK, PSL_NT|PSL_T|PSL_I|PSL_C); + + wrmsr(MSR_FSBASE, 0); + wrmsr(MSR_GSBASE, (u_int64_t)ci); + wrmsr(MSR_KERNELGSBASE, 0); +} diff --git a/sys/arch/amd64/amd64/db_disasm.c b/sys/arch/amd64/amd64/db_disasm.c new file mode 100644 index 00000000000..431afcc2551 --- /dev/null +++ b/sys/arch/amd64/amd64/db_disasm.c @@ -0,0 +1,56 @@ +/* $OpenBSD: db_disasm.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: db_disasm.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * 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. + * + * Id: db_disasm.c,v 2.3 91/02/05 17:11:03 mrt (CMU) + */ + +/* + * Instruction disassembler. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> +#include <ddb/db_sym.h> +#include <ddb/db_output.h> +#include <ddb/db_interface.h> + +/* + * Disassemble instruction at 'loc'. 'altfmt' specifies an + * (optional) alternate format. Return address of start of + * next instruction. + */ +db_addr_t +db_disasm(loc, altfmt) + db_addr_t loc; + boolean_t altfmt; +{ + return loc; +} diff --git a/sys/arch/amd64/amd64/db_interface.c b/sys/arch/amd64/amd64/db_interface.c new file mode 100644 index 00000000000..56c3dd5ce22 --- /dev/null +++ b/sys/arch/amd64/amd64/db_interface.c @@ -0,0 +1,303 @@ +/* $OpenBSD: db_interface.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: db_interface.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * 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. + * + * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) + */ + +/* + * Interface to new debugger. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/reboot.h> +#include <sys/systm.h> + +#include <uvm/uvm_extern.h> + +#include <dev/cons.h> + +#include <machine/cpufunc.h> +#include <machine/db_machdep.h> +#include <machine/cpuvar.h> +#include <machine/i82093var.h> +#include <machine/i82489reg.h> +#include <machine/atomic.h> + +#include <ddb/db_sym.h> +#include <ddb/db_command.h> +#include <ddb/db_extern.h> +#include <ddb/db_access.h> +#include <ddb/db_output.h> +#include <ddb/db_var.h> + +extern label_t *db_recover; +extern char *trap_type[]; +extern int trap_types; + +int db_active; +db_regs_t ddb_regs; /* register state */ +db_regs_t *ddb_regp; + +void db_mach_cpu (db_expr_t, int, db_expr_t, char *); + +const struct db_command db_machine_command_table[] = { +#ifdef MULTIPROCESSOR + { "cpu", db_mach_cpu, 0, 0 }, +#endif + { (char *)0, }, +}; + +void kdbprinttrap(int, int); +#ifdef MULTIPROCESSOR +extern void ddb_ipi(struct trapframe); +static void ddb_suspend(struct trapframe *); +int ddb_vec; +#endif + +#define NOCPU -1 + +int ddb_cpu = NOCPU; + +typedef void (vector)(void); +extern vector Xintrddb; + +void +db_machine_init() +{ + +#ifdef MULTIPROCESSOR + ddb_vec = idt_vec_alloc(0xf0, 0xff); + setgate((struct gate_descriptor *)&idt[ddb_vec], &Xintrddb, 1, + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#endif +} + +#ifdef MULTIPROCESSOR + +__cpu_simple_lock_t db_lock; + +static int +db_suspend_others(void) +{ + int cpu_me = cpu_number(); + int win; + + if (ddb_vec == 0) + return 1; + + __cpu_simple_lock(&db_lock); + if (ddb_cpu == NOCPU) + ddb_cpu = cpu_me; + win = (ddb_cpu == cpu_me); + __cpu_simple_unlock(&db_lock); + if (win) { + x86_ipi(ddb_vec, LAPIC_DEST_ALLEXCL, LAPIC_DLMODE_FIXED); + } + return win; +} + +static void +db_resume_others(void) +{ + int i; + + __cpu_simple_lock(&db_lock); + ddb_cpu = NOCPU; + __cpu_simple_unlock(&db_lock); + + for (i=0; i < X86_MAXPROCS; i++) { + struct cpu_info *ci = cpu_info[i]; + if (ci == NULL) + continue; + if (ci->ci_flags & CPUF_PAUSE) + x86_atomic_clearbits_l(&ci->ci_flags, CPUF_PAUSE); + } + +} + +#endif + +/* + * Print trap reason. + */ +void +kdbprinttrap(type, code) + int type, code; +{ + db_printf("kernel: "); + if (type >= trap_types || type < 0) + db_printf("type %d", type); + else + db_printf("%s", trap_type[type]); + db_printf(" trap, code=%x\n", code); +} + +/* + * kdb_trap - field a TRACE or BPT trap + */ +int +kdb_trap(type, code, regs) + int type, code; + db_regs_t *regs; +{ + int s; + db_regs_t dbreg; + + switch (type) { + case T_BPTFLT: /* breakpoint */ + case T_TRCTRAP: /* single_step */ + case T_NMI: /* NMI */ + case -1: /* keyboard interrupt */ + break; + default: + if (!db_panic) + return (0); + + kdbprinttrap(type, code); + if (db_recover != 0) { + db_error("Faulted in DDB; continuing...\n"); + /*NOTREACHED*/ + } + } + +#ifdef MULTIPROCESSOR + if (!db_suspend_others()) { + ddb_suspend(regs); + } else { + curcpu()->ci_ddb_regs = &dbreg; + ddb_regp = &dbreg; +#endif + + ddb_regs = *regs; + + ddb_regs.tf_cs &= 0xffff; + ddb_regs.tf_ds &= 0xffff; + ddb_regs.tf_es &= 0xffff; + ddb_regs.tf_fs &= 0xffff; + ddb_regs.tf_gs &= 0xffff; + ddb_regs.tf_ss &= 0xffff; + + s = splhigh(); + db_active++; + cnpollc(TRUE); + db_trap(type, code); + cnpollc(FALSE); + db_active--; + splx(s); +#ifdef MULTIPROCESSOR + db_resume_others(); + } +#endif + ddb_regp = &dbreg; + + *regs = ddb_regs; + + return (1); +} + +void +Debugger() +{ + breakpoint(); +} + +#ifdef MULTIPROCESSOR + +/* + * Called when we receive a debugger IPI (inter-processor interrupt). + * As with trap() in trap.c, this function is called from an assembly + * language IDT gate entry routine which prepares a suitable stack frame, + * and restores this frame after the exception has been processed. Note + * that the effect is as if the arguments were passed call by reference. + */ + +void +ddb_ipi(struct trapframe frame) +{ + + ddb_suspend(&frame); +} + +static void +ddb_suspend(struct trapframe *frame) +{ + volatile struct cpu_info *ci = curcpu(); + db_regs_t regs; + + regs = *frame; + + ci->ci_ddb_regs = ®s; + + x86_atomic_setbits_l(&ci->ci_flags, CPUF_PAUSE); + + while (ci->ci_flags & CPUF_PAUSE) + ; + ci->ci_ddb_regs = 0; +} + + +extern void cpu_debug_dump(void); /* XXX */ + +void +db_mach_cpu(addr, have_addr, count, modif) + db_expr_t addr; + int have_addr; + db_expr_t count; + char * modif; +{ + struct cpu_info *ci; + if (!have_addr) { + cpu_debug_dump(); + return; + } + + if ((addr < 0) || (addr >= X86_MAXPROCS)) { + db_printf("%ld: cpu out of range\n", addr); + return; + } + ci = cpu_info[addr]; + if (ci == NULL) { + db_printf("cpu %ld not configured\n", addr); + return; + } + if (ci != curcpu()) { + if (!(ci->ci_flags & CPUF_PAUSE)) { + db_printf("cpu %ld not paused\n", addr); + return; + } + } + if (ci->ci_ddb_regs == 0) { + db_printf("cpu %ld has no saved regs\n", addr); + return; + } + db_printf("using cpu %ld", addr); + ddb_regp = ci->ci_ddb_regs; +} + +#endif diff --git a/sys/arch/amd64/amd64/db_memrw.c b/sys/arch/amd64/amd64/db_memrw.c new file mode 100644 index 00000000000..9b26b5d99fb --- /dev/null +++ b/sys/arch/amd64/amd64/db_memrw.c @@ -0,0 +1,211 @@ +/* $OpenBSD: db_memrw.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: db_memrw.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross and Jason R. Thorpe. + * + * 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. + */ + +/* + * Interface to the debugger for virtual memory read/write. + * This file is shared by DDB and KGDB, and must work even + * when only KGDB is included (thus no db_printf calls). + * + * To write in the text segment, we have to first make + * the page writable, do the write, then restore the PTE. + * For writes outside the text segment, and all reads, + * just do the access -- if it causes a fault, the debugger + * will recover with a longjmp to an appropriate place. + * + * ALERT! If you want to access device registers with a + * specific size, then the read/write functions have to + * make sure to do the correct sized pointer access. + * + * Modified for i386 from hp300 version by + * Jason R. Thorpe <thorpej@zembu.com>. + * + * Basic copy to amd64 by fvdl. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> + +#include <uvm/uvm_extern.h> + +#include <machine/db_machdep.h> + +#include <ddb/db_access.h> + +/* + * Read bytes from kernel address space for debugger. + */ +void +db_read_bytes(vaddr_t addr, size_t size, char *data) +{ + char *src; + + src = (char *)addr; + + if (size == 8) { + *((long *)data) = *((long *)src); + return; + } + + if (size == 4) { + *((int *)data) = *((int *)src); + return; + } + + if (size == 2) { + *((short *)data) = *((short *)src); + return; + } + + while (size-- > 0) + *data++ = *src++; +} + +/* + * Write bytes somewhere in the kernel text. Make the text + * pages writable temporarily. + */ +static void +db_write_text(vaddr_t addr, size_t size, char *data) +{ + pt_entry_t *pte, oldpte, tmppte; + vaddr_t pgva; + size_t limit; + char *dst; + + if (size == 0) + return; + + dst = (char *)addr; + + do { + /* + * Get the PTE for the page. + */ + pte = kvtopte(addr); + oldpte = *pte; + + if ((oldpte & PG_V) == 0) { + printf(" address %p not a valid page\n", dst); + return; + } + + /* + * Get the VA for the page. + */ +#ifdef LARGEPAGES + if (oldpte & PG_PS) + pgva = (vaddr_t)dst & PG_LGFRAME; + else +#endif + pgva = x86_trunc_page(dst); + + /* + * Compute number of bytes that can be written + * with this mapping and subtract it from the + * total size. + */ +#ifdef LARGEPAGES + if (oldpte & PG_PS) + limit = NBPD - ((vaddr_t)dst & (NBPD - 1)); + else +#endif + limit = PAGE_SIZE - ((vaddr_t)dst & PGOFSET); + if (limit > size) + limit = size; + size -= limit; + + tmppte = (oldpte & ~PG_KR) | PG_KW; + *pte = tmppte; + pmap_update_pg(pgva); + + /* + * Page is now writable. Do as much access as we + * can in this page. + */ + for (; limit > 0; limit--) + *dst++ = *data++; + + /* + * Restore the old PTE. + */ + *pte = oldpte; + + pmap_update_pg(pgva); + + } while (size != 0); +} + +/* + * Write bytes to kernel address space for debugger. + */ +void +db_write_bytes(vaddr_t addr, size_t size, char *data) +{ + extern char etext; + char *dst; + + dst = (char *)addr; + + /* If any part is in kernel text, use db_write_text() */ + if (addr >= KERNBASE && addr < (vaddr_t)&etext) { + db_write_text(addr, size, data); + return; + } + + dst = (char *)addr; + + if (size == 8) { + *((long *)dst) = *((long *)data); + return; + } + + if (size == 4) { + *((int *)dst) = *((int *)data); + return; + } + + if (size == 2) { + *((short *)dst) = *((short *)data); + return; + } + + while (size-- > 0) + *dst++ = *data++; +} diff --git a/sys/arch/amd64/amd64/db_trace.c b/sys/arch/amd64/amd64/db_trace.c new file mode 100644 index 00000000000..223498c59f6 --- /dev/null +++ b/sys/arch/amd64/amd64/db_trace.c @@ -0,0 +1,412 @@ +/* $OpenBSD: db_trace.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: db_trace.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <machine/db_machdep.h> +#include <machine/frame.h> +#include <machine/trap.h> + +#include <ddb/db_sym.h> +#include <ddb/db_access.h> +#include <ddb/db_variables.h> +#include <ddb/db_output.h> +#include <ddb/db_interface.h> + +#if 1 +#define dbreg(xx) (long *)offsetof(db_regs_t, tf_ ## xx) +#else +#define dbreg(xx) (long *)&ddb_regs.tf_ ## xx +#endif + +static int db_x86_64_regop(struct db_variable *, db_expr_t *, int); + +/* + * Machine register set. + */ +struct db_variable db_regs[] = { + { "ds", dbreg(ds), db_x86_64_regop }, + { "es", dbreg(es), db_x86_64_regop }, + { "fs", dbreg(fs), db_x86_64_regop }, + { "gs", dbreg(gs), db_x86_64_regop }, + { "rdi", dbreg(rdi), db_x86_64_regop }, + { "rsi", dbreg(rsi), db_x86_64_regop }, + { "rbp", dbreg(rbp), db_x86_64_regop }, + { "rbx", dbreg(rbx), db_x86_64_regop }, + { "rdx", dbreg(rdx), db_x86_64_regop }, + { "rcx", dbreg(rcx), db_x86_64_regop }, + { "rax", dbreg(rax), db_x86_64_regop }, + { "r8", dbreg(r8), db_x86_64_regop }, + { "r9", dbreg(r9), db_x86_64_regop }, + { "r10", dbreg(r10), db_x86_64_regop }, + { "r11", dbreg(r11), db_x86_64_regop }, + { "r12", dbreg(r12), db_x86_64_regop }, + { "r13", dbreg(r13), db_x86_64_regop }, + { "r14", dbreg(r14), db_x86_64_regop }, + { "r15", dbreg(r15), db_x86_64_regop }, + { "rip", dbreg(rip), db_x86_64_regop }, + { "cs", dbreg(cs), db_x86_64_regop }, + { "rflags", dbreg(rflags), db_x86_64_regop }, + { "rsp", dbreg(rsp), db_x86_64_regop }, + { "ss", dbreg(ss), db_x86_64_regop }, +}; +struct db_variable * db_eregs = + db_regs + sizeof(db_regs)/sizeof(db_regs[0]); + +static int +db_x86_64_regop(struct db_variable *vp, db_expr_t *val, int opcode) +{ + db_expr_t *regaddr = + (db_expr_t *)(((uint8_t *)DDB_REGS) + ((size_t)vp->valuep)); + + switch (opcode) { + case DB_VAR_GET: + *val = *regaddr; + break; + case DB_VAR_SET: + *regaddr = *val; + break; + default: + panic("db_x86_64_regop: unknown op %d", opcode); + } + return 0; +} + +/* + * Stack trace. + */ +#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) + +struct x86_64_frame { + struct x86_64_frame *f_frame; + long f_retaddr; + long f_arg0; +}; + +#define NONE 0 +#define TRAP 1 +#define SYSCALL 2 +#define INTERRUPT 3 + +db_addr_t db_trap_symbol_value = 0; +db_addr_t db_syscall_symbol_value = 0; +db_addr_t db_kdintr_symbol_value = 0; +boolean_t db_trace_symbols_found = FALSE; + +void db_find_trace_symbols(void); +int db_numargs(struct x86_64_frame *); +void db_nextframe(struct x86_64_frame **, db_addr_t *, long *, int, + int (*) (const char *, ...)); + +void +db_find_trace_symbols() +{ + db_expr_t value; + + if (db_value_of_name("_trap", &value)) + db_trap_symbol_value = (db_addr_t) value; + if (db_value_of_name("_kdintr", &value)) + db_kdintr_symbol_value = (db_addr_t) value; + if (db_value_of_name("_syscall", &value)) + db_syscall_symbol_value = (db_addr_t) value; + db_trace_symbols_found = TRUE; +} + +/* + * Figure out how many arguments were passed into the frame at "fp". + * We can probably figure out how many arguments where passed above + * the first 6 (which are in registers), but since we can't + * reliably determine the values currently, just return 0. + */ +int +db_numargs(fp) + struct x86_64_frame *fp; +{ + return 0; +} + +/* + * Figure out the next frame up in the call stack. + * For trap(), we print the address of the faulting instruction and + * proceed with the calling frame. We return the ip that faulted. + * If the trap was caused by jumping through a bogus pointer, then + * the next line in the backtrace will list some random function as + * being called. It should get the argument list correct, though. + * It might be possible to dig out from the next frame up the name + * of the function that faulted, but that could get hairy. + */ +void +db_nextframe(fp, ip, argp, is_trap, pr) + struct x86_64_frame **fp; /* in/out */ + db_addr_t *ip; /* out */ + long *argp; /* in */ + int is_trap; /* in */ + int (*pr)(const char *, ...); /* in */ +{ + + switch (is_trap) { + case NONE: + *ip = (db_addr_t) + db_get_value((db_addr_t)&(*fp)->f_retaddr, 8, FALSE); + *fp = (struct x86_64_frame *) + db_get_value((db_addr_t)&(*fp)->f_frame, 8, FALSE); + break; + + default: { + struct trapframe *tf; + + /* The only argument to trap() or syscall() is the trapframe. */ + tf = (struct trapframe *)argp; + switch (is_trap) { + case TRAP: + (*pr)("--- trap (number %d) ---\n", tf->tf_trapno); + break; + case SYSCALL: + (*pr)("--- syscall (number %ld) ---\n", tf->tf_rax); + break; + case INTERRUPT: + (*pr)("--- interrupt ---\n"); + break; + } + *fp = (struct x86_64_frame *)tf->tf_rbp; + *ip = (db_addr_t)tf->tf_rip; + break; + } + } +} + +void +db_stack_trace_print(addr, have_addr, count, modif, pr) + db_expr_t addr; + boolean_t have_addr; + db_expr_t count; + char *modif; + int (*pr)(const char *, ...); +{ + struct x86_64_frame *frame, *lastframe; + long *argp; + db_addr_t callpc; + int is_trap = 0; + boolean_t kernel_only = TRUE; + boolean_t trace_thread = FALSE; + +#if 0 + if (!db_trace_symbols_found) + db_find_trace_symbols(); +#endif + + { + register char *cp = modif; + register char c; + + while ((c = *cp++) != 0) { + if (c == 't') + trace_thread = TRUE; + if (c == 'u') + kernel_only = FALSE; + } + } + + if (!have_addr) { + frame = (struct x86_64_frame *)ddb_regs.tf_rbp; + callpc = (db_addr_t)ddb_regs.tf_rip; + } else { +#if 0 + if (trace_thread) { + struct proc *p; + struct user *u; + struct lwp *l; + (*pr)("trace: pid %d ", (int)addr); + p = pfind(addr); + if (p == NULL) { + (*pr)("not found\n"); + return; + } + l = proc_representative_lwp(p); + if (!(l->l_flag&L_INMEM)) { + (*pr)("swapped out\n"); + return; + } + u = l->l_addr; + frame = (struct x86_64_frame *) u->u_pcb.pcb_rbp; + (*pr)("at %p\n", frame); + } else +#endif + frame = (struct x86_64_frame *)addr; + callpc = (db_addr_t) + db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE); + frame = (struct x86_64_frame *)frame->f_frame; + } + + lastframe = 0; + while (count && frame != 0) { + int narg; + char * name; + db_expr_t offset; + db_sym_t sym; +#define MAXNARG 16 + char *argnames[MAXNARG], **argnp = NULL; + + sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); + db_symbol_values(sym, &name, NULL); + + if (lastframe == 0 && sym == NULL) { + /* Symbol not found, peek at code */ + long instr = db_get_value(callpc, 8, FALSE); + + offset = 1; + if ((instr & 0x00ffffff) == 0x00e58955 || + /* enter: pushl %ebp, movl %esp, %ebp */ + (instr & 0x0000ffff) == 0x0000e589 + /* enter+1: movl %esp, %ebp */) { + offset = 0; + } + } + if (INKERNEL(frame) && name) { +#ifdef __ELF__ + if (!strcmp(name, "trap")) { + is_trap = TRAP; + } else if (!strcmp(name, "syscall")) { + is_trap = SYSCALL; + } else if (name[0] == 'X') { + if (!strncmp(name, "Xintr", 5) || + !strncmp(name, "Xresume", 7) || + !strncmp(name, "Xstray", 6) || + !strncmp(name, "Xhold", 5) || + !strncmp(name, "Xrecurse", 8) || + !strcmp(name, "Xdoreti") || + !strncmp(name, "Xsoft", 5)) { + is_trap = INTERRUPT; + } else + goto normal; + } else + goto normal; + narg = 0; +#else + if (!strcmp(name, "_trap")) { + is_trap = TRAP; + } else if (!strcmp(name, "_syscall")) { + is_trap = SYSCALL; + } else if (name[0] == '_' && name[1] == 'X') { + if (!strncmp(name, "_Xintr", 6) || + !strncmp(name, "_Xresume", 8) || + !strncmp(name, "_Xstray", 7) || + !strncmp(name, "_Xhold", 6) || + !strncmp(name, "_Xrecurse", 9) || + !strcmp(name, "_Xdoreti") || + !strncmp(name, "_Xsoft", 6)) { + is_trap = INTERRUPT; + } else + goto normal; + } else + goto normal; + narg = 0; +#endif /* __ELF__ */ + } else { + normal: + is_trap = NONE; + narg = MAXNARG; + if (db_sym_numargs(sym, &narg, argnames)) + argnp = argnames; + else + narg = db_numargs(frame); + } + + (*pr)("%s(", name); + + if (lastframe == 0 && offset == 0 && !have_addr) { + /* + * We have a breakpoint before the frame is set up + * Use %esp instead + */ + argp = &((struct x86_64_frame *)(ddb_regs.tf_rsp-8))->f_arg0; + } else { + argp = &frame->f_arg0; + } + + while (narg) { + if (argnp) + (*pr)("%s=", *argnp++); + (*pr)("%lx", db_get_value((db_addr_t)argp, 8, FALSE)); + argp++; + if (--narg != 0) + (*pr)(","); + } + (*pr)(") at "); + db_printsym(callpc, DB_STGY_PROC, pr); + (*pr)("\n"); + + if (lastframe == 0 && offset == 0 && !have_addr) { + /* Frame really belongs to next callpc */ + lastframe = (struct x86_64_frame *)(ddb_regs.tf_rsp-8); + callpc = (db_addr_t) + db_get_value((db_addr_t)&lastframe->f_retaddr, + 8, FALSE); + continue; + } + + lastframe = frame; + db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap, pr); + + if (frame == 0) { + /* end of chain */ + break; + } + if (INKERNEL(frame)) { + /* staying in kernel */ + if (frame <= lastframe) { + (*pr)("Bad frame pointer: %p\n", frame); + break; + } + } else if (INKERNEL(lastframe)) { + /* switch from user to kernel */ + if (kernel_only) { + (*pr)("end of kernel\n"); + break; /* kernel stack only */ + } + } else { + /* in user */ + if (frame <= lastframe) { + (*pr)("Bad user frame pointer: %p\n", + frame); + break; + } + } + --count; + } + (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); + + if (count && is_trap != NONE) { + db_printsym(callpc, DB_STGY_XTRN, pr); + (*pr)(":\n"); + } +} diff --git a/sys/arch/amd64/amd64/disksubr.c b/sys/arch/amd64/amd64/disksubr.c new file mode 100644 index 00000000000..c44f592be57 --- /dev/null +++ b/sys/arch/amd64/amd64/disksubr.c @@ -0,0 +1,550 @@ +/* $OpenBSD: disksubr.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */ + +/* + * Copyright (c) 1996 Theo de Raadt + * Copyright (c) 1982, 1986, 1988 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. + * + * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/syslog.h> +#include <sys/disk.h> + +void +dk_establish(dk, dev) + struct disk *dk; + struct device *dev; +{ +} + +/* + * Attempt to read a disk label from a device + * using the indicated strategy routine. + * The label must be partly set up before this: + * secpercyl, secsize and anything required for a block i/o read + * operation in the driver's strategy/start routines + * must be filled in before calling us. + * + * If dos partition table requested, attempt to load it and + * find disklabel inside a DOS partition. Also, if bad block + * table needed, attempt to extract it as well. Return buffer + * for use in signalling errors if requested. + * + * We would like to check if each MBR has a valid DOSMBR_SIGNATURE, but + * we cannot because it doesn't always exist. So.. we assume the + * MBR is valid. + * + * Returns null on success and an error string on failure. + */ +char * +readdisklabel(dev, strat, lp, osdep, spoofonly) + dev_t dev; + void (*strat)(struct buf *); + register struct disklabel *lp; + struct cpu_disklabel *osdep; + int spoofonly; +{ + struct dos_partition *dp = osdep->dosparts, *dp2; + struct dkbad *bdp = &DKBAD(osdep); + struct buf *bp = NULL; + struct disklabel *dlp; + char *msg = NULL, *cp; + int dospartoff, cyl, i, ourpart = -1; + + /* minimal requirements for archtypal disk label */ + if (lp->d_secsize == 0) + lp->d_secsize = DEV_BSIZE; + if (lp->d_secpercyl == 0) { + msg = "invalid geometry"; + goto done; + } + if (lp->d_secperunit == 0) + lp->d_secperunit = 0x1fffffff; + lp->d_npartitions = RAW_PART + 1; + for (i = 0; i < RAW_PART; i++) { + lp->d_partitions[i].p_size = 0; + lp->d_partitions[i].p_offset = 0; + } + if (lp->d_partitions[i].p_size == 0) + lp->d_partitions[i].p_size = 0x1fffffff; + lp->d_partitions[i].p_offset = 0; + + /* get a buffer and initialize it */ + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + + /* do dos partitions in the process of getting disklabel? */ + dospartoff = 0; + cyl = LABELSECTOR / lp->d_secpercyl; + if (dp) { + daddr_t part_blkno = DOSBBSECTOR; + unsigned long extoff = 0; + int wander = 1, n = 0, loop = 0; + + /* + * Read dos partition table, follow extended partitions. + * Map the partitions to disklabel entries i-p + */ + while (wander && n < 8 && loop < 8) { + loop++; + wander = 0; + if (part_blkno < extoff) + part_blkno = extoff; + + /* read boot record */ + bp->b_blkno = part_blkno; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylinder = part_blkno / lp->d_secpercyl; + (*strat)(bp); + + /* if successful, wander through dos partition table */ + if (biowait(bp)) { + msg = "dos partition I/O error"; + goto done; + } + bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp)); + + if (ourpart == -1) { + /* Search for our MBR partition */ + for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; + i++, dp2++) + if (get_le(&dp2->dp_size) && + dp2->dp_typ == DOSPTYP_OPENBSD) + ourpart = i; + for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; + i++, dp2++) + if (get_le(&dp2->dp_size) && + dp2->dp_typ == DOSPTYP_FREEBSD) + ourpart = i; + for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; + i++, dp2++) + if (get_le(&dp2->dp_size) && + dp2->dp_typ == DOSPTYP_NETBSD) + ourpart = i; + if (ourpart == -1) + goto donot; + /* + * This is our MBR partition. need sector address + * for SCSI/IDE, cylinder for ESDI/ST506/RLL + */ + dp2 = &dp[ourpart]; + dospartoff = get_le(&dp2->dp_start) + part_blkno; + cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect); + + /* XXX build a temporary disklabel */ + lp->d_partitions[0].p_size = get_le(&dp2->dp_size); + lp->d_partitions[0].p_offset = + get_le(&dp2->dp_start) + part_blkno; + if (lp->d_ntracks == 0) + lp->d_ntracks = dp2->dp_ehd + 1; + if (lp->d_nsectors == 0) + lp->d_nsectors = DPSECT(dp2->dp_esect); + if (lp->d_secpercyl == 0) + lp->d_secpercyl = lp->d_ntracks * + lp->d_nsectors; + } +donot: + /* + * In case the disklabel read below fails, we want to + * provide a fake label in i-p. + */ + for (dp2=dp, i=0; i < NDOSPART && n < 8; i++, dp2++) { + struct partition *pp = &lp->d_partitions[8+n]; + + if (dp2->dp_typ == DOSPTYP_OPENBSD) + continue; + if (get_le(&dp2->dp_size) > lp->d_secperunit) + continue; + if (get_le(&dp2->dp_size)) + pp->p_size = get_le(&dp2->dp_size); + if (get_le(&dp2->dp_start)) + pp->p_offset = + get_le(&dp2->dp_start) + part_blkno; + + switch (dp2->dp_typ) { + case DOSPTYP_UNUSED: + for (cp = (char *)dp2; + cp < (char *)(dp2 + 1); cp++) + if (*cp) + break; + /* + * Was it all zeroes? If so, it is + * an unused entry that we don't + * want to show. + */ + if (cp == (char *)(dp2 + 1)) + continue; + lp->d_partitions[8 + n++].p_fstype = + FS_UNUSED; + break; + + case DOSPTYP_LINUX: + pp->p_fstype = FS_EXT2FS; + n++; + break; + + case DOSPTYP_FAT12: + case DOSPTYP_FAT16S: + case DOSPTYP_FAT16B: + case DOSPTYP_FAT32: + case DOSPTYP_FAT32L: + case DOSPTYP_FAT16L: + pp->p_fstype = FS_MSDOS; + n++; + break; + case DOSPTYP_EXTEND: + case DOSPTYP_EXTENDL: + part_blkno = get_le(&dp2->dp_start) + extoff; + if (!extoff) { + extoff = get_le(&dp2->dp_start); + part_blkno = 0; + } + wander = 1; + break; + default: + pp->p_fstype = FS_OTHER; + n++; + break; + } + } + } + lp->d_bbsize = 8192; + lp->d_sbsize = 64*1024; /* XXX ? */ + lp->d_npartitions = MAXPARTITIONS; + } + + /* don't read the on-disk label if we are in spoofed-only mode */ + if (spoofonly) + goto done; + + /* next, dig out disk label */ + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_cylinder = cyl; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if (biowait(bp)) { + /* XXX we return the faked label built so far */ + msg = "disk label I/O error"; + goto done; + } + for (dlp = (struct disklabel *)bp->b_data; + dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof(*dlp)); + dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { + if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { + if (msg == NULL) + msg = "no disk label"; + } else if (dlp->d_npartitions > MAXPARTITIONS || + dkcksum(dlp) != 0) + msg = "disk label corrupted"; + else { + *lp = *dlp; + msg = NULL; + break; + } + } + + if (msg) { +#if defined(CD9660) + if (iso_disklabelspoof(dev, strat, lp) == 0) + msg = NULL; +#endif + goto done; + } + + /* obtain bad sector table if requested and present */ + if (bdp && (lp->d_flags & D_BADSECT)) { + struct dkbad *db; + + i = 0; + do { + /* read a bad sector table */ + bp->b_flags = B_BUSY | B_READ; + bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i; + if (lp->d_secsize > DEV_BSIZE) + bp->b_blkno *= lp->d_secsize / DEV_BSIZE; + else + bp->b_blkno /= DEV_BSIZE / lp->d_secsize; + bp->b_bcount = lp->d_secsize; + bp->b_cylinder = lp->d_ncylinders - 1; + (*strat)(bp); + + /* if successful, validate, otherwise try another */ + if (biowait(bp)) { + msg = "bad sector table I/O error"; + } else { + db = (struct dkbad *)(bp->b_data); +#define DKBAD_MAGIC 0x4321 + if (db->bt_mbz == 0 + && db->bt_flag == DKBAD_MAGIC) { + msg = NULL; + *bdp = *db; + break; + } else + msg = "bad sector table corrupted"; + } + } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && + i < lp->d_nsectors); + } + +done: + if (bp) { + bp->b_flags |= B_INVAL; + brelse(bp); + } + return (msg); +} + +/* + * Check new disk label for sensibility + * before setting it. + */ +int +setdisklabel(olp, nlp, openmask, osdep) + register struct disklabel *olp, *nlp; + u_long openmask; + struct cpu_disklabel *osdep; +{ + register int i; + register struct partition *opp, *npp; + + /* sanity clause */ + if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 || + (nlp->d_secsize % DEV_BSIZE) != 0) + return(EINVAL); + + /* special case to allow disklabel to be invalidated */ + if (nlp->d_magic == 0xffffffff) { + *olp = *nlp; + return (0); + } + + if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || + dkcksum(nlp) != 0) + return (EINVAL); + + /* XXX missing check if other dos partitions will be overwritten */ + + while (openmask != 0) { + i = ffs(openmask) - 1; + openmask &= ~(1 << i); + if (nlp->d_npartitions <= i) + return (EBUSY); + opp = &olp->d_partitions[i]; + npp = &nlp->d_partitions[i]; + if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) + return (EBUSY); + /* + * Copy internally-set partition information + * if new label doesn't include it. XXX + */ + if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { + npp->p_fstype = opp->p_fstype; + npp->p_fsize = opp->p_fsize; + npp->p_frag = opp->p_frag; + npp->p_cpg = opp->p_cpg; + } + } + nlp->d_checksum = 0; + nlp->d_checksum = dkcksum(nlp); + *olp = *nlp; + return (0); +} + + +/* + * Write disk label back to device after modification. + * XXX cannot handle OpenBSD partitions in extended partitions! + */ +int +writedisklabel(dev, strat, lp, osdep) + dev_t dev; + void (*strat)(struct buf *); + register struct disklabel *lp; + struct cpu_disklabel *osdep; +{ + struct dos_partition *dp = osdep->dosparts, *dp2; + struct buf *bp; + struct disklabel *dlp; + int error, dospartoff, cyl, i; + int ourpart = -1; + + /* get a buffer and initialize it */ + bp = geteblk((int)lp->d_secsize); + bp->b_dev = dev; + + /* do dos partitions in the process of getting disklabel? */ + dospartoff = 0; + cyl = LABELSECTOR / lp->d_secpercyl; + if (dp) { + /* read master boot record */ + bp->b_blkno = DOSBBSECTOR; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + bp->b_cylinder = DOSBBSECTOR / lp->d_secpercyl; + (*strat)(bp); + + if ((error = biowait(bp)) != 0) + goto done; + + /* XXX how do we check veracity/bounds of this? */ + bcopy(bp->b_data + DOSPARTOFF, dp, + NDOSPART * sizeof(*dp)); + + for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) + if (get_le(&dp2->dp_size) && dp2->dp_typ == DOSPTYP_OPENBSD) + ourpart = i; + for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) + if (get_le(&dp2->dp_size) && dp2->dp_typ == DOSPTYP_FREEBSD) + ourpart = i; + for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++) + if (get_le(&dp2->dp_size) && dp2->dp_typ == DOSPTYP_NETBSD) + ourpart = i; + + if (ourpart != -1) { + dp2 = &dp[ourpart]; + + /* + * need sector address for SCSI/IDE, + * cylinder for ESDI/ST506/RLL + */ + dospartoff = get_le(&dp2->dp_start); + cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect); + } + } + + /* next, dig out disk label */ + bp->b_blkno = dospartoff + LABELSECTOR; + bp->b_cylinder = cyl; + bp->b_bcount = lp->d_secsize; + bp->b_flags = B_BUSY | B_READ; + (*strat)(bp); + + /* if successful, locate disk label within block and validate */ + if ((error = biowait(bp)) != 0) + goto done; + for (dlp = (struct disklabel *)bp->b_data; + dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize - sizeof(*dlp)); + dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { + if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && + dkcksum(dlp) == 0) { + *dlp = *lp; + bp->b_flags = B_BUSY | B_WRITE; + (*strat)(bp); + error = biowait(bp); + goto done; + } + } + + /* Write it in the regular place. */ + *(struct disklabel *)bp->b_data = *lp; + bp->b_flags = B_BUSY | B_WRITE; + (*strat)(bp); + error = biowait(bp); + goto done; + +done: + bp->b_flags |= B_INVAL; + brelse(bp); + return (error); +} + +/* + * 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(bp, lp, osdep, wlabel) + struct buf *bp; + struct disklabel *lp; + struct cpu_disklabel *osdep; + int wlabel; +{ +#define blockpersec(count, lp) ((count) * (((lp)->d_secsize) / DEV_BSIZE)) + struct partition *p = lp->d_partitions + DISKPART(bp->b_dev); + int labelsector = blockpersec(lp->d_partitions[RAW_PART].p_offset, lp) + + LABELSECTOR; + int sz = howmany(bp->b_bcount, DEV_BSIZE); + + /* avoid division by zero */ + if (lp->d_secpercyl == 0) { + bp->b_error = EINVAL; + goto bad; + } + + /* beyond partition? */ + if (bp->b_blkno + sz > blockpersec(p->p_size, lp)) { + sz = blockpersec(p->p_size, lp) - bp->b_blkno; + if (sz == 0) { + /* If exactly at end of disk, return EOF. */ + bp->b_resid = bp->b_bcount; + goto done; + } + if (sz < 0) { + /* If past end of disk, return EINVAL. */ + bp->b_error = EINVAL; + goto bad; + } + /* Otherwise, truncate request. */ + bp->b_bcount = sz << DEV_BSHIFT; + } + + /* Overwriting disk label? */ + if (bp->b_blkno + blockpersec(p->p_offset, lp) <= labelsector && +#if LABELSECTOR != 0 + bp->b_blkno + blockpersec(p->p_offset, lp) + sz > labelsector && +#endif + (bp->b_flags & B_READ) == 0 && !wlabel) { + bp->b_error = EROFS; + goto bad; + } + + /* calculate cylinder for disksort to order transfers with */ + bp->b_cylinder = (bp->b_blkno + blockpersec(p->p_offset, lp)) / + lp->d_secpercyl; + return (1); + +bad: + bp->b_flags |= B_ERROR; +done: + return (0); +} diff --git a/sys/arch/amd64/amd64/fpu.c b/sys/arch/amd64/amd64/fpu.c new file mode 100644 index 00000000000..9b874b9b251 --- /dev/null +++ b/sys/arch/amd64/amd64/fpu.c @@ -0,0 +1,309 @@ +/* $OpenBSD: fpu.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: fpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ + +/*- + * Copyright (c) 1994, 1995, 1998 Charles M. Hannum. All rights reserved. + * Copyright (c) 1990 William Jolitz. + * Copyright (c) 1991 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. + * + * @(#)npx.c 7.2 (Berkeley) 5/12/91 + */ + +/* + * XXXfvdl update copyright notice. this started out as a stripped isa/npx.c + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/vmmeter.h> +#include <sys/signalvar.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/cpufunc.h> +#include <machine/pcb.h> +#include <machine/trap.h> +#include <machine/specialreg.h> +#include <machine/fpu.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> + +/* + * We do lazy initialization and switching using the TS bit in cr0 and the + * MDP_USEDFPU bit in mdproc. + * + * DNA exceptions are handled like this: + * + * 1) If there is no FPU, return and go to the emulator. + * 2) If someone else has used the FPU, save its state into that process' PCB. + * 3a) If MDP_USEDFPU is not set, set it and initialize the FPU. + * 3b) Otherwise, reload the process' previous FPU state. + * + * When a process is created or exec()s, its saved cr0 image has the TS bit + * set and the MDP_USEDFPU bit clear. The MDP_USEDFPU bit is set when the + * process first gets a DNA and the FPU is initialized. The TS bit is turned + * off when the FPU is used, and turned on again later when the process' FPU + * state is saved. + */ + +#define fninit() __asm("fninit") +#define fwait() __asm("fwait") +#define fxsave(addr) __asm("fxsave %0" : "=m" (*addr)) +#define fxrstor(addr) __asm("fxrstor %0" : : "m" (*addr)) +#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr)) +#define clts() __asm("clts") +#define stts() lcr0(rcr0() | CR0_TS) + +void fpudna(struct cpu_info *); + +/* + * Init the FPU. + */ +void +fpuinit(struct cpu_info *ci) +{ + lcr0(rcr0() & ~(CR0_EM|CR0_TS)); + fninit(); + lcr0(rcr0() | (CR0_TS)); +} + +/* + * Record the FPU state and reinitialize it all except for the control word. + * Then generate a SIGFPE. + * + * Reinitializing the state allows naive SIGFPE handlers to longjmp without + * doing any fixups. + */ + +void +fputrap(struct trapframe *frame) +{ + struct proc *p = curcpu()->ci_fpcurproc; + struct savefpu *sfp = &p->p_addr->u_pcb.pcb_savefpu; + u_int16_t cw; + union sigval sv; + +printf("fputrap\n"); +#ifdef DIAGNOSTIC + /* + * At this point, fpcurproc should be curproc. If it wasn't, + * the TS bit should be set, and we should have gotten a DNA exception. + */ + if (p != curproc) + panic("fputrap: wrong proc"); +#endif + + fxsave(sfp); + if (frame->tf_trapno == T_XMM) { + } else { + fninit(); + fwait(); + cw = sfp->fp_fxsave.fx_fcw; + fldcw(&cw); + fwait(); + } + sfp->fp_ex_tw = sfp->fp_fxsave.fx_ftw; + sfp->fp_ex_sw = sfp->fp_fxsave.fx_fsw; + sv.sival_ptr = (void *)frame->tf_rip; /* XXX - ? */ + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGFPE, frame->tf_err, 0 /* XXX */, sv); + KERNEL_PROC_UNLOCK(p); +} + +/* + * Implement device not available (DNA) exception + * + * If we were the last process to use the FPU, we can simply return. + * Otherwise, we save the previous state, if necessary, and restore our last + * saved state. + */ +void +fpudna(struct cpu_info *ci) +{ + u_int16_t cw; + struct proc *p; + int s; + + if (ci->ci_fpsaving) { + printf("recursive fpu trap; cr0=%x\n", rcr0()); + return; + } + + s = splipi(); + +#ifdef MULTIPROCESSOR + p = ci->ci_curproc; +#else + p = curproc; +#endif + + /* + * Initialize the FPU state to clear any exceptions. If someone else + * was using the FPU, save their state. + */ + if (ci->ci_fpcurproc != NULL && ci->ci_fpcurproc != p) + fpusave_cpu(ci, 1); + else { + clts(); + fninit(); + fwait(); + stts(); + } + splx(s); + + if (p == NULL) { + clts(); + return; + } + + KDASSERT(ci->ci_fpcurproc == NULL); +#ifndef MULTIPROCESSOR + KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL); +#else + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 1); +#endif + + p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS; + clts(); + + s = splipi(); + ci->ci_fpcurproc = p; + p->p_addr->u_pcb.pcb_fpcpu = ci; + splx(s); + + if ((p->p_md.md_flags & MDP_USEDFPU) == 0) { + cw = p->p_addr->u_pcb.pcb_savefpu.fp_fxsave.fx_fcw; + fldcw(&cw); + p->p_md.md_flags |= MDP_USEDFPU; + } else + fxrstor(&p->p_addr->u_pcb.pcb_savefpu); +} + + +void +fpusave_cpu(struct cpu_info *ci, int save) +{ + struct proc *p; + int s; + + KDASSERT(ci == curcpu()); + + p = ci->ci_fpcurproc; + if (p == NULL) + return; + + if (save) { +#ifdef DIAGNOSTIC + if (ci->ci_fpsaving != 0) + panic("fpusave_cpu: recursive save!"); +#endif + /* + * Set ci->ci_fpsaving, so that any pending exception will be + * thrown away. (It will be caught again if/when the FPU + * state is restored.) + */ + clts(); + ci->ci_fpsaving = 1; + fxsave(&p->p_addr->u_pcb.pcb_savefpu); + ci->ci_fpsaving = 0; + } + + stts(); + p->p_addr->u_pcb.pcb_cr0 |= CR0_TS; + + s = splipi(); + p->p_addr->u_pcb.pcb_fpcpu = NULL; + ci->ci_fpcurproc = NULL; + splx(s); +} + +/* + * Save l's FPU state, which may be on this processor or another processor. + */ +void +fpusave_proc(struct proc *p, int save) +{ + struct cpu_info *ci = curcpu(); + struct cpu_info *oci; + + KDASSERT(p->p_addr != NULL); + KDASSERT(p->p_flag & P_INMEM); + + oci = p->p_addr->u_pcb.pcb_fpcpu; + if (oci == NULL) + return; + +#if defined(MULTIPROCESSOR) + if (oci == ci) { + int s = splipi(); + fpusave_cpu(ci, save); + splx(s); + } else { +#ifdef DIAGNOSTIC + int spincount; +#endif + + x86_send_ipi(oci, + save ? X86_IPI_SYNCH_FPU : X86_IPI_FLUSH_FPU); + +#ifdef DIAGNOSTIC + spincount = 0; +#endif + while (p->dpl_addr->u_pcb.pcb_fpcpu != NULL) +#ifdef DIAGNOSTIC + { + spincount++; + if (spincount > 10000000) { + panic("fp_save ipi didn't"); + } + } +#else + __splbarrier(); /* XXX replace by generic barrier */ + ; +#endif + } +#else + KASSERT(ci->ci_fpcurproc == p); + fpusave_cpu(ci, save); +#endif +} diff --git a/sys/arch/amd64/amd64/gdt.c b/sys/arch/amd64/amd64/gdt.c new file mode 100644 index 00000000000..4790b079614 --- /dev/null +++ b/sys/arch/amd64/amd64/gdt.c @@ -0,0 +1,374 @@ +/* $OpenBSD: gdt.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: gdt.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by John T. Kohl and Charles M. Hannum. + * + * 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. + */ + +/* + * Modified to deal with variable-length entries for NetBSD/x86_64 by + * fvdl@wasabisystems.com, may 2001 + * XXX this file should be shared with the i386 code, the difference + * can be hidden in macros. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/lock.h> +#include <sys/user.h> + +#include <uvm/uvm.h> + +#include <machine/gdt.h> + +#define MINGDTSIZ 2048 +#define MAXGDTSIZ 65536 + +int gdt_size; /* size of GDT in bytes */ +int gdt_dyncount; /* number of dyn. allocated GDT entries in use */ +int gdt_dynavail; +int gdt_next; /* next available slot for sweeping */ +int gdt_free; /* next free slot; terminated with GNULL_SEL */ + +struct lock gdt_lock_store; + +static __inline void gdt_lock(void); +static __inline void gdt_unlock(void); +void gdt_init(void); +void gdt_grow(void); +int gdt_get_slot(void); +void gdt_put_slot(int); + +/* + * Lock and unlock the GDT, to avoid races in case gdt_{ge,pu}t_slot() sleep + * waiting for memory. + * + * Note that the locking done here is not sufficient for multiprocessor + * systems. A freshly allocated slot will still be of type SDT_SYSNULL for + * some time after the GDT is unlocked, so gdt_compact() could attempt to + * reclaim it. + */ +static __inline void +gdt_lock() +{ + + (void) lockmgr(&gdt_lock_store, LK_EXCLUSIVE, NULL, curproc); +} + +static __inline void +gdt_unlock() +{ + + (void) lockmgr(&gdt_lock_store, LK_RELEASE, NULL, curproc); +} + +void +set_mem_gdt(sd, base, limit, type, dpl, gran, def32, is64) + struct mem_segment_descriptor *sd; + void *base; + size_t limit; + int type, dpl, gran, def32, is64; +{ + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + int off; + + set_mem_segment(sd, base, limit, type, dpl, gran, def32, is64); + off = (char *)sd - gdtstore; + for (CPU_INFO_FOREACH(cii, ci)) { + if (ci->ci_gdt != NULL) + *(struct mem_segment_descriptor *)(ci->ci_gdt + off) = + *sd; + } +} + +void +set_sys_gdt(sd, base, limit, type, dpl, gran) + struct sys_segment_descriptor *sd; + void *base; + size_t limit; + int type, dpl, gran; +{ + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + int off; + + set_sys_segment(sd, base, limit, type, dpl, gran); + off = (char *)sd - gdtstore; + for (CPU_INFO_FOREACH(cii, ci)) { + if (ci->ci_gdt != NULL) + *(struct sys_segment_descriptor *)(ci->ci_gdt + off) = + *sd; + } +} + + +/* + * Initialize the GDT. + */ +void +gdt_init() +{ + char *old_gdt; + struct vm_page *pg; + vaddr_t va; + struct cpu_info *ci = &cpu_info_primary; + + lockinit(&gdt_lock_store, PZERO, "gdtlck", 0, 0); + + gdt_size = MINGDTSIZ; + gdt_dyncount = 0; + gdt_next = 0; + gdt_free = GNULL_SEL; + gdt_dynavail = + (gdt_size - DYNSEL_START) / sizeof (struct sys_segment_descriptor); + + old_gdt = gdtstore; + gdtstore = (char *)uvm_km_valloc(kernel_map, MAXGDTSIZ); + for (va = (vaddr_t)gdtstore; va < (vaddr_t)gdtstore + MINGDTSIZ; + va += PAGE_SIZE) { + pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO); + if (pg == NULL) { + panic("gdt_init: no pages"); + } + pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), + VM_PROT_READ | VM_PROT_WRITE); + } + memcpy(gdtstore, old_gdt, DYNSEL_START); + ci->ci_gdt = gdtstore; + set_sys_segment(GDT_ADDR_SYS(gdtstore, GLDT_SEL), ldtstore, + LDT_SIZE - 1, SDT_SYSLDT, SEL_KPL, 0); + + gdt_init_cpu(ci); +} + +/* + * Allocate shadow GDT for a slave cpu. + */ +void +gdt_alloc_cpu(struct cpu_info *ci) +{ + ci->ci_gdt = (char *)uvm_km_valloc(kernel_map, MAXGDTSIZ); + uvm_map_pageable(kernel_map, (vaddr_t)ci->ci_gdt, + (vaddr_t)ci->ci_gdt + MINGDTSIZ, FALSE, FALSE); + memset(ci->ci_gdt, 0, MINGDTSIZ); + memcpy(ci->ci_gdt, gdtstore, + DYNSEL_START + gdt_dyncount * sizeof(struct sys_segment_descriptor)); +} + + +/* + * Load appropriate gdt descriptor; we better be running on *ci + * (for the most part, this is how a cpu knows who it is). + */ +void +gdt_init_cpu(struct cpu_info *ci) +{ + struct region_descriptor region; + + setregion(®ion, ci->ci_gdt, (u_int16_t)(MAXGDTSIZ - 1)); + lgdt(®ion); +} + +#ifdef MULTIPROCESSOR + +void +gdt_reload_cpu(struct cpu_info *ci) +{ + struct region_descriptor region; + + setregion(®ion, ci->ci_gdt, MAXGDTSIZ - 1); + lgdt(®ion); +} +#endif + + +/* + * Grow or shrink the GDT. + */ +void +gdt_grow() +{ + size_t old_len, new_len; + struct vm_page *pg; + vaddr_t va; + + old_len = gdt_size; + gdt_size <<= 1; + new_len = old_len << 1; + gdt_dynavail = + (gdt_size - DYNSEL_START) / sizeof (struct sys_segment_descriptor); + + for (va = (vaddr_t)gdtstore + old_len; va < (vaddr_t)gdtstore + new_len; + va += PAGE_SIZE) { + while ((pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO)) == + NULL) { + uvm_wait("gdt_grow"); + } + pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), + VM_PROT_READ | VM_PROT_WRITE); + } +} + +/* + * Allocate a GDT slot as follows: + * 1) If there are entries on the free list, use those. + * 2) If there are fewer than gdt_dynavail entries in use, there are free slots + * near the end that we can sweep through. + * 3) As a last resort, we increase the size of the GDT, and sweep through + * the new slots. + */ +int +gdt_get_slot() +{ + int slot; + struct sys_segment_descriptor *gdt; + + gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START]; + + gdt_lock(); + + if (gdt_free != GNULL_SEL) { + slot = gdt_free; + gdt_free = gdt[slot].sd_xx3; /* XXXfvdl res. field abuse */ + } else { +#ifdef DIAGNOSTIC + if (gdt_next != gdt_dyncount) + panic("gdt_get_slot botch 1"); +#endif + if (gdt_next >= gdt_dynavail) { +#ifdef DIAGNOSTIC + if (gdt_size >= MAXGDTSIZ) + panic("gdt_get_slot botch 2"); +#endif + gdt_grow(); + } + slot = gdt_next++; + } + + gdt_dyncount++; + gdt_unlock(); + return (slot); +} + +/* + * Deallocate a GDT slot, putting it on the free list. + */ +void +gdt_put_slot(slot) + int slot; +{ + struct sys_segment_descriptor *gdt; + + gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START]; + + gdt_lock(); + gdt_dyncount--; + + gdt[slot].sd_type = SDT_SYSNULL; + gdt[slot].sd_xx3 = gdt_free; + gdt_free = slot; + + gdt_unlock(); +} + +int +tss_alloc(pcb) + struct pcb *pcb; +{ + int slot; + struct sys_segment_descriptor *gdt; + + gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START]; + + slot = gdt_get_slot(); +#if 0 + printf("tss_alloc: slot %d addr %p\n", slot, &gdt[slot]); +#endif + set_sys_gdt(&gdt[slot], &pcb->pcb_tss, sizeof (struct x86_64_tss)-1, + SDT_SYS386TSS, SEL_KPL, 0); +#if 0 + printf("lolimit %lx lobase %lx type %lx dpl %lx p %lx hilimit %lx\n" + "xx1 %lx gran %lx hibase %lx xx2 %lx zero %lx xx3 %lx pad %lx\n", + (unsigned long)gdt[slot].sd_lolimit, + (unsigned long)gdt[slot].sd_lobase, + (unsigned long)gdt[slot].sd_type, + (unsigned long)gdt[slot].sd_dpl, + (unsigned long)gdt[slot].sd_p, + (unsigned long)gdt[slot].sd_hilimit, + (unsigned long)gdt[slot].sd_xx1, + (unsigned long)gdt[slot].sd_gran, + (unsigned long)gdt[slot].sd_hibase, + (unsigned long)gdt[slot].sd_xx2, + (unsigned long)gdt[slot].sd_zero, + (unsigned long)gdt[slot].sd_xx3); +#endif + return GDYNSEL(slot, SEL_KPL); +} + +void +tss_free(int sel) +{ + + gdt_put_slot(IDXDYNSEL(sel)); +} + +void +ldt_alloc(pmap, ldt, len) + struct pmap *pmap; + char *ldt; + size_t len; +{ + int slot; + struct sys_segment_descriptor *gdt; + + gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START]; + + slot = gdt_get_slot(); + set_sys_gdt(&gdt[slot], ldt, len - 1, SDT_SYSLDT, SEL_KPL, 0); + pmap->pm_ldt_sel = GSEL(slot, SEL_KPL); +} + +void +ldt_free(pmap) + struct pmap *pmap; +{ + int slot; + + slot = IDXDYNSEL(pmap->pm_ldt_sel); + + gdt_put_slot(slot); +} diff --git a/sys/arch/amd64/amd64/genassym.cf b/sys/arch/amd64/amd64/genassym.cf new file mode 100644 index 00000000000..da5462ebd46 --- /dev/null +++ b/sys/arch/amd64/amd64/genassym.cf @@ -0,0 +1,122 @@ +# $OpenBSD: genassym.cf,v 1.1 2004/01/28 01:39:38 mickey Exp $ + +# Written by Artur Grabowski art@openbsd.org, Public Domain + +include <sys/param.h> +include <sys/proc.h> +include <sys/resourcevar.h> +include <sys/device.h> +include <sys/user.h> + +include <uvm/uvm.h> + +include <machine/trap.h> +include <machine/pmap.h> +include <machine/vmparam.h> +include <machine/intr.h> + +export SRUN + +define L3_SLOT_KERNBASE pl3_pi(KERNBASE) +define L2_SLOT_KERNBASE pl2_pi(KERNBASE) +define L1_SLOT_KERNBASE pl1_pi(KERNBASE) + +export VM_MAXUSER_ADDRESS +export VM_MIN_KERNEL_ADDRESS + +define UVM_PAGE_IDLE_ZERO offsetof(struct uvm, page_idle_zero) + +struct proc +member p_addr +member p_back +member p_forw +member p_priority +member p_stat +member p_wchan +member P_MD_TSS_SEL p_md.md_tss_sel +member P_MD_REGS p_md.md_regs +member P_MD_FLAGS p_md.md_flags +member P_MD_SYSCALL p_md.md_syscall +member P_MD_ASTPENDING p_md.md_astpending +member p_flag + +export P_SYSTEM + +export MDP_IRET + +struct uvmexp V_ +member INTR intrs + +struct trapframe +member tf_rdi +member tf_rsi +member tf_rdx +member tf_rcx +member tf_r8 +member tf_r9 +member tf_r10 +member tf_r11 +member tf_r12 +member tf_r13 +member tf_r14 +member tf_r15 +member tf_rbp +member tf_rbx +member tf_rax +member tf_gs +member tf_fs +member tf_es +member tf_ds +member tf_trapno +member tf_err +member tf_rip +member tf_cs +member tf_rflags +member tf_rsp +member tf_ss + +define FRAMESIZE sizeof(struct trapframe) + +struct pcb +member pcb_cr3 +member pcb_rbp +member pcb_rsp +member pcb_usersp +member PCB_RSP0 pcb_tss.tss_rsp0 +member pcb_cr0 +member pcb_ldt_sel +member pcb_onfault +member pcb_fpcpu + +struct cpu_info +member CPU_INFO_SCRATCH ci_scratch +member CPU_INFO_SELF ci_self +member CPU_INFO_RESCHED ci_want_resched +member CPU_INFO_CURPROC ci_curproc +member CPU_INFO_CURPCB ci_curpcb +member CPU_INFO_IDLE_PCB ci_idle_pcb +member CPU_INFO_IDLE_TSS_SEL ci_idle_tss_sel +member CPU_INFO_ASTPENDING ci_astpending +member CPU_INFO_ILEVEL ci_ilevel +member CPU_INFO_IDEPTH ci_idepth +member CPU_INFO_ISOURCES ci_isources +member CPU_INFO_IPENDING ci_ipending +member CPU_INFO_IUNMASK ci_iunmask + +struct intrsource +member is_recurse +member is_resume +member is_evcnt +member is_handlers +member is_pic +member is_flags +member is_pin +member is_type +member is_maxlevel + +struct intrhand +member ih_fun +member ih_arg +member ih_next +member ih_level + diff --git a/sys/arch/amd64/amd64/i8259.c b/sys/arch/amd64/amd64/i8259.c new file mode 100644 index 00000000000..12b04b2a40b --- /dev/null +++ b/sys/arch/amd64/amd64/i8259.c @@ -0,0 +1,255 @@ +/* $OpenBSD: i8259.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: i8259.c,v 1.2 2003/03/02 18:27:15 fvdl Exp $ */ + +/* + * Copyright 2002 (c) Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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) 1991 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. + * + * @(#)isa.c 7.2 (Berkeley) 5/13/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> + +#include <dev/isa/isareg.h> + +#include <machine/pio.h> +#include <machine/cpufunc.h> +#include <machine/cpu.h> +#include <machine/pic.h> +#include <machine/i8259.h> + + +#ifndef __x86_64__ +#include "mca.h" +#if NMCA > 0 +#include <machine/mca_machdep.h> /* for MCA_system */ +#endif +#endif + +static void i8259_hwmask(struct pic *, int); +static void i8259_hwunmask(struct pic *, int); +static void i8259_setup(struct pic *, struct cpu_info *, int, int, int); +static void i8259_reinit_irqs(void); + +unsigned i8259_imen; + +/* + * Perhaps this should be made into a real device. + */ +struct pic i8259_pic = { + {0, {NULL}, NULL, 0, "pic0", NULL, 0, 0}, + PIC_I8259, +#ifdef MULTIPROCESSOR + __SIMPLELOCK_UNLOCKED, +#else + 0, +#endif + i8259_hwmask, + i8259_hwunmask, + i8259_setup, + i8259_setup, + i8259_stubs, + i8259_stubs, +}; + +void +i8259_default_setup(void) +{ +#if NMCA > 0 + /* level-triggered interrupts on MCA PS/2s */ + if (MCA_system) + outb(IO_ICU1, 0x19); /* reset; program device, four bytes */ + else +#endif + outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ + + outb(IO_ICU1+1, ICU_OFFSET); /* starting at this vector index */ + outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */ +#ifdef AUTO_EOI_1 + outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ +#else + outb(IO_ICU1+1, 1); /* 8086 mode */ +#endif + outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ + outb(IO_ICU1, 0x68); /* special mask mode (if available) */ + outb(IO_ICU1, 0x0a); /* Read IRR by default. */ +#ifdef REORDER_IRQ + outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ +#endif + +#if NMCA > 0 + /* level-triggered interrupts on MCA PS/2s */ + if (MCA_system) + outb(IO_ICU2, 0x19); /* reset; program device, four bytes */ + else +#endif + outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ + + outb(IO_ICU2+1, ICU_OFFSET+8); /* staring at this vector index */ + outb(IO_ICU2+1, IRQ_SLAVE); +#ifdef AUTO_EOI_2 + outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ +#else + outb(IO_ICU2+1, 1); /* 8086 mode */ +#endif + outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ + outb(IO_ICU2, 0x68); /* special mask mode (if available) */ + outb(IO_ICU2, 0x0a); /* Read IRR by default. */ +} + +static void +i8259_hwmask(struct pic *pic, int pin) +{ + unsigned port; + u_int8_t byte; + + i8259_imen |= (1 << pin); +#ifdef PIC_MASKDELAY + delay(10); +#endif + if (pin > 7) { + port = IO_ICU2 + 1; + byte = i8259_imen >> 8; + } else { + port = IO_ICU1 + 1; + byte = i8259_imen & 0xff; + } + outb(port, byte); +} + +static void +i8259_hwunmask(struct pic *pic, int pin) +{ + unsigned port; + u_int8_t byte; + + disable_intr(); /* XXX */ + i8259_imen &= ~(1 << pin); +#ifdef PIC_MASKDELAY + delay(10); +#endif + if (pin > 7) { + port = IO_ICU2 + 1; + byte = i8259_imen >> 8; + } else { + port = IO_ICU1 + 1; + byte = i8259_imen & 0xff; + } + outb(port, byte); + enable_intr(); +} + +static void +i8259_reinit_irqs(void) +{ + int irqs, irq; + struct cpu_info *ci = &cpu_info_primary; + + irqs = 0; + for (irq = 0; irq < NUM_LEGACY_IRQS; irq++) + if (ci->ci_isources[irq] != NULL) + irqs |= 1 << irq; + if (irqs >= 0x100) /* any IRQs >= 8 in use */ + irqs |= 1 << IRQ_SLAVE; + i8259_imen = ~irqs; + + outb(IO_ICU1 + 1, i8259_imen); + outb(IO_ICU2 + 1, i8259_imen >> 8); +} + +static void +i8259_setup(struct pic *pic, struct cpu_info *ci, int pin, int idtvec, int type) +{ + if (CPU_IS_PRIMARY(ci)) + i8259_reinit_irqs(); +} + +void +i8259_reinit(void) +{ + i8259_default_setup(); + i8259_reinit_irqs(); +} + +unsigned +i8259_setmask(unsigned mask) +{ + unsigned old = i8259_imen; + + i8259_imen = mask; + outb(IO_ICU1 + 1, i8259_imen); + outb(IO_ICU2 + 1, i8259_imen >> 8); + return old; +} diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c new file mode 100644 index 00000000000..6535b5e768c --- /dev/null +++ b/sys/arch/amd64/amd64/identcpu.c @@ -0,0 +1,105 @@ +/* $OpenBSD: identcpu.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ + +/* + * Copyright (c) 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#include <sys/types.h> +#include <sys/systm.h> +#include <machine/cpu.h> +#include <machine/cpufunc.h> + +/* sysctl wants this. */ +char cpu_model[48]; + +void +identifycpu(struct cpu_info *ci) +{ + u_int64_t last_tsc; + u_int32_t dummy, val; + u_int32_t brand[12]; + + CPUID(1, ci->ci_signature, val, dummy, ci->ci_feature_flags); + CPUID(0x80000001, dummy, dummy, dummy, val); + ci->ci_feature_flags |= val; + + CPUID(0x80000002, brand[0], brand[1], brand[2], brand[3]); + CPUID(0x80000003, brand[4], brand[5], brand[6], brand[7]); + CPUID(0x80000004, brand[8], brand[9], brand[10], brand[11]); + + strlcpy(cpu_model, (char *)brand, sizeof(cpu_model)); + if (cpu_model[0] == 0) + strlcpy(cpu_model, "Opteron or Athlon 64", sizeof(cpu_model)); + + last_tsc = rdtsc(); + delay(100000); + ci->ci_tsc_freq = (rdtsc() - last_tsc) * 10; + + amd_cpu_cacheinfo(ci); + + printf("%s: %s", ci->ci_dev->dv_xname, cpu_model); + + if (ci->ci_tsc_freq != 0) + printf(", %lu.%02lu MHz", (ci->ci_tsc_freq + 4999) / 1000000, + ((ci->ci_tsc_freq + 4999) / 10000) % 100); + printf("\n"); + + if ((ci->ci_feature_flags & CPUID_MASK1) != 0) { + printf("%s: features: %b\n", ci->ci_dev->dv_xname, + ci->ci_feature_flags, CPUID_FLAGS1); + } + if ((ci->ci_feature_flags & CPUID_MASK2) != 0) { + printf("%s: features: %b\n", ci->ci_dev->dv_xname, + ci->ci_feature_flags, CPUID_EXT_FLAGS2); + } + if ((ci->ci_feature_flags & CPUID_MASK3) != 0) { + printf("%s: features: %b\n", ci->ci_dev->dv_xname, + ci->ci_feature_flags, CPUID_EXT_FLAGS3); + } + + x86_print_cacheinfo(ci); + + return; /* TODO - warning to fix this ifdef later */ +#ifdef notyet + microtime_func = cc_microtime; +#endif +} + +void +cpu_probe_features(struct cpu_info *ci) +{ + ci->ci_feature_flags = cpu_feature; + ci->ci_signature = 0; +} diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c new file mode 100644 index 00000000000..a80798e3a44 --- /dev/null +++ b/sys/arch/amd64/amd64/intr.c @@ -0,0 +1,707 @@ +/* $OpenBSD: intr.c,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: intr.c,v 1.3 2003/03/03 22:16:20 fvdl Exp $ */ + +/* + * Copyright 2002 (c) Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +/* #define INTRDEBUG */ + +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/errno.h> + +#include <machine/atomic.h> +#include <machine/i8259.h> +#include <machine/cpu.h> +#include <machine/pio.h> + +#include "ioapic.h" +#include "lapic.h" + +#if NIOAPIC > 0 +#include <machine/i82093var.h> +#include <machine/mpbiosvar.h> +#endif + +#if NLAPIC > 0 +#include <machine/i82489var.h> +#endif + +struct pic softintr_pic = { + {0, {NULL}, NULL, 0, "softintr_fakepic", NULL, 0, 0}, + PIC_SOFT, +#ifdef MULTIPROCESSOR + __SIMPLELOCK_UNLOCKED, +#else + 0, +#endif + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +/* + * Fill in default interrupt table (in case of spurious interrupt + * during configuration of kernel), setup interrupt control unit + */ +void +intr_default_setup(void) +{ + int i; + + /* icu vectors */ + for (i = 0; i < NUM_LEGACY_IRQS; i++) { + idt_allocmap[ICU_OFFSET + i] = 1; + setgate(&idt[ICU_OFFSET + i], + i8259_stubs[i].ist_entry, 0, SDT_SYS386IGT, + SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + } + + /* + * Eventually might want to check if it's actually there. + */ + i8259_default_setup(); +} + +/* + * Handle a NMI, possibly a machine check. + * return true to panic system, false to ignore. + */ +int +x86_nmi(void) +{ + log(LOG_CRIT, "NMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70)); + return(0); +} + +/* + * Recalculate the interrupt masks from scratch. + */ +void +intr_calculatemasks(struct cpu_info *ci) +{ + int irq, level, unusedirqs, intrlevel[MAX_INTR_SOURCES]; + struct intrhand *q; + + /* First, figure out which levels each IRQ uses. */ + unusedirqs = 0xffffffff; + for (irq = 0; irq < MAX_INTR_SOURCES; irq++) { + int levels = 0; + + if (ci->ci_isources[irq] == NULL) { + intrlevel[irq] = 0; + continue; + } + for (q = ci->ci_isources[irq]->is_handlers; q; q = q->ih_next) + levels |= 1 << q->ih_level; + intrlevel[irq] = levels; + if (levels) + unusedirqs &= ~(1 << irq); + } + + /* Then figure out which IRQs use each level. */ + for (level = 0; level < NIPL; level++) { + int irqs = 0; + for (irq = 0; irq < MAX_INTR_SOURCES; irq++) + if (intrlevel[irq] & (1 << level)) + irqs |= 1 << irq; + ci->ci_imask[level] = irqs | unusedirqs; + } + + for (level = 0; level<(NIPL-1); level++) + ci->ci_imask[level+1] |= ci->ci_imask[level]; + + for (irq = 0; irq < MAX_INTR_SOURCES; irq++) { + int maxlevel = IPL_NONE; + int minlevel = IPL_HIGH; + + if (ci->ci_isources[irq] == NULL) + continue; + for (q = ci->ci_isources[irq]->is_handlers; q; + q = q->ih_next) { + if (q->ih_level < minlevel) + minlevel = q->ih_level; + if (q->ih_level > maxlevel) + maxlevel = q->ih_level; + } + ci->ci_isources[irq]->is_maxlevel = maxlevel; + ci->ci_isources[irq]->is_minlevel = minlevel; + } + + for (level = 0; level < NIPL; level++) + ci->ci_iunmask[level] = ~ci->ci_imask[level]; +} + + +/* + * XXX if defined(MULTIPROCESSOR) && .. ? + */ +#if NIOAPIC > 0 +int +intr_find_mpmapping(int bus, int pin, int *handle) +{ + struct mp_intr_map *mip; + + if (bus == -1 || mp_busses[bus].mb_intrs == NULL) + return ENOENT; + + for (mip = mp_busses[bus].mb_intrs; mip != NULL; mip=mip->next) { + if (mip->bus_pin == pin) { + *handle = mip->ioapic_ih; + return 0; + } + } + return ENOENT; +} +#endif + +int +intr_allocate_slot_cpu(struct cpu_info *ci, struct pic *pic, int pin, + int *index) +{ + int start, slot, i; + struct intrsource *isp; + + start = CPU_IS_PRIMARY(ci) ? NUM_LEGACY_IRQS : 0; + slot = -1; + + simple_lock(&ci->ci_slock); + for (i = start; i < MAX_INTR_SOURCES ; i++) { + isp = ci->ci_isources[i]; + if (isp != NULL && isp->is_pic == pic && isp->is_pin == pin) { + slot = i; + break; + } + if (isp == NULL && slot == -1) { + slot = i; + continue; + } + } + if (slot == -1) { + simple_unlock(&ci->ci_slock); + return EBUSY; + } + + isp = ci->ci_isources[slot]; + if (isp == NULL) { + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), + M_DEVBUF, M_NOWAIT); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) { + simple_unlock(&ci->ci_slock); + return ENOMEM; + } + snprintf(isp->is_evname, sizeof (isp->is_evname), + "pin %d", pin); +#if notyet + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL, + pic->pic_dev.dv_xname, isp->is_evname); +#endif + ci->ci_isources[slot] = isp; + } + simple_unlock(&ci->ci_slock); + + *index = slot; + return 0; +} + +/* + * A simple round-robin allocator to assign interrupts to CPUs. + */ +int +intr_allocate_slot(struct pic *pic, int legacy_irq, int pin, int level, + struct cpu_info **cip, int *index, int *idt_slot) +{ + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + struct intrsource *isp; + int slot, idtvec, error; + + /* + * If a legacy IRQ is wanted, try to use a fixed slot pointing + * at the primary CPU. In the case of IO APICs, multiple pins + * may map to one legacy IRQ, but they should not be shared + * in that case, so the first one gets the legacy slot, but + * a subsequent allocation with a different pin will get + * a different slot. + */ + if (legacy_irq != -1) { + ci = &cpu_info_primary; + slot = legacy_irq; + isp = ci->ci_isources[slot]; + if (isp == NULL) { + MALLOC(isp, struct intrsource *, + sizeof (struct intrsource), M_DEVBUF, + M_NOWAIT); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) + return ENOMEM; + snprintf(isp->is_evname, sizeof (isp->is_evname), + "pin %d", pin); + +#if notyet + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, + NULL, pic->pic_dev.dv_xname, isp->is_evname); +#endif + simple_lock(&ci->ci_slock); + ci->ci_isources[slot] = isp; + simple_unlock(&ci->ci_slock); + } else { + if (isp->is_pin != pin) { + if (pic == &i8259_pic) + return EINVAL; + goto other; + } + } + + if (pic == &i8259_pic) + idtvec = ICU_OFFSET + legacy_irq; + else { +#ifdef IOAPIC_HWMASK + if (level > isp->is_maxlevel) { +#else + if (isp->is_minlevel == 0 || level < isp->is_minlevel) { +#endif + idtvec = idt_vec_alloc(APIC_LEVEL(level), + IDT_INTR_HIGH); + if (idtvec == 0) + return EBUSY; + } else + idtvec = isp->is_idtvec; + } + } else { +other: + /* + * Otherwise, look for a free slot elsewhere. Do the primary + * CPU first. + */ + ci = &cpu_info_primary; + error = intr_allocate_slot_cpu(ci, pic, pin, &slot); + if (error == 0) + goto found; + + /* + * ..now try the others. + */ + for (CPU_INFO_FOREACH(cii, ci)) { + if (CPU_IS_PRIMARY(ci)) + continue; + error = intr_allocate_slot_cpu(ci, pic, pin, &slot); + if (error == 0) + goto found; + } + return EBUSY; +found: + idtvec = idt_vec_alloc(APIC_LEVEL(level), IDT_INTR_HIGH); + if (idtvec == 0) { + simple_lock(&ci->ci_slock); + FREE(ci->ci_isources[slot], M_DEVBUF); + ci->ci_isources[slot] = NULL; + simple_unlock(&ci->ci_slock); + return EBUSY; + } + } + *idt_slot = idtvec; + *index = slot; + *cip = ci; + return 0; +} + +void * +intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level, + int (*handler)(void *), void *arg) +{ + struct intrhand **p, *q, *ih; + struct cpu_info *ci; + int slot, error, idt_vec; + struct intrsource *source; + struct intrstub *stubp; + +#ifdef DIAGNOSTIC + if (legacy_irq != -1 && (legacy_irq < 0 || legacy_irq > 15)) + panic("intr_establish: bad legacy IRQ value"); + + if (legacy_irq == -1 && pic == &i8259_pic) + panic("intr_establish: non-legacy IRQ on i8259"); +#endif + + error = intr_allocate_slot(pic, legacy_irq, pin, level, &ci, &slot, + &idt_vec); + if (error != 0) { + printf("failed to allocate interrupt slot for PIC %s pin %d\n", + pic->pic_dev.dv_xname, pin); + return NULL; + } + + /* no point in sleeping unless someone can free memory. */ + ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) { + printf("intr_establish: can't allocate handler info\n"); + return NULL; + } + + source = ci->ci_isources[slot]; + + if (source->is_handlers != NULL && + source->is_pic->pic_type != pic->pic_type) { + free(ih, M_DEVBUF); + printf("intr_establish: can't share intr source between " + "different PIC types (legacy_irq %d pin %d slot %d)\n", + legacy_irq, pin, slot); + return NULL; + } + + simple_lock(&ci->ci_slock); + + source->is_pin = pin; + source->is_pic = pic; + + switch (source->is_type) { + case IST_NONE: + source->is_type = type; + break; + case IST_EDGE: + case IST_LEVEL: + if (source->is_type == type) + break; + case IST_PULSE: + if (type != IST_NONE) { + simple_unlock(&ci->ci_slock); + printf("intr_establish: pic %s pin %d: can't share " + "type %d with %d\n", pic->pic_name, pin, + source->is_type, type); + free(ih, M_DEVBUF); + return NULL; + } + break; + default: + simple_unlock(&ci->ci_slock); + panic("intr_establish: bad intr type %d for pic %s pin %d\n", + source->is_type, pic->pic_dev.dv_xname, pin); + } + + if (!cold) + pic->pic_hwmask(pic, pin); + + /* + * Figure out where to put the handler. + * This is O(N^2), but we want to preserve the order, and N is + * generally small. + */ + for (p = &ci->ci_isources[slot]->is_handlers; + (q = *p) != NULL && q->ih_level > level; + p = &q->ih_next) + ; + + ih->ih_fun = handler; + ih->ih_arg = arg; + ih->ih_next = *p; + ih->ih_level = level; + ih->ih_pin = pin; + ih->ih_cpu = ci; + ih->ih_slot = slot; + *p = ih; + + intr_calculatemasks(ci); + + simple_unlock(&ci->ci_slock); + + if (ci->ci_isources[slot]->is_resume == NULL || + source->is_idtvec != idt_vec) { + if (source->is_idtvec != 0 && source->is_idtvec != idt_vec) + idt_vec_free(source->is_idtvec); + source->is_idtvec = idt_vec; + stubp = type == IST_LEVEL ? + &pic->pic_level_stubs[slot] : &pic->pic_edge_stubs[slot]; + ci->ci_isources[slot]->is_resume = stubp->ist_resume; + ci->ci_isources[slot]->is_recurse = stubp->ist_recurse; + setgate(&idt[idt_vec], stubp->ist_entry, 0, SDT_SYS386IGT, + SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + } + + pic->pic_addroute(pic, ci, pin, idt_vec, type); + + if (!cold) + pic->pic_hwunmask(pic, pin); + +#ifdef INTRDEBUG + printf("allocated pic %s type %s pin %d level %d to cpu%u slot %d idt entry %d\n", + pic->pic_name, type == IST_EDGE ? "edge" : "level", pin, level, + ci->ci_apicid, slot, idt_vec); +#endif + + return (ih); +} + +/* + * Deregister an interrupt handler. + */ +void +intr_disestablish(struct intrhand *ih) +{ + struct intrhand **p, *q; + struct cpu_info *ci; + struct pic *pic; + struct intrsource *source; + int idtvec; + + ci = ih->ih_cpu; + pic = ci->ci_isources[ih->ih_slot]->is_pic; + source = ci->ci_isources[ih->ih_slot]; + idtvec = source->is_idtvec; + + simple_lock(&ci->ci_slock); + pic->pic_hwmask(pic, ih->ih_pin); + x86_atomic_clearbits_l(&ci->ci_ipending, (1 << ih->ih_slot)); + + /* + * Remove the handler from the chain. + */ + for (p = &source->is_handlers; (q = *p) != NULL && q != ih; + p = &q->ih_next) + ; + if (q == NULL) { + simple_unlock(&ci->ci_slock); + panic("intr_disestablish: handler not registered"); + } + + *p = q->ih_next; + + intr_calculatemasks(ci); + pic->pic_delroute(pic, ci, ih->ih_pin, idtvec, source->is_type); + pic->pic_hwunmask(pic, ih->ih_pin); + +#ifdef INTRDEBUG + printf("cpu%u: remove slot %d (pic %s pin %d vec %d)\n", + ci->ci_apicid, ih->ih_slot, pic->pic_dev.dv_xname, ih->ih_pin, + idtvec); +#endif + + if (source->is_handlers == NULL) { +#if notyet + evcnt_detach(&source->is_evcnt); +#endif + FREE(source, M_DEVBUF); + ci->ci_isources[ih->ih_slot] = NULL; + if (pic != &i8259_pic) + idt_vec_free(idtvec); + } + + free(ih, M_DEVBUF); + + simple_unlock(&ci->ci_slock); +} + +#define CONCAT(x,y) __CONCAT(x,y) + +/* + * Fake interrupt handler structures for the benefit of symmetry with + * other interrupt sources, and the benefit of intr_calculatemasks() + */ +struct intrhand fake_softclock_intrhand; +struct intrhand fake_softnet_intrhand; +struct intrhand fake_softserial_intrhand; +struct intrhand fake_timer_intrhand; +struct intrhand fake_ipi_intrhand; + +#if NLAPIC > 0 && defined(MULTIPROCESSOR) +static char *x86_ipi_names[X86_NIPI] = X86_IPI_NAMES; +#endif + +/* + * Initialize all handlers that aren't dynamically allocated, and exist + * for each CPU. + */ +void +cpu_intr_init(struct cpu_info *ci) +{ + struct intrsource *isp; +#if NLAPIC > 0 && defined(MULTIPROCESSOR) + int i; +#endif + + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF, + M_WAITOK); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) + panic("can't allocate fixed interrupt source"); + isp->is_recurse = Xsoftclock; + isp->is_resume = Xsoftclock; + fake_softclock_intrhand.ih_level = IPL_SOFTCLOCK; + isp->is_handlers = &fake_softclock_intrhand; + isp->is_pic = &softintr_pic; + ci->ci_isources[SIR_CLOCK] = isp; +#if notyet + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL, + ci->ci_dev->dv_xname, "softclock"); +#endif + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF, + M_WAITOK); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) + panic("can't allocate fixed interrupt source"); + isp->is_recurse = Xsoftnet; + isp->is_resume = Xsoftnet; + fake_softnet_intrhand.ih_level = IPL_SOFTNET; + isp->is_handlers = &fake_softnet_intrhand; + isp->is_pic = &softintr_pic; + ci->ci_isources[SIR_NET] = isp; +#if notyet + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL, + ci->ci_dev->dv_xname, "softnet"); +#endif + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF, + M_WAITOK); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) + panic("can't allocate fixed interrupt source"); + isp->is_recurse = Xsoftserial; + isp->is_resume = Xsoftserial; + fake_softserial_intrhand.ih_level = IPL_SOFTSERIAL; + isp->is_handlers = &fake_softserial_intrhand; + isp->is_pic = &softintr_pic; + ci->ci_isources[SIR_SERIAL] = isp; +#if notyet + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL, + ci->ci_dev->dv_xname, "softserial"); +#endif +#if NLAPIC > 0 + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF, + M_WAITOK); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) + panic("can't allocate fixed interrupt source"); + isp->is_recurse = Xrecurse_lapic_ltimer; + isp->is_resume = Xresume_lapic_ltimer; + fake_timer_intrhand.ih_level = IPL_CLOCK; + isp->is_handlers = &fake_timer_intrhand; + isp->is_pic = &local_pic; + ci->ci_isources[LIR_TIMER] = isp; +#if notyet + evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL, + ci->ci_dev->dv_xname, "timer"); +#endif +#ifdef MULTIPROCESSOR + MALLOC(isp, struct intrsource *, sizeof (struct intrsource), M_DEVBUF, + M_WAITOK); + memset(isp, 0, sizeof(struct intrsource)); + if (isp == NULL) + panic("can't allocate fixed interrupt source"); + isp->is_recurse = Xrecurse_lapic_ipi; + isp->is_resume = Xresume_lapic_ipi; + fake_ipi_intrhand.ih_level = IPL_IPI; + isp->is_handlers = &fake_ipi_intrhand; + isp->is_pic = &local_pic; + ci->ci_isources[LIR_IPI] = isp; + + for (i = 0; i < X86_NIPI; i++) + evcnt_attach_dynamic(&ci->ci_ipi_events[i], EVCNT_TYPE_INTR, + NULL, ci->ci_dev->dv_xname, x86_ipi_names[i]); +#endif +#endif + + intr_calculatemasks(ci); + +} + +#ifdef MULTIPROCESSOR +void +x86_intlock(struct intrframe iframe) +{ + if (iframe.if_ppl < IPL_SCHED) + spinlockmgr(&kernel_lock, LK_EXCLUSIVE|LK_CANRECURSE, 0); +} + +void +x86_intunlock(struct intrframe iframe) +{ + if (iframe.if_ppl < IPL_SCHED) + spinlockmgr(&kernel_lock, LK_RELEASE, 0); +} + +void +x86_softintlock(void) +{ + spinlockmgr(&kernel_lock, LK_EXCLUSIVE|LK_CANRECURSE, 0); +} + +void +x86_softintunlock(void) +{ + spinlockmgr(&kernel_lock, LK_RELEASE, 0); +} +#endif + +void +intr_printconfig(void) +{ +#ifdef INTRDEBUG + int i; + struct intrhand *ih; + struct intrsource *isp; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + for (CPU_INFO_FOREACH(cii, ci)) { + printf("cpu%d: interrupt masks:\n", ci->ci_apicid); + for (i = 0; i < NIPL; i++) + printf("IPL %d mask %lx unmask %lx\n", i, + (u_long)ci->ci_imask[i], (u_long)ci->ci_iunmask[i]); + simple_lock(&ci->ci_slock); + for (i = 0; i < MAX_INTR_SOURCES; i++) { + isp = ci->ci_isources[i]; + if (isp == NULL) + continue; + printf("cpu%u source %d is pin %d from pic %s maxlevel %d\n", + ci->ci_apicid, i, isp->is_pin, + isp->is_pic->pic_name, isp->is_maxlevel); + for (ih = isp->is_handlers; ih != NULL; + ih = ih->ih_next) + printf("\thandler %p level %d\n", + ih->ih_fun, ih->ih_level); + + } + simple_unlock(&ci->ci_slock); + } +#endif +} diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S new file mode 100644 index 00000000000..2ec08feec31 --- /dev/null +++ b/sys/arch/amd64/amd64/locore.S @@ -0,0 +1,1243 @@ +/* $OpenBSD: locore.S,v 1.1 2004/01/28 01:39:38 mickey Exp $ */ +/* $NetBSD: locore.S,v 1.2 2003/04/26 19:34:45 fvdl Exp $ */ + +/* + * Copyright-o-rama! + */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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) 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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) 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. + * + * @(#)locore.s 7.3 (Berkeley) 5/13/91 + */ + +#include "assym.h" +#include "lapic.h" +#include "ioapic.h" +#include "ksyms.h" + +#include <sys/errno.h> +#include <sys/syscall.h> + +#include <machine/param.h> +#include <machine/pte.h> +#include <machine/pmap.h> +#include <machine/segments.h> +#include <machine/specialreg.h> +#include <machine/trap.h> +#include <machine/bootinfo.h> +#include <machine/frameasm.h> + +#if NLAPIC > 0 +#include <machine/i82489reg.h> +#endif + +/* + * override user-land alignment before including asm.h + */ +#define ALIGN_DATA .align 8 +#define ALIGN_TEXT .align 16,0x90 +#define _ALIGN_TEXT ALIGN_TEXT + +#include <machine/asm.h> + +#if defined(MULTIPROCESSOR) + +#define SET_CURPROC(proc,cpu) \ + movq CPUVAR(SELF),cpu ; \ + movq proc,CPUVAR(CURPROC) ; \ + movq cpu,P_CPU(proc) + +#else + +#define SET_CURPROC(proc,tcpu) movq proc,CPUVAR(CURPROC) +#define GET_CURPROC(reg) movq CPUVAR(CURPROC),reg + +#endif + +#define GET_CURPCB(reg) movq CPUVAR(CURPCB),reg +#define SET_CURPCB(reg) movq reg,CPUVAR(CURPCB) + + +/* XXX temporary kluge; these should not be here */ +/* Get definitions for IOM_BEGIN, IOM_END, and IOM_SIZE */ +#include <dev/isa/isareg.h> + + +/* + * Initialization + */ + .data + +#if NLAPIC > 0 + .align NBPG + .globl _C_LABEL(local_apic), _C_LABEL(lapic_id), _C_LABEL(lapic_tpr) +_C_LABEL(local_apic): + .space LAPIC_ID +_C_LABEL(lapic_id): + .long 0x00000000 + .space LAPIC_TPRI-(LAPIC_ID+4) +_C_LABEL(lapic_tpr): + .space LAPIC_PPRI-LAPIC_TPRI +_C_LABEL(lapic_ppr): + .space LAPIC_ISR-LAPIC_PPRI +_C_LABEL(lapic_isr): + .space NBPG-LAPIC_ISR +#endif + + .globl _C_LABEL(cpu_id),_C_LABEL(cpu_vendor), _C_LABEL(cpu_brand_id) + .globl _C_LABEL(cpuid_level),_C_LABEL(cpu_feature) + .globl _C_LABEL(esym),_C_LABEL(boothowto) + .globl _C_LABEL(bootinfo),_C_LABEL(atdevbase) + .globl _C_LABEL(proc0paddr),_C_LABEL(PTDpaddr) + .globl _C_LABEL(biosbasemem),_C_LABEL(biosextmem) + .globl _C_LABEL(gdtstore) +_C_LABEL(cpu): .long 0 # are we 386, 386sx, or 486, + # or Pentium, or.. +_C_LABEL(cpu_id): .long 0 # saved from `cpuid' instruction +_C_LABEL(cpu_feature): .long 0 # feature flags from 'cpuid' + # instruction +_C_LABEL(cpuid_level): .long -1 # max. level accepted by 'cpuid' + # instruction +_C_LABEL(cpu_vendor): .space 16 # vendor string returned by `cpuid' + # instruction +_C_LABEL(cpu_brand_id): .long 0 # brand ID from 'cpuid' instruction +_C_LABEL(esym): .quad 0 # ptr to end of syms +_C_LABEL(atdevbase): .quad 0 # location of start of iomem in virtual +_C_LABEL(proc0paddr): .quad 0 +_C_LABEL(PTDpaddr): .quad 0 # paddr of PTD, for libkvm +#ifndef REALBASEMEM +_C_LABEL(biosbasemem): .long 0 # base memory reported by BIOS +#else +_C_LABEL(biosbasemem): .long REALBASEMEM +#endif +#ifndef REALEXTMEM +_C_LABEL(biosextmem): .long 0 # extended memory reported by BIOS +#else +_C_LABEL(biosextmem): .long REALEXTMEM +#endif + +#define _RELOC(x) ((x) - KERNBASE) +#define RELOC(x) _RELOC(_C_LABEL(x)) + + .globl gdt64 + +gdt64: + .word gdt64_end-gdt64_start + .quad _RELOC(gdt64_start) +.align 64 + +gdt64_start: + .quad 0x0000000000000000 /* always empty */ + .quad 0x00af9a000000ffff /* kernel CS */ + .quad 0x00cf92000000ffff /* kernel DS */ +gdt64_end: + +farjmp64: + .long longmode-KERNBASE + .word GSEL(GCODE_SEL, SEL_KPL) + + .space 512 +tmpstk: + + .globl _C_LABEL(cpu_private) + .comm _C_LABEL(cpu_private),NBPG,NBPG + +/* + * Some hackage to deal with 64bit symbols in 32 bit mode. + * This may not be needed it things are cleaned up a little. + */ + + + .text + .globl _C_LABEL(kernel_text) + .set _C_LABEL(kernel_text),KERNTEXTOFF + +.code32 + + .globl start +start: movw $0x1234,0x472 # warm boot + + /* + * Load parameters from stack + * (howto, [bootdev], bootinfo, esym, basemem, extmem). + */ + movl 4(%esp),%eax + movl %eax,RELOC(boothowto) + movl 12(%esp),%eax + testl %eax, %eax + jz 1f + movl (%eax), %ebx /* number of entries */ + movl $RELOC(bootinfo),%ebp + movl %ebp, %edx + addl $BOOTINFO_MAXSIZE,%ebp + movl %ebx, (%edx) + addl $4, %edx +2: + testl %ebx, %ebx + jz 1f + addl $4, %eax + movl (%eax), %ecx /* address of entry */ + pushl %edi + pushl %esi + pushl %eax + + movl (%ecx),%eax /* len */ + movl %edx,%edi + addl (%ecx), %edx /* update dest pointer */ + cmpl %ebp, %edx + jg 2f + movl %ecx,%esi + movl %eax,%ecx + rep + movsb + popl %eax + popl %esi + popl %edi + subl $1, %ebx + jmp 2b +2: /* cleanup for overflow case */ + popl %eax + popl %esi + popl %edi + movl $RELOC(bootinfo),%ebp + movl %ebp, %edx + subl %ebx, (%edx) /* correct number of entries */ +1: + + movl 16(%esp),%eax + testl %eax,%eax + jz 1f + addl $KERNBASE_LO,%eax +1: movl $RELOC(esym),%ebp + movl %eax,(%ebp) + movl $KERNBASE_HI,4(%ebp) + + movl $RELOC(biosextmem),%ebp + movl (%ebp),%eax + testl %eax,%eax + jnz 1f + movl 20(%esp),%eax + movl %eax,(%ebp) +1: + movl $RELOC(biosbasemem),%ebp + movl (%ebp),%eax + testl %eax,%eax + jnz 1f + movl 24(%esp),%eax + movl %eax,(%ebp) +1: + + /* First, reset the PSL. */ + pushl $PSL_MBO + popfl + + xorl %eax,%eax + cpuid + movl %eax,RELOC(cpuid_level) + movl $RELOC(cpu_vendor),%ebp + movl %ebx,(%ebp) + movl %edx,4(%ebp) + movl %ecx,8(%ebp) + movl $0, 12(%ebp) + + movl $1,%eax + cpuid + movl %eax,RELOC(cpu_id) + movl %edx,RELOC(cpu_feature) + + /* Brand ID is bits 0-7 of %ebx */ + andl $255,%ebx + movl %ebx,RELOC(cpu_brand_id) + + /* + * Finished with old stack; load new %esp now instead of later so we + * can trace this code without having to worry about the trace trap + * clobbering the memory test or the zeroing of the bss+bootstrap page + * tables. + * + * The boot program should check: + * text+data <= &stack_variable - more_space_for_stack + * text+data+bss+pad+space_for_page_tables <= end_of_memory + * Oops, the gdt is in the carcass of the boot program so clearing + * the rest of memory is still not possible. + */ + movl $RELOC(tmpstk),%esp + +/* + * Virtual address space of kernel: + * + * text | data | bss | [syms] | page dir | proc0 kstack | L1 ptp | L2 ptp | L3 + * 0 1 2 3 + */ + +#if L2_SLOT_KERNBASE > 0 +#define TABLE_L2_ENTRIES (2 * (NKL2_KIMG_ENTRIES + 1)) +#else +#define TABLE_L2_ENTRIES (NKL2_KIMG_ENTRIES + 1) +#endif + +#if L3_SLOT_KERNBASE > 0 +#define TABLE_L3_ENTRIES (2 * NKL3_KIMG_ENTRIES) +#else +#define TABLE_L3_ENTRIES NKL3_KIMG_ENTRIES +#endif + + +#define PROC0_PML4_OFF 0 +#define PROC0_STK_OFF (PROC0_PML4_OFF + NBPG) +#define PROC0_PTP3_OFF (PROC0_STK_OFF + UPAGES * NBPG) +#define PROC0_PTP2_OFF (PROC0_PTP3_OFF + NKL4_KIMG_ENTRIES * NBPG) +#define PROC0_PTP1_OFF (PROC0_PTP2_OFF + TABLE_L3_ENTRIES * NBPG) +#define TABLESIZE \ + ((NKL4_KIMG_ENTRIES + TABLE_L3_ENTRIES + TABLE_L2_ENTRIES + 1 + UPAGES) \ + * NBPG) + +#define fillkpt \ +1: movl %eax,(%ebx) ; /* store phys addr */ \ + movl $0,4(%ebx) ; /* upper 32 bits 0 */ \ + addl $8,%ebx ; /* next pte/pde */ \ + addl $NBPG,%eax ; /* next phys page */ \ + loop 1b ; \ + + + /* Find end of kernel image. */ + movl $RELOC(end),%edi +#if (NKSYMS || defined(DDB) || defined(LKM)) && !defined(SYMTAB_SPACE) + /* Save the symbols (if loaded). */ + movl RELOC(esym),%eax + testl %eax,%eax + jz 1f + subl $KERNBASE_LO,%eax /* XXX */ + movl %eax,%edi +1: +#endif + /* Clear tables */ + movl %edi,%esi + addl $PGOFSET,%esi + andl $~PGOFSET,%esi + + movl %esi,%edi + xorl %eax,%eax + cld + movl $TABLESIZE,%ecx + shrl $2,%ecx + rep + stosl + + leal (PROC0_PTP1_OFF)(%esi), %ebx + + /* + * Compute etext - KERNBASE. This can't be > 4G, or we can't deal + * with it anyway, since we can't load it in 32 bit mode. So use + * the bottom 32 bits. + */ + movl $RELOC(etext),%edx + addl $PGOFSET,%edx + andl $~PGOFSET,%edx + + /* + * Skip the first MB. + */ + movl $(KERNTEXTOFF_LO - KERNBASE_LO),%eax + movl %eax,%ecx + shrl $(PGSHIFT-3),%ecx /* ((n >> PGSHIFT) << 3) for # pdes */ + addl %ecx,%ebx + + /* Map kernel text read-only */ + movl %edx,%ecx + subl %eax,%ecx + shrl $PGSHIFT,%ecx + orl $(PG_V|PG_KR),%eax + fillkpt + + /* Map the data, BSS, and bootstrap tables read-write. */ + leal (PG_V|PG_KW)(%edx),%eax + movl $TABLESIZE,%ecx + addl %esi,%ecx /* %ecx = &end[TABLESIZE] */ + subl %edx,%ecx /* %ecx = %ecx - etext */ + shrl $PGSHIFT,%ecx + fillkpt + + /* Map ISA I/O mem (later atdevbase) */ + movl $(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax + movl $(IOM_SIZE>>PGSHIFT),%ecx + fillkpt + + /* Set up level 2 pages */ + leal (PROC0_PTP2_OFF)(%esi),%ebx + leal (PROC0_PTP1_OFF)(%esi),%eax + orl $(PG_V|PG_KW), %eax + movl $(NKL2_KIMG_ENTRIES+1),%ecx + fillkpt + +#if L2_SLOT_KERNBASE > 0 + /* If needed, set up level 2 entries for actual kernel mapping */ + leal (PROC0_PTP2_OFF+ L2_SLOT_KERNBASE*8)(%esi),%ebx + leal (PROC0_PTP1_OFF)(%esi),%eax + orl $(PG_V|PG_KW), %eax + movl $(NKL2_KIMG_ENTRIES+1),%ecx + fillkpt +#endif + + /* Set up level 3 pages */ + leal (PROC0_PTP3_OFF)(%esi),%ebx + leal (PROC0_PTP2_OFF)(%esi),%eax + orl $(PG_V|PG_KW), %eax + movl $NKL3_KIMG_ENTRIES,%ecx + fillkpt + +#if L3_SLOT_KERNBASE > 0 + /* If needed, set up level 3 entries for actual kernel mapping */ + leal (PROC0_PTP3_OFF+ L3_SLOT_KERNBASE*8)(%esi),%ebx + leal (PROC0_PTP2_OFF)(%esi),%eax + orl $(PG_V|PG_KW), %eax + movl $NKL3_KIMG_ENTRIES,%ecx + fillkpt +#endif + + /* Set up top level entries for identity mapping */ + leal (PROC0_PML4_OFF)(%esi),%ebx + leal (PROC0_PTP3_OFF)(%esi),%eax + orl $(PG_V|PG_KW), %eax + movl $NKL4_KIMG_ENTRIES,%ecx + fillkpt + + /* Set up top level entries for actual kernel mapping */ + leal (PROC0_PML4_OFF + L4_SLOT_KERNBASE*8)(%esi),%ebx + leal (PROC0_PTP3_OFF)(%esi),%eax + orl $(PG_V|PG_KW), %eax + movl $NKL4_KIMG_ENTRIES,%ecx + fillkpt + + /* Install recursive top level PDE */ + leal (PROC0_PML4_OFF + PDIR_SLOT_PTE*8)(%esi),%ebx + leal (PROC0_PML4_OFF)(%esi),%eax + orl $(PG_V|PG_KW),%eax + movl %eax,(%ebx) + movl $0, 4(%ebx) + + + /* Save phys. addr of PTD, for libkvm. */ + movl $RELOC(PTDpaddr),%ebp + movl %esi,(%ebp) + movl $0,4(%ebp) + + /* + * Startup checklist: + * 1. Enable PAE (and SSE while here). + */ + movl %cr4,%eax + orl $(CR4_PAE|CR4_OSFXSR|CR4_OSXMMEXCPT),%eax + movl %eax,%cr4 + + /* + * 2. Set Long Mode Enable in EFER. Also enable the + * syscall extensions. + */ + movl $MSR_EFER,%ecx + rdmsr + xorl %eax,%eax /* XXX */ + orl $(EFER_LME|EFER_SCE),%eax + wrmsr + + /* + * 3. Load %cr3 with pointer to PML4. + */ + movl %esi,%eax + movl %eax,%cr3 + + /* + * 4. Enable paging and the rest of it. + */ + movl %cr0,%eax + orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP),%eax + movl %eax,%cr0 + jmp compat +compat: + + /* + * 5. + * Not quite done yet, we're now in a compatibility segment, + * in legacy mode. We must jump to a long mode segment. + * Need to set up a temporary GDT with a long mode segment + * in it to do that. + */ + + movl $RELOC(gdt64),%eax + lgdt (%eax) + movl $RELOC(farjmp64),%eax + ljmp *(%eax) + +.code64 +longmode: + /* + * 6. + * Finally, we're in long mode. However, we're still + * in the identity mapped area (could not jump out + * of that earlier because it would have been a > 32bit + * jump). We can do that now, so here we go. + */ + movabsq $longmode_hi,%rax + jmp *%rax +longmode_hi: + /* + * We have arrived. + * There's no need anymore for the identity mapping in low + * memory, remove it. + */ + movq $KERNBASE,%r8 + +#if L2_SLOT_KERNBASE > 0 + movq $(NKL2_KIMG_ENTRIES+1),%rcx + leaq (PROC0_PTP2_OFF)(%rsi),%rbx + addq %r8, %rbx +1: movq $0,(%rbx) + addq $8,%rbx + loop 1b +#endif + +#if L3_SLOT_KERNBASE > 0 + movq $NKL3_KIMG_ENTRIES,%rcx + leaq (PROC0_PTP3_OFF)(%rsi),%rbx + addq %r8, %rbx +1: movq $0,(%rbx) + addq $8,%rbx + loop 1b +#endif + + movq $NKL4_KIMG_ENTRIES,%rcx + leaq (PROC0_PML4_OFF)(%rsi),%rbx # old, phys address of PML4 + addq %r8, %rbx # new, virtual adress of PML4 +1: movq $0,(%rbx) + addq $8,%rbx + loop 1b + + /* Relocate atdevbase. */ + movq $(TABLESIZE+KERNBASE),%rdx + addq %rsi,%rdx + movq %rdx,_C_LABEL(atdevbase)(%rip) + + /* Set up bootstrap stack. */ + leaq (PROC0_STK_OFF)(%rsi),%rax + addq %r8,%rax + movq %rax,_C_LABEL(proc0paddr)(%rip) + leaq (USPACE-FRAMESIZE)(%rax),%rsp + movq %rsi,PCB_CR3(%rax) # pcb->pcb_cr3 + xorq %rbp,%rbp # mark end of frames + + xorw %ax,%ax + movw %ax,%gs + movw %ax,%fs + + /* XXX merge these */ + leaq TABLESIZE(%rsi),%rdi + call _C_LABEL(init_x86_64) + + call _C_LABEL(main) + +/*****************************************************************************/ + +/* + * Signal trampoline; copied to top of user stack. + */ +NENTRY(sigcode) + call *%rax + + movq %rsp,%rdi + pushq %rdi /* fake return address */ + movq $SYS_sigreturn,%rax + syscall + movq $SYS_exit,%rax + syscall + .globl _C_LABEL(esigcode) +_C_LABEL(esigcode): + +/* + * void lgdt(struct region_descriptor *rdp); + * Change the global descriptor table. + */ +NENTRY(lgdt) + /* Reload the descriptor table. */ + movq %rdi,%rax + lgdt (%rax) + /* Flush the prefetch q. */ + jmp 1f + nop +1: /* Reload "stale" selectors. */ + movl $GSEL(GDATA_SEL, SEL_KPL),%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%ss + /* Reload code selector by doing intersegment return. */ + popq %rax + pushq $GSEL(GCODE_SEL, SEL_KPL) + pushq %rax + lretq + +ENTRY(setjmp) + /* + * Only save registers that must be preserved across function + * calls according to the ABI (%rbx, %rsp, %rbp, %r12-%r15) + * and %rip. + */ + movq %rdi,%rax + movq %rbx,(%rax) + movq %rsp,8(%rax) + movq %rbp,16(%rax) + movq %r12,24(%rax) + movq %r13,32(%rax) + movq %r14,40(%rax) + movq %r15,48(%rax) + movq (%rsp),%rdx + movq %rdx,56(%rax) + xorl %eax,%eax + ret + +ENTRY(longjmp) + movq %rdi,%rax + movq (%rax),%rbx + movq 8(%rax),%rsp + movq 16(%rax),%rbp + movq 24(%rax),%r12 + movq 32(%rax),%r13 + movq 40(%rax),%r14 + movq 48(%rax),%r15 + movq 56(%rax),%rdx + movq %rdx,(%rsp) + xorl %eax,%eax + incl %eax + ret + +/*****************************************************************************/ + +/* + * The following primitives manipulate the run queues. + * _whichqs tells which of the 32 queues _qs + * have processes in them. Setrq puts processes into queues, Remrq + * removes them from queues. The running process is on no queue, + * other processes are on a queue related to p->p_pri, divided by 4 + * actually to shrink the 0-127 range of priorities into the 32 available + * queues. + */ + .globl _C_LABEL(whichqs),_C_LABEL(qs) + .globl _C_LABEL(uvmexp),_C_LABEL(panic) + +#if NAPM > 0 + .globl _C_LABEL(apm_cpu_idle),_C_LABEL(apm_cpu_busy) +#endif + +#ifdef DIAGNOSTIC +NENTRY(switch_error1) + movabsq $1f,%rdi + call _C_LABEL(panic) + /* NOTREACHED */ +1: .asciz "cpu_switch 1" +NENTRY(switch_error2) + movabsq $1f,%rdi + call _C_LABEL(panic) + /* NOTREACHED */ +1: .asciz "cpu_switch 2" +NENTRY(switch_error3) + movabsq $1f,%rdi + call _C_LABEL(panic) + /* NOTREACHED */ +1: .asciz "cpu_switch 3" +#endif /* DIAGNOSTIC */ + +/* + * When no processes are on the runq, cpu_switch() branches to here to wait for + * something to come ready. + */ +ENTRY(idle) +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) + call _C_LABEL(sched_unlock_idle) +#endif + jmp idle_start +idle_zero: + sti + call _C_LABEL(uvm_pageidlezero) + jmp idle_start +idle_loop: + /* Try to zero some pages. */ + movl _C_LABEL(uvm)+UVM_PAGE_IDLE_ZERO(%rip),%ecx + testl %ecx,%ecx + jnz idle_zero + sti + hlt +NENTRY(mpidle) +idle_start: + cli + movl _C_LABEL(whichqs)(%rip),%ecx + testl %ecx, %ecx + jz idle_loop +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) + call _C_LABEL(sched_lock_idle) +#endif + jmp sw1 + +/* + * void cpu_switch(struct proc *) + * Find a runnable process and switch to it. Wait if necessary. If the new + * proc is the same as the old one, we short-circuit the context save and + * restore. + */ +ENTRY(cpu_switch) + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + movl CPUVAR(ILEVEL), %ebx + pushq %rbx + + movq %rdi,%r13 + + /* + * Clear curproc so that we don't accumulate system time while idle. + * This also insures that schedcpu() will move the old proc to + * the correct queue if it happens to get called from the spllower() + * below and changes the priority. (See corresponding comment in + * userret()). + */ + movq $0, CPUVAR(CURPROC) + + movl $IPL_NONE, %edi + call _C_LABEL(Xspllower) + + /* + * First phase: find new proc. + * + * Registers: + * %rax - queue head, scratch, then zero + * %r8 - queue number + * %ecx - cached value of whichqs + * %rdx - next process in queue + * %r13 - old proc + * %r12 - new proc + */ + +switch_search: + /* Look for new proc. */ + cli # splhigh doesn't do a cli + movl _C_LABEL(whichqs)(%rip),%ecx + +sw1: bsfl %ecx,%r8d # find a full q + jz _C_LABEL(idle) + +switch_dequeue: + movq %r8,%r9 + + shlq $4, %r9 + leaq _C_LABEL(qs)(%rip),%rax + addq %r9,%rax + /* movq (%rax),%rax */ + + movq P_FORW(%rax),%r12 # unlink from front of process q +#ifdef DIAGNOSTIC + cmpq %r12,%rax # linked to self (i.e. nothing queued)? + je _C_LABEL(switch_error1) # not possible +#endif /* DIAGNOSTIC */ + movq P_FORW(%r12),%rdx + movq %rdx,P_FORW(%rax) + movq %rax,P_BACK(%rdx) + + cmpq %rdx,%rax # q empty? + jne 3f + + btrl %r8d,%ecx # yes, clear to indicate empty + movl %ecx,_C_LABEL(whichqs)(%rip) # update q status + +3: /* We just did it. */ + xorq %rax,%rax + movl %eax,CPUVAR(RESCHED) +switch_resume: +#ifdef DIAGNOSTIC + cmpq %rax,P_WCHAN(%r12) + jne _C_LABEL(switch_error2) + cmpb $SRUN,P_STAT(%r12) + jne _C_LABEL(switch_error3) +#endif + + /* Isolate proc. XXX Is this necessary? */ + movq %rax,P_BACK(%r12) + + /* Record new proc. */ +#ifdef MULTIPROCESSOR + movb $SONPROC,P_STAT(%r12) # l->l_stat = SONPROC +#endif + SET_CURPROC(%r12,%rcx) + + sti + + /* Skip context switch if same proc. */ + movl $1,%eax + cmpq %r12,%r13 + je switch_return + + /* If old proc exited, don't bother. */ + testq %r13,%r13 + jz switch_exited + + /* + * Second phase: save old context. + * + * Registers: + * %rax, %rcx - scratch + * %r13 - old proc, then old pcb + * %r12 - new proc + */ + + movq P_ADDR(%r13),%r13 + + /* Save stack pointers. */ + movq %rsp,PCB_RSP(%r13) + movq %rbp,PCB_RBP(%r13) + +switch_exited: + /* + * Third phase: restore saved context. + * + * Registers: + * %rax, %rcx, %rdx - scratch + * %r13 - new pcb + * %r12 - new process + */ + + /* No interrupts while loading new state. */ + cli + movq P_ADDR(%r12),%r13 + + /* Restore stack pointers. */ + movq PCB_RSP(%r13),%rsp + movq PCB_RBP(%r13),%rbp + +#if 0 + /* Don't bother with the rest if switching to a system process. */ + testl $P_SYSTEM,P_FLAG(%r12) + jnz switch_restored +#endif + + /* Load TSS info. */ +#ifdef MULTIPROCESSOR + movq CPUVAR(GDT),%rax +#else + movq _C_LABEL(gdtstore)(%rip),%rax +#endif + movl P_MD_TSS_SEL(%r12),%edx + + /* Switch address space. */ + movq PCB_CR3(%r13),%rcx + movq %rcx,%cr3 + + /* Switch TSS. Reset "task busy" flag before */ + andl $~0x0200,4(%rax,%rdx, 1) + ltr %dx + + movq PCB_LDT_SEL(%r13),%rcx + lldt %cx +#if 0 +switch_restored: +#endif + /* Restore cr0 (including FPU state). */ + movl PCB_CR0(%r13),%ecx +#ifdef MULTIPROCESSOR + movq PCB_FPCPU(%r13),%r8 + cmpq CPUVAR(SELF),%r8 + jz 1f + orl $CR0_TS,%ecx +1: +#endif + movq %rcx,%cr0 + + SET_CURPCB(%r13) + + /* Interrupts are okay again. */ + sti + +switch_return: +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) + call _C_LABEL(sched_unlock_idle) +#endif + /* + * Restore old cpl from stack. Note that this is always an increase, + * due to the spl0() on entry. + */ + popq %rbx + movl %ebx, CPUVAR(ILEVEL) + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + ret + +ENTRY(cpu_switchto) + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + movq %rdi,%r13 + movq %rsi,%r12 + + movq $0,CPUVAR(CURPROC) + + xorq %rax,%rax + jmp switch_resume + + +/* + * void switch_exit(struct proc *l, void (*exit)(struct proc *)); + * Switch to proc0's saved context and deallocate the address space and kernel + * stack for p. Then jump into cpu_switch(), as if we were in proc0 all along. + */ + .globl _C_LABEL(proc0),_C_LABEL(uvmspace_free),_C_LABEL(kernel_map) + .globl _C_LABEL(uvm_km_free),_C_LABEL(tss_free) +ENTRY(switch_exit) +#ifdef MULTIPROCESSOR + movq CPUVAR(IDLE_PCB),%r8 + movl CPUVAR(IDLE_TSS_SEL),%edx +#else + leaq _C_LABEL(proc0)(%rip),%r9 + movq P_ADDR(%r9),%r8 + movl P_MD_TSS_SEL(%r9),%edx +#endif + + /* In case we fault... */ + movq $0,CPUVAR(CURPROC) + + cli + + /* Restore stack pointers. */ + movq PCB_RSP(%r8),%rsp + movq PCB_RBP(%r8),%rbp + + /* Load TSS info. */ +#ifdef MULTIPROCESSOR + movq CPUVAR(GDT),%rax +#else + movq _C_LABEL(gdtstore)(%rip),%rax +#endif + + /* Switch address space. */ + movq PCB_CR3(%r8),%rcx + movq %rcx,%cr3 + + /* Switch TSS. */ + andl $~0x0200,4-SEL_KPL(%rax,%rdx,1) + ltr %dx + + /* We're always in the kernel, so we don't need the LDT. */ + + /* Restore cr0 (including FPU state). */ + movl PCB_CR0(%r8),%ecx + movq %rcx,%cr0 + + /* Record new pcb. */ + SET_CURPCB(%r8) + + /* Interrupts are okay again. */ + sti + + /* + * Schedule the dead process's vmspace and stack to be freed. + * {lpw_}exit2(l). Function still in %rsi (2nd arg), proc in + * %rdi (first arg). + */ + + call *%rsi + + /* Jump into cpu_switch() with the right state. */ + movq %r9, %r13 + movq $0, CPUVAR(CURPROC) + jmp switch_search + +/* + * savectx(struct pcb *pcb); + * Update pcb, saving current processor state. + */ +ENTRY(savectx) + /* Save stack pointers. */ + movq %rsp,PCB_RSP(%rdi) + movq %rbp,PCB_RBP(%rdi) + + ret + +IDTVEC(syscall32) + sysret /* go away please */ + +/* + * syscall insn entry. This currently isn't much faster, but + * it can be made faster in the future. + */ +IDTVEC(syscall) + swapgs + movq %r15,CPUVAR(SCRATCH) + movq CPUVAR(CURPCB),%r15 + movq PCB_RSP0(%r15),%r15 + xchgq %r15,%rsp + sti + + /* + * XXX don't need this whole frame, split of the + * syscall frame and trapframe is needed. + * First, leave some room for the trapno, error, + * ss:rsp, etc, so that all GP registers can be + * saved. Then, fill in the rest. + */ + pushq $(LSEL(LUDATA_SEL, SEL_UPL)) + pushq %r15 + subq $(TF_RSP-TF_TRAPNO),%rsp + movq CPUVAR(SCRATCH),%r15 + subq $32,%rsp + INTR_SAVE_GPRS + movw %fs,TF_FS(%rsp) + movw %gs,TF_GS(%rsp) + movw %es,TF_ES(%rsp) + movw $(LSEL(LUDATA_SEL, SEL_UPL)),TF_DS(%rsp) + movq %r11, TF_RFLAGS(%rsp) /* old rflags from syscall insn */ + movq $(LSEL(LUCODE_SEL, SEL_UPL)), TF_CS(%rsp) + movq %rcx,TF_RIP(%rsp) + movq $2,TF_ERR(%rsp) + movq $T_ASTFLT, TF_TRAPNO(%rsp) + + movq CPUVAR(CURPROC),%r14 + movq %rsp,P_MD_REGS(%r14) # save pointer to frame + andl $~MDP_IRET,P_MD_FLAGS(%r14) + call *P_MD_SYSCALL(%r14) +1: /* Check for ASTs on exit to user mode. */ + cli + CHECK_ASTPENDING(%r11) + je 2f + /* Always returning to user mode here. */ + CLEAR_ASTPENDING(%r11) + sti + /* Pushed T_ASTFLT into tf_trapno on entry. */ + call _C_LABEL(trap) + jmp 1b +2: + sti + testl $MDP_IRET, P_MD_FLAGS(%r14) + jne iret_return; +syscall_return: +#ifdef DIAGNOSTIC + movl CPUVAR(ILEVEL), %r8d + testl %r8d, %r8d + jne 3f +#endif + /* + * XXX interrupts off longer than they should be here. + */ + cli + swapgs + movw TF_GS(%rsp),%gs + movw TF_FS(%rsp),%fs + movw TF_ES(%rsp),%es + INTR_RESTORE_GPRS + addq $48,%rsp + popq %rcx /* return rip */ + addq $8,%rsp + popq %r11 /* flags as set by sysret insn */ + movq (%rsp),%rsp + sysretq + +#ifdef DIAGNOSTIC +3: movabsq $4f, %rdi + movl TF_RAX(%rsp),%esi + movl TF_RDI(%rsp),%edx + movl %ebx,%ecx + xorq %rax,%rax + call _C_LABEL(printf) +#ifdef DDB + int $3 +#endif /* DDB */ + movl $IPL_NONE,CPUVAR(ILEVEL) + jmp 1b +4: .asciz "WARNING: SPL NOT LOWERED ON SYSCALL %d %d EXIT %x %x\n" +#endif + + +NENTRY(proc_trampoline) +#ifdef MULTIPROCESSOR + call _C_LABEL(proc_trampoline_mp) +#endif + movl $IPL_NONE,CPUVAR(ILEVEL) + movq %r13,%rdi + call *%r12 + INTRFASTEXIT + /* NOTREACHED */ + +NENTRY(child_trampoline) +#ifdef MULTIPROCESSOR + call _C_LABEL(proc_trampoline_mp) +#endif + movl $IPL_NONE,CPUVAR(ILEVEL) + movq %r13,%rdi + call *%r12 + jmp syscall_return + + .globl _C_LABEL(osyscall_return) + +/* + * Old call gate entry for syscall. XXXfvdl: only needed if we're + * going to support running old NetBSD or ibcs2 binaries, etc, + * on NetBSD/amd64. + */ +IDTVEC(oosyscall) + /* Set rflags in trap frame. */ + pushfq + popq 8(%rsp) + pushq $7 # size of instruction for restart + jmp osyscall1 + +/* + * Trap gate entry for int $80 syscall, also used by sigreturn. + */ +IDTVEC(osyscall) + pushq $2 # size of instruction for restart +osyscall1: + pushq $T_ASTFLT # trap # for doing ASTs + INTRENTRY + sti + movq CPUVAR(CURPROC),%rdx + movq %rsp,P_MD_REGS(%rdx) # save pointer to frame + call *P_MD_SYSCALL(%rdx) +_C_LABEL(osyscall_return): +2: /* Check for ASTs on exit to user mode. */ + cli + CHECK_ASTPENDING(%r11) + je 1f + /* Always returning to user mode here. */ + CLEAR_ASTPENDING(%r11) + sti + /* Pushed T_ASTFLT into tf_trapno on entry. */ + call _C_LABEL(trap) + jmp 2b +iret_return: +#ifndef DIAGNOSTIC +1: INTRFASTEXIT +#else /* DIAGNOSTIC */ +1: cmpl $IPL_NONE,CPUVAR(ILEVEL) + jne 3f + INTRFASTEXIT +3: sti + movabsq $4f, %rdi + xorq %rax,%rax + call _C_LABEL(printf) +#ifdef DDB + int $3 +#endif /* DDB */ + movl $IPL_NONE,CPUVAR(ILEVEL) + jmp 2b +4: .asciz "WARNING: SPL NOT LOWERED ON SYSCALL EXIT\n" +#endif /* DIAGNOSTIC */ diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c new file mode 100644 index 00000000000..bd4cd513785 --- /dev/null +++ b/sys/arch/amd64/amd64/machdep.c @@ -0,0 +1,1874 @@ +/* $OpenBSD: machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1997, 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * 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) 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. + * + * @(#)machdep.c 7.4 (Berkeley) 6/3/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/signal.h> +#include <sys/signalvar.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/exec.h> +#include <sys/buf.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/msgbuf.h> +#include <sys/mount.h> +#include <sys/vnode.h> +#include <sys/extent.h> +#include <sys/core.h> +#include <sys/kcore.h> +#include <sys/syscallargs.h> + +#ifdef SYSVMSG +#include <sys/msg.h> +#endif + +#ifdef KGDB +#include <sys/kgdb.h> +#endif + +#include <dev/cons.h> + +#include <uvm/uvm_extern.h> +#include <uvm/uvm_page.h> + +#include <sys/sysctl.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/gdt.h> +#include <machine/pio.h> +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/specialreg.h> +#include <machine/bootinfo.h> +#include <machine/fpu.h> +#include <machine/mtrr.h> +#include <machine/mpbiosvar.h> + +#include <dev/isa/isareg.h> +#include <machine/isa_machdep.h> +#include <dev/ic/i8042reg.h> + +#ifdef DDB +#include <machine/db_machdep.h> +#include <ddb/db_extern.h> +#endif + +#include "isa.h" +#include "isadma.h" +#include "ksyms.h" + +/* the following is used externally (sysctl_hw) */ +char machine[] = "amd64"; /* cpu "architecture" */ +char machine_arch[] = "x86_64"; /* machine == machine_arch */ + +char bootinfo[BOOTINFO_MAXSIZE]; + +struct bi_devmatch *x86_64_alldisks = NULL; +int x86_64_ndisks = 0; + +#ifdef CPURESET_DELAY +int cpureset_delay = CPURESET_DELAY; +#else +int cpureset_delay = 2000; /* default to 2s */ +#endif + +int physmem; +u_int64_t dumpmem_low; +u_int64_t dumpmem_high; +extern int boothowto; +int cpu_class; + +char *ssym = NULL; + +#define CPUID2MODEL(cpuid) (((cpuid) >> 4) & 15) + +vaddr_t msgbuf_vaddr; +paddr_t msgbuf_paddr; + +vaddr_t idt_vaddr; +paddr_t idt_paddr; + +vaddr_t lo32_vaddr; +paddr_t lo32_paddr; + +struct vm_map *exec_map = NULL; +struct vm_map *phys_map = NULL; + +#ifdef NBUF +int nbuf = NUF; +#else +int nbuf = 0; +#endif + +#ifndef BUFCACHEPERCENT +#define BUFCACHEPERCENT 5 +#endif + +#ifdef BUFPAGES +int bufpages = BUFPAGES; +#else +int bufpages = 0; +#endif +int bufcachepercent = BUFCACHEPERCENT; + +#ifdef DEBUG +int sigdebug = 0; +pid_t sigpid = 0; +#define SDB_FOLLOW 0x01 +#endif + +extern paddr_t avail_start, avail_end; + +void (*delay_func)(int) = i8254_delay; +void (*microtime_func)(struct timeval *) = i8254_microtime; +void (*initclock_func)(void) = i8254_initclocks; + +struct mtrr_funcs *mtrr_funcs; + +/* + * Size of memory segments, before any memory is stolen. + */ +phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; +int mem_cluster_cnt; + +vaddr_t allocsys(vaddr_t); +void setup_buffers(vaddr_t *); +int cpu_dump(void); +int cpu_dumpsize(void); +u_long cpu_dump_mempagecnt(void); +void dumpsys(void); +void init_x86_64(paddr_t); +void syscall_intern(struct proc *p); + +/* + * Machine-dependent startup code + */ +void +cpu_startup(void) +{ + vaddr_t v; + vsize_t sz; + int x; + vaddr_t minaddr, maxaddr; + + /* + * Initialize error message buffer (et end of core). + */ + msgbuf_vaddr = uvm_km_valloc(kernel_map, x86_round_page(MSGBUFSIZE)); + if (msgbuf_vaddr == 0) + panic("failed to valloc msgbuf_vaddr"); + + /* msgbuf_paddr was init'd in pmap */ + for (x = 0; x < btoc(MSGBUFSIZE); x++) + pmap_kenter_pa((vaddr_t)msgbuf_vaddr + x * PAGE_SIZE, + msgbuf_paddr + x * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE); + pmap_update(pmap_kenel()); + + initmsgbuf((caddr_t)msgbuf_vaddr, round_page(MSGBUFSIZE)); + + printf("%s", version); + + printf("real mem = %u (%uK)\n", ctob(physmem), ctob(physmem)/1024); + + /* + * Find out how much space we need, allocate it, + * and then give everything true virtual addresses. + */ + sz = allocsys(0); + if ((v = uvm_km_zalloc(kernel_map, round_page(sz))) == 0) + panic("startup: no room for tables"); + if (allocsys(v) - v != sz) + panic("startup: table size inconsistency"); + + /* + * Now allocate buffers proper. They are different than the above + * in that they usually occupy more virtual memory than physical. + */ + setup_buffers(&maxaddr); + + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + minaddr = vm_map_min(kernel_map); + exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); + + /* + * Allocate a submap for physio + */ + minaddr = vm_map_min(kernel_map); + phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + VM_PHYS_SIZE, 0, FALSE, NULL); + + printf("avail mem = %lu (%luK)\n", ptoa(uvmexp.free), + ptoa(uvmexp.free)/1024); + printf("using %u buffers containing %u bytes (%uK) of memory\n", + nbuf, bufpages * PAGE_SIZE, bufpages * PAGE_SIZE / 1024); + + bufinit(); + + if (boothowto & RB_CONFIG) { +#ifdef BOOT_CONFIG + user_config(); +#else + printf("kernel does not support - c; continuing..\n"); +#endif + } + + /* Safe for i/o port / memory space allocation to use malloc now. */ + x86_bus_space_mallocok(); +} + + +/* + * The following defines are for the code in setup_buffers that tries to + * ensure that enough ISA DMAable memory is still left after the buffercache + * has been allocated. + */ +#define CHUNKSZ (3 * 1024 * 1024) +#define ISADMA_LIMIT (16 * 1024 * 1024) /* XXX wrong place */ +#define ALLOC_PGS(sz, limit, pgs) \ + uvm_pglistalloc((sz), 0, (limit), PAGE_SIZE, 0, &(pgs), 1, 0) +#define FREE_PGS(pgs) uvm_pglistfree(&(pgs)) + +/* + * Allocate space for system data structures. We are given + * a starting virtual address and we return a final virtual + * address; along the way we set each data structure pointer. + * + * We call allocsys() with 0 to find out how much space we want, + * allocate that much and fill it with zeroes, and then call + * allocsys() again with the correct base virtual address. + */ +vaddr_t +allocsys(vaddr_t v) +{ + +#define valloc(name, type, num) \ + v = (vaddr_t)(((name) = (type *)v) + (num)) + +#ifdef SYSVMSG + valloc(msgpool, char, msginfo.msgmax); + valloc(msgmaps, struct msgmap, msginfo.msgseg); + valloc(msghdrs, struct msg, msginfo.msgtql); + valloc(msqids, struct msqid_ds, msginfo.msgmni); +#endif + + /* + * Determine how many buffers to allocate. We use 10% of the + * first 2MB of memory, and 5% of the rest, with a minimum of 16 + * buffers. We allocate 1/2 as many swap buffer headers as file + * i/o buffers. + */ + if (bufpages == 0) { + if (physmem < btoc(2 * 1024 * 1024)) + bufpages = physmem / 10; + else + bufpages = (btoc(2 * 1024 * 1024) + physmem) * + bufcachepercent / 100; + } + if (nbuf == 0) { + nbuf = bufpages; + if (nbuf < 16) + nbuf = 16; + } + + /* Restrict to at most 35% filled kvm */ + /* XXX - This needs UBC... */ + if (nbuf > + (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) / MAXBSIZE * 35 / 100) + nbuf = (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) / + MAXBSIZE * 35 / 100; + + /* More buffer pages than fits into the buffers is senseless. */ + if (bufpages > nbuf * MAXBSIZE / PAGE_SIZE) + bufpages = nbuf * MAXBSIZE / PAGE_SIZE; + + valloc(buf, struct buf, nbuf); + return v; +} + +void +setup_buffers(vaddr_t *maxaddr) +{ + vsize_t size; + vaddr_t addr; + int base, residual, left, chunk, i; + struct pglist pgs, saved_pgs; + struct vm_page *pg; + int rv; + + size = MAXBSIZE * nbuf; + addr = vm_map_min(kernel_map); + if ((rv = uvm_map(kernel_map, &addr, round_page(size), + NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE, + UVM_ADV_NORMAL, 0)))) + panic("cpu_startup: cannot allocate VM for buffers %d", rv); + buffers = (char *)addr; + + base = bufpages / nbuf; + residual = bufpages % nbuf; + if (base >= MAXBSIZE / PAGE_SIZE) { + /* don't want to alloc more physical mem than needed */ + base = MAXBSIZE / PAGE_SIZE; + residual = 0; + } + + /* + * In case we might need DMA bouncing we have to make sure there + * is some memory below 16MB available. On machines with many + * pages reserved for the buffer cache we risk filling all of that + * area with buffer pages. We still want much of the buffers + * reside there as that lowers the probability of them needing to + * bounce, but we have to set aside some space for DMA buffers too. + * + * The current strategy is to grab hold of one 3MB chunk below 16MB + * first, which we are saving for DMA buffers, then try to get + * one chunk at a time for fs buffers, until that is not possible + * anymore, at which point we get the rest wherever we may find it. + * After that we give our saved area back. That will guarantee at + * least 3MB below 16MB left for drivers' attach routines, among + * them isadma. However we still have a potential problem of PCI + * devices attached earlier snatching that memory. This can be + * solved by making the PCI DMA memory allocation routines go for + * memory above 16MB first. + */ + + left = bufpages; + + /* + * First, save ISA DMA bounce buffer area so we won't lose that + * capability. + */ + TAILQ_INIT(&saved_pgs); + TAILQ_INIT(&pgs); + if (!ALLOC_PGS(CHUNKSZ, ISADMA_LIMIT, saved_pgs)) { + /* + * Then, grab as much ISA DMAable memory as possible + * for the buffer cache as it is nice to not need to + * bounce all buffer I/O. + */ + for (left = bufpages; left > 0; left -= chunk) { + chunk = min(left, CHUNKSZ / PAGE_SIZE); + if (ALLOC_PGS(chunk * PAGE_SIZE, ISADMA_LIMIT, pgs)) + break; + } + } + + /* + * If we need more pages for the buffer cache, get them from anywhere. + */ + if (left > 0 && ALLOC_PGS(left * PAGE_SIZE, avail_end, pgs)) + panic("cannot get physical memory for buffer cache"); + + /* + * Finally, give back the ISA DMA bounce buffer area, so it can be + * allocated by the isadma driver later. + */ + if (!TAILQ_EMPTY(&saved_pgs)) + FREE_PGS(saved_pgs); + + pg = TAILQ_FIRST(&pgs); + for (i = 0; i < nbuf; i++) { + /* + * First <residual> buffers get (base+1) physical pages + * allocated for them. The rest get (base) physical pages. + * + * The rest of each buffer occupies virtual space, + * but has no physical memory allocated for it. + */ + addr = (vaddr_t)buffers + i * MAXBSIZE; + for (size = PAGE_SIZE * (i < residual ? base + 1 : base); + size > 0; size -= PAGE_SIZE, addr += PAGE_SIZE) { + pmap_kenter_pa(addr, VM_PAGE_TO_PHYS(pg), + VM_PROT_READ|VM_PROT_WRITE); + pg = TAILQ_NEXT(pg, pageq); + } + } + pmap_update(pmap_kernel()); +} + +/* + * Set up proc0's TSS and LDT. + */ +void +x86_64_proc0_tss_ldt_init(void) +{ + struct pcb *pcb; + int x; + + gdt_init(); + + cpu_info_primary.ci_curpcb = pcb = &proc0.p_addr->u_pcb; + + pcb->pcb_flags = 0; + pcb->pcb_tss.tss_iobase = + (u_int16_t)((caddr_t)pcb->pcb_iomap - (caddr_t)&pcb->pcb_tss); + for (x = 0; x < sizeof(pcb->pcb_iomap) / 4; x++) + pcb->pcb_iomap[x] = 0xffffffff; + + pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = + GSYSSEL(GLDT_SEL, SEL_KPL); + pcb->pcb_cr0 = rcr0(); + pcb->pcb_tss.tss_rsp0 = (u_int64_t)proc0.p_addr + USPACE - 16; + pcb->pcb_tss.tss_ist[0] = (u_int64_t)proc0.p_addr + PAGE_SIZE; + proc0.p_md.md_regs = (struct trapframe *)pcb->pcb_tss.tss_rsp0 - 1; + proc0.p_md.md_tss_sel = tss_alloc(pcb); + + ltr(proc0.p_md.md_tss_sel); + lldt(pcb->pcb_ldt_sel); +} + +/* + * Set up TSS and LDT for a new PCB. + */ + +void +x86_64_init_pcb_tss_ldt(ci) + struct cpu_info *ci; +{ + int x; + struct pcb *pcb = ci->ci_idle_pcb; + + pcb->pcb_tss.tss_iobase = + (u_int16_t)((caddr_t)pcb->pcb_iomap - (caddr_t)&pcb->pcb_tss); + for (x = 0; x < sizeof(pcb->pcb_iomap) / 4; x++) + pcb->pcb_iomap[x] = 0xffffffff; + + /* XXXfvdl pmap_kernel not needed */ + pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = + GSYSSEL(GLDT_SEL, SEL_KPL); + pcb->pcb_cr0 = rcr0(); + + ci->ci_idle_tss_sel = tss_alloc(pcb); +} + +/* + * machine dependent system variables. + */ +int +cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) + int *name; + u_int namelen; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; + struct proc *p; +{ + dev_t consdev; + struct btinfo_bootpath *bibp; + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case CPU_CONSDEV: + if (cn_tab != NULL) + consdev = cn_tab->cn_dev; + else + consdev = NODEV; + return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, + sizeof consdev)); + + case CPU_BOOTED_KERNEL: + bibp = lookup_bootinfo(BTINFO_BOOTPATH); + if(!bibp) + return(ENOENT); /* ??? */ + return (sysctl_rdstring(oldp, oldlenp, newp, bibp->bootpath)); + case CPU_DISKINFO: + if (x86_64_alldisks == NULL) + return (ENOENT); + return (sysctl_rdstruct(oldp, oldlenp, newp, x86_64_alldisks, + sizeof (struct disklist) + + (x86_64_ndisks - 1) * sizeof (struct nativedisk_info))); + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +/* + * Send an interrupt to process. + * + * Stack is set up to allow sigcode stored + * in u. 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, int mask, u_long code, int type, + union sigval val) +{ + struct proc *p = curproc; + struct trapframe *tf = p->p_md.md_regs; + struct sigacts * psp = p->p_sigacts; + struct sigcontext ksc; + siginfo_t ksi; + register_t sp, scp, sip; + u_long sss; + +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) + printf("sendsig: %s[%d] sig %d catcher %p\n", + p->p_comm, p->p_pid, sig, catcher); +#endif + + if (p->p_md.md_flags & MDP_USEDFPU) + fpusave_proc(p, 1); + + bcopy(tf, &ksc, sizeof(*tf)); + ksc.sc_onstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; + ksc.sc_mask = mask; + + /* Allocate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) && !ksc.sc_onstack && + (psp->ps_sigonstack & sigmask(sig))) { + sp = (register_t)psp->ps_sigstk.ss_sp + psp->ps_sigstk.ss_size; + psp->ps_sigstk.ss_flags |= SS_ONSTACK; + } else + sp = tf->tf_rsp; + + sp &= ~15ULL; /* just in case */ + sss = (sizeof(ksc) + 15) & ~15; + sip = 0; + if (psp->ps_siginfo & sigmask(sig)) { + sip = sp - ((sizeof(ksi) + 15) & ~15); + sss += (sizeof(ksi) + 15) & ~15; + + initsiginfo(&ksi, sig, code, type, val); + if (copyout(&ksi, (void *)sip, sizeof(ksi))) + sigexit(p, SIGILL); + } + scp = sp - sss; + + if (copyout(&ksc, (void *)scp, sizeof(ksc))) + sigexit(p, SIGILL); + + /* + * Build context to run handler in. + */ + tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_fs = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_gs = LSEL(LUDATA_SEL, SEL_UPL); + + tf->tf_rax = (u_int64_t)catcher; + tf->tf_rdi = sig; + tf->tf_rsi = sip; + tf->tf_rdx = scp; + + tf->tf_rip = (u_int64_t)p->p_sigcode; + tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); + tf->tf_rflags &= ~(PSL_T|PSL_VM|PSL_AC); + tf->tf_rsp = sp - sss; + tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); + +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) + printf("sendsig(%d): pc 0x%x, catcher 0x%x\n", p->p_pid, + tf->tf_rip, tf->tf_rax); +#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 + * psl to gain improper privileges or to cause + * a machine fault. + */ +int +sys_sigreturn(struct proc *p, void *v, register_t *retval) +{ + struct sys_sigreturn_args /* { + syscallarg(struct sigcontext *) sigcntxp; + } */ *uap = v; + struct sigcontext *scp, ksc; + struct trapframe *tf = p->p_md.md_regs; + int error; + + scp = SCARG(uap, sigcntxp); +#ifdef DEBUG + if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) + printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); +#endif + + if (copyin((caddr_t)scp, &ksc, sizeof ksc)) + return (error); + + ksc.sc_trapno = tf->tf_trapno; + ksc.sc_err = tf->tf_err; + bcopy(&ksc, tf, sizeof(*tf)); + + /* Restore signal stack. */ + if (ksc.sc_onstack) + p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; + p->p_sigmask = ksc.sc_mask & ~sigcantmask; + + return (EJUSTRETURN); +} + +int waittime = -1; +struct pcb dumppcb; + +void +boot(int howto) +{ + + if (cold) { + howto |= RB_HALT; + goto haltsys; + } + + boothowto = howto; + if ((howto & RB_NOSYNC) == 0 && waittime < 0) { + waittime = 0; + + if (curproc == NULL) + curproc = &proc0; /* XXX */ + vfs_shutdown(); + /* + * If we've been adjusting the clock, the todr + * will be out of synch; adjust it now. + */ + if ((howto & RB_TIMEBAD) == 0) { + resettodr(); + } else { + printf("WARNING: not updating battery clock\n"); + } + } + + /* Disable interrupts. */ + splhigh(); + + /* Do a dump if requested. */ + if (howto & RB_DUMP) + dumpsys(); + +haltsys: + doshutdownhooks(); + +#ifdef MULTIPROCESSOR + x86_broadcast_ipi(X86_IPI_HALT); +#endif + + if (howto & RB_HALT) { + if (howto & RB_POWERDOWN) { +#if NACPI > 0 + delay(500000); + acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); + printf("WARNING: powerdown failed!\n"); +#endif + } + + printf("\n"); + printf("The operating system has halted.\n"); + printf("Please press any key to reboot.\n\n"); + cnpollc(1); /* for proper keyboard command handling */ + cngetc(); + cnpollc(0); + } + + printf("rebooting...\n"); + if (cpureset_delay > 0) + delay(cpureset_delay * 1000); + cpu_reset(); + for(;;) ; + /*NOTREACHED*/ +} + +/* + * XXXfvdl share dumpcode. + */ + +/* + * These variables are needed by /sbin/savecore + */ +u_int32_t dumpmag = 0x8fca0101; /* magic number */ +int dumpsize = 0; /* pages */ +long dumplo = 0; /* blocks */ + +/* + * cpu_dump: dump the machine-dependent kernel core dump headers. + */ +int +cpu_dump() +{ + int (*dump)(dev_t, daddr_t, caddr_t, size_t); + char buf[dbtob(1)]; + kcore_seg_t *segp; + + dump = bdevsw[major(dumpdev)].d_dump; + + memset(buf, 0, sizeof buf); + segp = (kcore_seg_t *)buf; + + /* + * Generate a segment header. + */ + CORE_SETMAGIC(*segp, KCORE_MAGIC, MID_MACHINE, CORE_CPU); + segp->c_size = dbtob(1) - ALIGN(sizeof(*segp)); + + return (dump(dumpdev, dumplo, (caddr_t)buf, dbtob(1))); +} + +/* + * This is called by main to set dumplo and dumpsize. + * Dumps always skip the first PAGE_SIZE of disk space + * in case there might be a disk label stored there. + * If there is extra space, put dump at the end to + * reduce the chance that swapping trashes it. + */ +void +dumpconf() +{ + const struct bdevsw *bdev; + int nblks, dumpblks; /* size of dump area */ + + if (dumpdev == NODEV) + goto bad; + bdev = &bdevsw[major(dumpdev)]; + + if (bdev == NULL) + panic("dumpconf: bad dumpdev=0x%x", dumpdev); + if (bdev->d_psize == NULL) + goto bad; + nblks = (*bdev->d_psize)(dumpdev); + if (nblks <= ctod(1)) + goto bad; + + dumpblks = cpu_dumpsize(); + if (dumpblks < 0) + goto bad; + dumpblks += ctod(cpu_dump_mempagecnt()); + + /* If dump won't fit (incl. room for possible label), punt. */ + if (dumpblks > (nblks - ctod(1))) + goto bad; + + /* Put dump at end of partition */ + dumplo = nblks - dumpblks; + + /* dumpsize is in page units, and doesn't include headers. */ + dumpsize = cpu_dump_mempagecnt(); + return; + + bad: + dumpsize = 0; +} + +/* + * Doadump comes here after turning off memory management and + * getting on the dump stack, either when called above, or by + * the auto-restart code. + */ +#define BYTES_PER_DUMP PAGE_SIZE /* must be a multiple of pagesize XXX small */ +static vaddr_t dumpspace; + +vaddr_t +reserve_dumppages(vaddr_t p) +{ + + dumpspace = p; + return (p + BYTES_PER_DUMP); +} + +void +dumpsys() +{ + u_long totalbytesleft, bytes, i, n, memseg; + u_long maddr; + int psize; + daddr_t blkno; + int (*dump)(dev_t, daddr_t, caddr_t, size_t); + int error; + + /* Save registers. */ + savectx(&dumppcb); + + if (dumpdev == NODEV) + return; + + /* + * For dumps during autoconfiguration, + * if dump device has already configured... + */ + if (dumpsize == 0) + dumpconf(); + if (dumplo <= 0 || dumpsize == 0) { + printf("\ndump to dev %u,%u not possible\n", major(dumpdev), + minor(dumpdev)); + return; + } + printf("\ndumping to dev %u,%u offset %ld\n", major(dumpdev), + minor(dumpdev), dumplo); + + error = (*bdevsw[major(dumpdev)].d_psize)(dumpdev); + printf("dump "); + if (psize == -1) { + printf("area unavailable\n"); + return; + } + + if ((error = cpu_dump()) != 0) + goto err; + + totalbytesleft = ptoa(cpu_dump_mempagecnt()); + blkno = dumplo + cpu_dumpsize(); + dump = bdevsw[major(dumpdev)].d_dump; + error = 0; + + for (memseg = 0; memseg < mem_cluster_cnt; memseg++) { + maddr = mem_clusters[memseg].start; + bytes = mem_clusters[memseg].size; + + for (i = 0; i < bytes; i += n, totalbytesleft -= n) { + /* Print out how many MBs we have left to go. */ + if ((totalbytesleft % (1024*1024)) == 0) + printf("%ld ", totalbytesleft / (1024 * 1024)); + + /* Limit size for next transfer. */ + n = bytes - i; + if (n > BYTES_PER_DUMP) + n = BYTES_PER_DUMP; + + (void) pmap_map(dumpspace, maddr, maddr + n, + VM_PROT_READ); + + error = (*dump)(dumpdev, blkno, (caddr_t)dumpspace, n); + if (error) + goto err; + maddr += n; + blkno += btodb(n); /* XXX? */ + +#if 0 /* XXX this doesn't work. grr. */ + /* operator aborting dump? */ + if (sget() != NULL) { + error = EINTR; + break; + } +#endif + } + } + + err: + switch (error) { + + case ENXIO: + printf("device bad\n"); + break; + + case EFAULT: + printf("device not ready\n"); + break; + + case EINVAL: + printf("area improper\n"); + break; + + case EIO: + printf("i/o error\n"); + break; + + case EINTR: + printf("aborted from console\n"); + break; + + case 0: + printf("succeeded\n"); + break; + + default: + printf("error %d\n", error); + break; + } + printf("\n\n"); + delay(5000000); /* 5 seconds */ +} + +/* + * Clear registers on exec + */ +void +setregs(struct proc *p, struct exec_package *pack, u_long stack, + register_t *retval) +{ + struct pcb *pcb = &p->p_addr->u_pcb; + struct trapframe *tf; + + /* If we were using the FPU, forget about it. */ + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 0); + +#ifdef USER_LDT + pmap_ldt_cleanup(p); +#endif + + syscall_intern(p); + + p->p_md.md_flags &= ~MDP_USEDFPU; + pcb->pcb_flags = 0; + pcb->pcb_savefpu.fp_fxsave.fx_fcw = __NetBSD_NPXCW__; + pcb->pcb_savefpu.fp_fxsave.fx_mxcsr = __INITIAL_MXCSR__; + pcb->pcb_savefpu.fp_fxsave.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__; + + tf = p->p_md.md_regs; + tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_fs = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_gs = LSEL(LUDATA_SEL, SEL_UPL); + tf->tf_rdi = 0; + tf->tf_rsi = 0; + tf->tf_rbp = 0; + tf->tf_rbx = 0; + tf->tf_rdx = 0; + tf->tf_rcx = 0; + tf->tf_rax = 0; + tf->tf_rip = pack->ep_entry; + tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL); + tf->tf_rflags = PSL_USERSET; + tf->tf_rsp = stack; + tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL); + + retval[1] = 0; +} + +/* + * Initialize segments and descriptor tables + */ + +struct gate_descriptor *idt; +char idt_allocmap[NIDT]; +struct simplelock idt_lock; +char *ldtstore; +char *gdtstore; +extern struct user *proc0paddr; + +void +setgate(gd, func, ist, type, dpl, sel) + struct gate_descriptor *gd; + void *func; + int ist, type, dpl, sel; +{ + gd->gd_looffset = (u_int64_t)func & 0xffff; + gd->gd_selector = sel; + gd->gd_ist = ist; + gd->gd_type = type; + gd->gd_dpl = dpl; + gd->gd_p = 1; + gd->gd_hioffset = (u_int64_t)func >> 16; + gd->gd_zero = 0; + gd->gd_xx1 = 0; + gd->gd_xx2 = 0; + gd->gd_xx3 = 0; +} + +void +unsetgate(gd) + struct gate_descriptor *gd; +{ + memset(gd, 0, sizeof (*gd)); +} + +void +setregion(rd, base, limit) + struct region_descriptor *rd; + void *base; + u_int16_t limit; +{ + rd->rd_limit = limit; + rd->rd_base = (u_int64_t)base; +} + +/* + * Note that the base and limit fields are ignored in long mode. + */ +void +set_mem_segment(sd, base, limit, type, dpl, gran, def32, is64) + struct mem_segment_descriptor *sd; + void *base; + size_t limit; + int type, dpl, gran, is64; +{ + sd->sd_lolimit = (unsigned)limit; + sd->sd_lobase = (unsigned long)base; + sd->sd_type = type; + sd->sd_dpl = dpl; + sd->sd_p = 1; + sd->sd_hilimit = (unsigned)limit >> 16; + sd->sd_avl = 0; + sd->sd_long = is64; + sd->sd_def32 = def32; + sd->sd_gran = gran; + sd->sd_hibase = (unsigned long)base >> 24; +} + +void +set_sys_segment(sd, base, limit, type, dpl, gran) + struct sys_segment_descriptor *sd; + void *base; + size_t limit; + int type, dpl, gran; +{ + memset(sd, 0, sizeof *sd); + sd->sd_lolimit = (unsigned)limit; + sd->sd_lobase = (u_int64_t)base; + sd->sd_type = type; + sd->sd_dpl = dpl; + sd->sd_p = 1; + sd->sd_hilimit = (unsigned)limit >> 16; + sd->sd_gran = gran; + sd->sd_hibase = (u_int64_t)base >> 24; +} + +void cpu_init_idt() +{ + struct region_descriptor region; + + setregion(®ion, idt, NIDT * sizeof(idt[0]) - 1); + lidt(®ion); +} + + +#define IDTVEC(name) __CONCAT(X, name) +typedef void (vector)(void); +extern vector IDTVEC(syscall); +extern vector IDTVEC(syscall32); +extern vector IDTVEC(osyscall); +extern vector IDTVEC(oosyscall); +extern vector *IDTVEC(exceptions)[]; + +#define KBTOB(x) ((size_t)(x) * 1024UL) + +#if 0 +void +beepme(int pitch, int duration) +{ +#define IO_TIMER1 0x040 +#define IO_PPI 0x061 +#define TIMER_SEL2 0x80 +#define TIMER_16BIT 0x30 +#define TIMER_SQWAVE 0x06 +#define TIMER_CNTR2 (IO_TIMER1 + 2) +#define TIMER_MODE (IO_TIMER1 + 3) +#define TIMER_FREQ 1193182 +#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x)) + +#define PIT_ENABLETMR2 0x01 +#define PIT_SPKRDATA 0x02 +#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA) + +#define PITCH 440 + + outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE); + outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256); + outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256); + outb(IO_PPI, inb(IO_PPI) | PIT_SPKR); + delay(duration / 2); + outb(IO_PPI, inb(IO_PPI) & ~PIT_SPKR); + delay(duration / 2); +} +#endif + +void +init_x86_64(first_avail) + paddr_t first_avail; +{ + extern void consinit(void); + extern struct extent *iomem_ex; + struct region_descriptor region; + struct mem_segment_descriptor *ldt_segp; + int x, first16q, ist; + u_int64_t seg_start, seg_end; + u_int64_t seg_start1, seg_end1; +#if !defined(REALEXTMEM) && !defined(REALBASEMEM) + struct btinfo_memmap *bim; + u_int64_t addr, size, io_end; +#endif + + cpu_init_msrs(&cpu_info_primary); + + proc0.p_addr = proc0paddr; + cpu_info_primary.ci_curpcb = &proc0.p_addr->u_pcb; + + x86_bus_space_init(); + + consinit(); /* XXX SHOULD NOT BE DONE HERE */ + + /* + * Initailize PAGE_SIZE-dependent variables. + */ + uvm_setpagesize(); + +#if 0 + uvmexp.ncolors = 2; +#endif + + avail_start = PAGE_SIZE; /* BIOS leaves data in low memory */ + /* and VM system doesn't work with phys 0 */ +#ifdef MULTIPROCESSOR + if (avail_start < MP_TRAMPOLINE + PAGE_SIZE) + avail_start = MP_TRAMPOLINE + PAGE_SIZE; +#endif + + /* + * Call pmap initialization to make new kernel address space. + * We must do this before loading pages into the VM system. + */ + pmap_bootstrap(VM_MIN_KERNEL_ADDRESS); + + if (avail_start != PAGE_SIZE) + pmap_prealloc_lowmem_ptps(); + +#if !defined(REALBASEMEM) && !defined(REALEXTMEM) + + /* + * Check to see if we have a memory map from the BIOS (passed + * to us by the boot program. + */ + bim = lookup_bootinfo(BTINFO_MEMMAP); + if (bim != NULL && bim->num > 0) { +#if DEBUG_MEMLOAD + printf("BIOS MEMORY MAP (%d ENTRIES):\n", bim->num); +#endif + for (x = 0; x < bim->num; x++) { + addr = bim->entry[x].addr; + size = bim->entry[x].size; +#if DEBUG_MEMLOAD + printf(" addr 0x%lx size 0x%lx type 0x%x\n", + addr, size, bim->entry[x].type); +#endif + + /* + * If the segment is not memory, skip it. + */ + switch (bim->entry[x].type) { + case BIM_Memory: + case BIM_ACPI: + case BIM_NVS: + break; + default: + continue; + } + + seg_start = addr; + seg_end = addr + size; + + if (seg_end > 0x100000000000ULL) { + printf("WARNING: skipping large " + "memory map entry: " + "0x%lx/0x%lx/0x%x\n", + addr, size, + bim->entry[x].type); + continue; + } + + /* + * Allocate the physical addresses used by RAM + * from the iomem extent map. This is done before + * the addresses are page rounded just to make + * sure we get them all. + */ + if (seg_start < 0x100000000UL) { + if (seg_end > 0x100000000UL) + io_end = 0x100000000UL; + else + io_end = seg_end; + if (extent_alloc_region(iomem_ex, seg_start, + io_end - seg_start, EX_NOWAIT)) { + /* XXX What should we do? */ + printf("WARNING: CAN'T ALLOCATE " + "MEMORY SEGMENT %d " + "(0x%lx/0x%lx/0l%x) FROM " + "IOMEM EXTENT MAP!\n", + x, seg_start, io_end - seg_start, + bim->entry[x].type); + } + } + + /* + * If it's not free memory, skip it. + */ + if (bim->entry[x].type != BIM_Memory) + continue; + + /* XXX XXX XXX */ + if (mem_cluster_cnt >= VM_PHYSSEG_MAX) + panic("init386: too many memory segments"); + + seg_start = round_page(seg_start); + seg_end = trunc_page(seg_end); + + if (seg_start == seg_end) + continue; + + mem_clusters[mem_cluster_cnt].start = seg_start; + mem_clusters[mem_cluster_cnt].size = + seg_end - seg_start; + + if (avail_end < seg_end) + avail_end = seg_end; + physmem += atop(mem_clusters[mem_cluster_cnt].size); + mem_cluster_cnt++; + } + } +#endif /* ! REALBASEMEM && ! REALEXTMEM */ + + /* + * If the loop above didn't find any valid segment, fall back to + * former code. + */ + if (mem_cluster_cnt == 0) { + /* + * Allocate the physical addresses used by RAM from the iomem + * extent map. This is done before the addresses are + * page rounded just to make sure we get them all. + */ + if (extent_alloc_region(iomem_ex, 0, KBTOB(biosbasemem), + EX_NOWAIT)) { + /* XXX What should we do? */ + printf("WARNING: CAN'T ALLOCATE BASE MEMORY FROM " + "IOMEM EXTENT MAP!\n"); + } + mem_clusters[0].start = 0; + mem_clusters[0].size = trunc_page(KBTOB(biosbasemem)); + physmem += atop(mem_clusters[0].size); + if (extent_alloc_region(iomem_ex, IOM_END, KBTOB(biosextmem), + EX_NOWAIT)) { + /* XXX What should we do? */ + printf("WARNING: CAN'T ALLOCATE EXTENDED MEMORY FROM " + "IOMEM EXTENT MAP!\n"); + } +#if NISADMA > 0 + /* + * Some motherboards/BIOSes remap the 384K of RAM that would + * normally be covered by the ISA hole to the end of memory + * so that it can be used. However, on a 16M system, this + * would cause bounce buffers to be allocated and used. + * This is not desirable behaviour, as more than 384K of + * bounce buffers might be allocated. As a work-around, + * we round memory down to the nearest 1M boundary if + * we're using any isadma devices and the remapped memory + * is what puts us over 16M. + */ + if (biosextmem > (15*1024) && biosextmem < (16*1024)) { + char pbuf[9]; + + format_bytes(pbuf, sizeof(pbuf), + biosextmem - (15*1024)); + printf("Warning: ignoring %s of remapped memory\n", + pbuf); + biosextmem = (15*1024); + } +#endif + mem_clusters[1].start = IOM_END; + mem_clusters[1].size = trunc_page(KBTOB(biosextmem)); + physmem += atop(mem_clusters[1].size); + + mem_cluster_cnt = 2; + + avail_end = IOM_END + trunc_page(KBTOB(biosextmem)); + } + + /* + * If we have 16M of RAM or less, just put it all on + * the default free list. Otherwise, put the first + * 16M of RAM on a lower priority free list (so that + * all of the ISA DMA'able memory won't be eaten up + * first-off). + */ + if (avail_end <= (16 * 1024 * 1024)) + first16q = VM_FREELIST_DEFAULT; + else + first16q = VM_FREELIST_FIRST16; + + /* Make sure the end of the space used by the kernel is rounded. */ + first_avail = round_page(first_avail); + + /* + * Now, load the memory clusters (which have already been + * rounded and truncated) into the VM system. + * + * NOTE: WE ASSUME THAT MEMORY STARTS AT 0 AND THAT THE KERNEL + * IS LOADED AT IOM_END (1M). + */ + for (x = 0; x < mem_cluster_cnt; x++) { + seg_start = mem_clusters[x].start; + seg_end = mem_clusters[x].start + mem_clusters[x].size; + seg_start1 = 0; + seg_end1 = 0; + + if (seg_start > 0xffffffffULL) { + printf("skipping %lld bytes of memory above 4GB\n", + seg_end - seg_start); + continue; + } + if (seg_end > 0x100000000ULL) { + printf("skipping %lld bytes of memory above 4GB\n", + seg_end - 0x100000000ULL); + seg_end = 0x100000000ULL; + } + + /* + * Skip memory before our available starting point. + */ + if (seg_end <= avail_start) + continue; + + if (avail_start >= seg_start && avail_start < seg_end) { + if (seg_start != 0) + panic("init_x86_64: memory doesn't start at 0"); + seg_start = avail_start; + if (seg_start == seg_end) + continue; + } + + /* + * If this segment contains the kernel, split it + * in two, around the kernel. + */ + if (seg_start <= IOM_END && first_avail <= seg_end) { + seg_start1 = first_avail; + seg_end1 = seg_end; + seg_end = IOM_END; + } + + /* First hunk */ + if (seg_start != seg_end) { + if (seg_start <= (16 * 1024 * 1024) && + first16q != VM_FREELIST_DEFAULT) { + u_int64_t tmp; + + if (seg_end > (16 * 1024 * 1024)) + tmp = (16 * 1024 * 1024); + else + tmp = seg_end; +#if DEBUG_MEMLOAD + printf("loading 0x%qx-0x%qx (0x%lx-0x%lx)\n", + (unsigned long long)seg_start, + (unsigned long long)tmp, + atop(seg_start), atop(tmp)); +#endif + uvm_page_physload(atop(seg_start), + atop(tmp), atop(seg_start), + atop(tmp), first16q); + seg_start = tmp; + } + + if (seg_start != seg_end) { +#if DEBUG_MEMLOAD + printf("loading 0x%qx-0x%qx (0x%lx-0x%lx)\n", + (unsigned long long)seg_start, + (unsigned long long)seg_end, + atop(seg_start), atop(seg_end)); +#endif + uvm_page_physload(atop(seg_start), + atop(seg_end), atop(seg_start), + atop(seg_end), VM_FREELIST_DEFAULT); + } + } + + /* Second hunk */ + if (seg_start1 != seg_end1) { + if (seg_start1 <= (16 * 1024 * 1024) && + first16q != VM_FREELIST_DEFAULT) { + u_int64_t tmp; + + if (seg_end1 > (16 * 1024 * 1024)) + tmp = (16 * 1024 * 1024); + else + tmp = seg_end1; +#if DEBUG_MEMLOAD + printf("loading 0x%qx-0x%qx (0x%lx-0x%lx)\n", + (unsigned long long)seg_start1, + (unsigned long long)tmp, + atop(seg_start1), atop(tmp)); +#endif + uvm_page_physload(atop(seg_start1), + atop(tmp), atop(seg_start1), + atop(tmp), first16q); + seg_start1 = tmp; + } + + if (seg_start1 != seg_end1) { +#if DEBUG_MEMLOAD + printf("loading 0x%qx-0x%qx (0x%lx-0x%lx)\n", + (unsigned long long)seg_start1, + (unsigned long long)seg_end1, + atop(seg_start1), atop(seg_end1)); +#endif + uvm_page_physload(atop(seg_start1), + atop(seg_end1), atop(seg_start1), + atop(seg_end1), VM_FREELIST_DEFAULT); + } + } + } + + /* + * Steal memory for the message buffer (at end of core). + */ + { + struct vm_physseg *vps = NULL; + psize_t sz = round_page(MSGBUFSIZE); + psize_t reqsz = sz; + + for (x = 0; x < vm_nphysseg; x++) { + vps = &vm_physmem[x]; + if (ptoa(vps->avail_end) == avail_end) + break; + } + if (x == vm_nphysseg) + panic("init_x86_64: can't find end of memory"); + + /* Shrink so it'll fit in the last segment. */ + if ((vps->avail_end - vps->avail_start) < atop(sz)) + sz = ptoa(vps->avail_end - vps->avail_start); + + vps->avail_end -= atop(sz); + vps->end -= atop(sz); + msgbuf_paddr = ptoa(vps->avail_end); + + /* Remove the last segment if it now has no pages. */ + if (vps->start == vps->end) { + for (vm_nphysseg--; x < vm_nphysseg; x++) + vm_physmem[x] = vm_physmem[x + 1]; + } + + /* Now find where the new avail_end is. */ + for (avail_end = 0, x = 0; x < vm_nphysseg; x++) + if (vm_physmem[x].avail_end > avail_end) + avail_end = vm_physmem[x].avail_end; + avail_end = ptoa(avail_end); + + /* Warn if the message buffer had to be shrunk. */ + if (sz != reqsz) + printf("WARNING: %ld bytes not available for msgbuf " + "in last cluster (%ld used)\n", reqsz, sz); + } + + /* + * XXXfvdl todo: acpi wakeup code. + */ + + pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 32 * 1024 * 1024); + + pmap_kenter_pa(idt_vaddr, idt_paddr, VM_PROT_READ|VM_PROT_WRITE); + pmap_kenter_pa(idt_vaddr + PAGE_SIZE, idt_paddr + PAGE_SIZE, + VM_PROT_READ|VM_PROT_WRITE); + + pmap_kenter_pa(lo32_vaddr, lo32_paddr, VM_PROT_READ|VM_PROT_WRITE); + + idt = (struct gate_descriptor *)idt_vaddr; + gdtstore = (char *)(idt + NIDT); + ldtstore = gdtstore + DYNSEL_START; + + /* make gdt gates and memory segments */ + set_mem_segment(GDT_ADDR_MEM(gdtstore, GCODE_SEL), 0, 0xfffff, SDT_MEMERA, + SEL_KPL, 1, 0, 1); + + set_mem_segment(GDT_ADDR_MEM(gdtstore, GDATA_SEL), 0, 0xfffff, SDT_MEMRWA, + SEL_KPL, 1, 0, 1); + + set_sys_segment(GDT_ADDR_SYS(gdtstore, GLDT_SEL), ldtstore, LDT_SIZE - 1, + SDT_SYSLDT, SEL_KPL, 0); + + set_mem_segment(GDT_ADDR_MEM(gdtstore, GUCODE_SEL), 0, + x86_btop(VM_MAXUSER_ADDRESS) - 1, SDT_MEMERA, SEL_UPL, 1, 0, 1); + + set_mem_segment(GDT_ADDR_MEM(gdtstore, GUDATA_SEL), 0, + x86_btop(VM_MAXUSER_ADDRESS) - 1, SDT_MEMRWA, SEL_UPL, 1, 0, 1); + + /* make ldt gates and memory segments */ + setgate((struct gate_descriptor *)(ldtstore + LSYS5CALLS_SEL), + &IDTVEC(oosyscall), 0, SDT_SYS386CGT, SEL_UPL, + GSEL(GCODE_SEL, SEL_KPL)); + + *(struct mem_segment_descriptor *)(ldtstore + LUCODE_SEL) = + *GDT_ADDR_MEM(gdtstore, GUCODE_SEL); + *(struct mem_segment_descriptor *)(ldtstore + LUDATA_SEL) = + *GDT_ADDR_MEM(gdtstore, GUDATA_SEL); + + /* + * 32 bit GDT entries. + */ + + set_mem_segment(GDT_ADDR_MEM(gdtstore, GUCODE32_SEL), 0, + x86_btop(VM_MAXUSER_ADDRESS) - 1, SDT_MEMERA, SEL_UPL, 1, 1, 0); + + set_mem_segment(GDT_ADDR_MEM(gdtstore, GUDATA32_SEL), 0, + x86_btop(VM_MAXUSER_ADDRESS) - 1, SDT_MEMRWA, SEL_UPL, 1, 1, 0); + + /* + * 32 bit LDT entries. + */ + ldt_segp = (struct mem_segment_descriptor *)(ldtstore + LUCODE32_SEL); + set_mem_segment(ldt_segp, 0, x86_btop(VM_MAXUSER_ADDRESS32) - 1, + SDT_MEMERA, SEL_UPL, 1, 1, 0); + ldt_segp = (struct mem_segment_descriptor *)(ldtstore + LUDATA32_SEL); + set_mem_segment(ldt_segp, 0, x86_btop(VM_MAXUSER_ADDRESS32) - 1, + SDT_MEMRWA, SEL_UPL, 1, 1, 0); + + /* + * Other entries. + */ + memcpy((struct gate_descriptor *)(ldtstore + LSOL26CALLS_SEL), + (struct gate_descriptor *)(ldtstore + LSYS5CALLS_SEL), + sizeof (struct gate_descriptor)); + memcpy((struct gate_descriptor *)(ldtstore + LBSDICALLS_SEL), + (struct gate_descriptor *)(ldtstore + LSYS5CALLS_SEL), + sizeof (struct gate_descriptor)); + + /* exceptions */ + for (x = 0; x < 32; x++) { + ist = (x == 8 || x == 3) ? 1 : 0; + setgate(&idt[x], IDTVEC(exceptions)[x], ist, SDT_SYS386IGT, + (x == 3 || x == 4) ? SEL_UPL : SEL_KPL, + GSEL(GCODE_SEL, SEL_KPL)); + idt_allocmap[x] = 1; + } + + /* new-style interrupt gate for syscalls */ + setgate(&idt[128], &IDTVEC(osyscall), 0, SDT_SYS386IGT, SEL_UPL, + GSEL(GCODE_SEL, SEL_KPL)); + idt_allocmap[128] = 1; + + setregion(®ion, gdtstore, DYNSEL_START - 1); + lgdt(®ion); + + cpu_init_idt(); + +#ifdef DDB + { + extern caddr_t esym; + struct btinfo_symtab *symtab; + + symtab = lookup_bootinfo(BTINFO_SYMTAB); + if (symtab) { + ssym = (char *)((vaddr_t)symtab->ssym + KERNBASE); + esym = (caddr_t)((vaddr_t)symtab->esym + KERNBASE); + } + + db_machine_init(); + ddb_init(); + } + + if (boothowto & RB_KDB) + Debugger(); +#endif +#ifdef KGDB + kgdb_port_init(); + if (boothowto & RB_KDB) { + kgdb_debug_init = 1; + kgdb_connect(1); + } +#endif + + intr_default_setup(); + + softintr_init(); + splraise(IPL_IPI); + enable_intr(); + + /* Make sure maxproc is sane */ + if (maxproc > cpu_maxproc()) + maxproc = cpu_maxproc(); +} + +void * +lookup_bootinfo(type) + int type; +{ + struct btinfo_common *help; + int n = *(int*)bootinfo; + help = (struct btinfo_common *)(bootinfo + sizeof(int)); + while(n--) { + if(help->type == type) { +#if 0 + if (type == BTINFO_CONSOLE) { + struct btinfo_console *consinfo = (struct btinfo_console *)help; + snprintf(consinfo->devname, 16, "com"); + consinfo->speed = 9600; + consinfo->addr = 0x3f8; + } +#endif + return(help); + } + help = (struct btinfo_common *)((char*)help + help->len); + } + return(0); +} + +void +cpu_reset() +{ + + disable_intr(); + + /* + * The keyboard controller has 4 random output pins, one of which is + * connected to the RESET pin on the CPU in many PCs. We tell the + * keyboard controller to pulse this line a couple of times. + */ + outb(IO_KBD + KBCMDP, KBC_PULSE0); + delay(100000); + outb(IO_KBD + KBCMDP, KBC_PULSE0); + delay(100000); + + /* + * Try to cause a triple fault and watchdog reset by making the IDT + * invalid and causing a fault. + */ + memset((caddr_t)idt, 0, NIDT * sizeof(idt[0])); + __asm __volatile("divl %0,%1" : : "q" (0), "a" (0)); + +#if 0 + /* + * Try to cause a triple fault and watchdog reset by unmapping the + * entire address space and doing a TLB flush. + */ + memset((caddr_t)PTD, 0, PAGE_SIZE); + tlbflush(); +#endif + + for (;;); +} + +/* + * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers. + */ +int +cpu_dumpsize() +{ + int size; + + size = ALIGN(sizeof(kcore_seg_t)) + + ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t)); + if (roundup(size, dbtob(1)) != dbtob(1)) + return (-1); + + return (1); +} + +/* + * cpu_dump_mempagecnt: calculate the size of RAM (in pages) to be dumped. + */ +u_long +cpu_dump_mempagecnt() +{ + u_long i, n; + + n = 0; + for (i = 0; i < mem_cluster_cnt; i++) + n += atop(mem_clusters[i].size); + return (n); +} + +#if 0 +extern void i8254_microtime(struct timeval *tv); + +/* + * XXXXXXX + * the simulator's 8254 seems to travel backward in time sometimes? + * work around this with this hideous code. Unacceptable for + * real hardware, but this is just a patch to stop the weird + * effects. SMP unsafe, etc. + */ +void +microtime(struct timeval *tv) +{ + static struct timeval mtv; + + i8254_microtime(tv); + if (tv->tv_sec <= mtv.tv_sec && tv->tv_usec < mtv.tv_usec) { + mtv.tv_usec++; + if (mtv.tv_usec > 1000000) { + mtv.tv_sec++; + mtv.tv_usec = 0; + } + *tv = mtv; + } else + mtv = *tv; +} +#endif + +void +cpu_initclocks() +{ + (*initclock_func)(); +} + +#ifdef MULTIPROCESSOR +void +need_resched(struct cpu_info *ci) +{ + ci->ci_want_resched = 1; + if ((ci)->ci_curproc != NULL) + aston((ci)->ci_curproc); +} +#endif + +/* + * Allocate an IDT vector slot within the given range. + * XXX needs locking to avoid MP allocation races. + * XXXfvdl share idt code + */ + +int +idt_vec_alloc(low, high) + int low; + int high; +{ + int vec; + + simple_lock(&idt_lock); + for (vec = low; vec <= high; vec++) { + if (idt_allocmap[vec] == 0) { + idt_allocmap[vec] = 1; + simple_unlock(&idt_lock); + return vec; + } + } + simple_unlock(&idt_lock); + return 0; +} + +void +idt_vec_set(vec, function) + int vec; + void (*function)(void); +{ + /* + * Vector should be allocated, so no locking needed. + */ + KASSERT(idt_allocmap[vec] == 1); + setgate(&idt[vec], function, 0, SDT_SYS386IGT, SEL_KPL, + GSEL(GCODE_SEL, SEL_KPL)); +} + +void +idt_vec_free(vec) + int vec; +{ + simple_lock(&idt_lock); + unsetgate(&idt[vec]); + idt_allocmap[vec] = 0; + simple_unlock(&idt_lock); +} + +/* + * Number of processes is limited by number of available GDT slots. + */ +int +cpu_maxproc(void) +{ +#ifdef USER_LDT + return ((MAXGDTSIZ - DYNSEL_START) / 32); +#else + return (MAXGDTSIZ - DYNSEL_START) / 16; +#endif +} + +#ifdef DIAGNOSTIC +void +splassert_check(int wantipl, const char *func) +{ + int cpl = curcpu()->ci_ilevel; + + if (cpl < wantipl) { + splassert_fail(wantipl, cpl, func); + } +} +#endif + diff --git a/sys/arch/amd64/amd64/mainbus.c b/sys/arch/amd64/amd64/mainbus.c new file mode 100644 index 00000000000..e4c5e6d32fd --- /dev/null +++ b/sys/arch/amd64/amd64/mainbus.c @@ -0,0 +1,190 @@ +/* $OpenBSD: mainbus.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: mainbus.c,v 1.1 2003/04/26 18:39:29 fvdl Exp $ */ + +/* + * Copyright (c) 1996 Christopher G. Demetriou. 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 Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <dev/isa/isavar.h> +#include <dev/pci/pcivar.h> + +#include <dev/isa/isareg.h> + +#include "pci.h" +#include "isa.h" + +#include <machine/cpuvar.h> +#include <machine/i82093var.h> +#include <machine/mpbiosvar.h> + +/* + * XXXfvdl ACPI + */ + +int mainbus_match(struct device *, void *, void *); +void mainbus_attach(struct device *, struct device *, void *); + +struct cfattach mainbus_ca = { + sizeof(struct device), mainbus_match, mainbus_attach +}; + +struct cfdriver mainbus_cd = { + NULL, "mainbus", DV_DULL +}; + +int mainbus_print(void *, const char *); + +union mainbus_attach_args { + const char *mba_busname; /* first elem of all */ + struct pcibus_attach_args mba_pba; + struct isabus_attach_args mba_iba; + struct cpu_attach_args mba_caa; + struct apic_attach_args aaa_caa; +}; + +/* + * This is set when the ISA bus is attached. If it's not set by the + * time it's checked below, then mainbus attempts to attach an ISA. + */ +int isa_has_been_seen; +#if NISA > 0 +struct isabus_attach_args mba_iba = { + "isa", + X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM, + NULL, +}; +#endif + +#if defined(MPBIOS) || defined(MPACPI) +struct mp_bus *mp_busses; +int mp_nbus; +struct mp_intr_map *mp_intrs; +int mp_nintr; + +int mp_isa_bus = -1; +int mp_eisa_bus = -1; + +#ifdef MPVERBOSE +int mp_verbose = 1; +#else +int mp_verbose = 0; +#endif +#endif + + +/* + * Probe for the mainbus; always succeeds. + */ +int +mainbus_match(struct device *parent, void *match, void *aux) +{ + + return 1; +} + +/* + * Attach the mainbus. + */ +void +mainbus_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ +#if NPCI > 0 + union mainbus_attach_args mba; +#endif +#ifdef MPBIOS + int mpbios_present = 0; +#endif + + printf("\n"); + +#ifdef MPBIOS + mpbios_present = mpbios_probe(self); +#endif + +#if NPCI > 0 + pci_mode = pci_mode_detect(); +#endif + +#ifdef MPBIOS + if (mpbios_present) + mpbios_scan(self); + else +#endif + { + struct cpu_attach_args caa; + + memset(&caa, 0, sizeof(caa)); + caa.caa_name = "cpu"; + caa.cpu_number = 0; + caa.cpu_role = CPU_ROLE_SP; + caa.cpu_func = 0; + + config_found(self, &caa, mainbus_print); + } + +#if NPCI > 0 + if (pci_mode != 0) { + mba.mba_pba.pba_busname = "pci"; + mba.mba_pba.pba_iot = X86_BUS_SPACE_IO; + mba.mba_pba.pba_memt = X86_BUS_SPACE_MEM; + mba.mba_pba.pba_dmat = &pci_bus_dma_tag; + mba.mba_pba.pba_bus = 0; + mba.mba_pba.pba_pc = NULL; + config_found(self, &mba.mba_pba, mainbus_print); + } +#endif + +#if NISA > 0 + if (isa_has_been_seen == 0) + config_found(self, &mba_iba, mainbus_print); +#endif + +} + +int +mainbus_print(aux, pnp) + void *aux; + const char *pnp; +{ + union mainbus_attach_args *mba = aux; + + if (pnp) + printf("%s at %s", mba->mba_busname, pnp); + if (strcmp(mba->mba_busname, "pci") == 0) + printf(" bus %d", mba->mba_pba.pba_bus); + return (UNCONF); +} diff --git a/sys/arch/amd64/amd64/mem.c b/sys/arch/amd64/amd64/mem.c new file mode 100644 index 00000000000..7bb187717c3 --- /dev/null +++ b/sys/arch/amd64/amd64/mem.c @@ -0,0 +1,266 @@ +/* $OpenBSD: mem.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * 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. + * + * @(#)mem.c 8.3 (Berkeley) 1/12/94 + */ + +/* + * Memory special file + */ + +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/systm.h> +#include <sys/uio.h> +#include <sys/ioccom.h> +#include <sys/malloc.h> +#include <sys/memrange.h> +#include <sys/proc.h> +#include <sys/fcntl.h> + +#include <machine/cpu.h> +#include <machine/conf.h> + +#include <uvm/uvm_extern.h> + +extern char *vmmap; /* poor name! */ +caddr_t zeropage; + +/* open counter for aperture */ +#ifdef APERTURE +static int ap_open_count = 0; +extern int allowaperture; + +#define VGA_START 0xA0000 +#define BIOS_END 0xFFFFF +#endif + +/*ARGSUSED*/ +int +mmopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + + switch (minor(dev)) { + case 0: + case 1: + case 2: + case 12: + break; +#ifdef APERTURE + case 4: + if (suser(p, 0) != 0 || !allowaperture) + return (EPERM); + + /* authorize only one simultaneous open() */ + if (ap_open_count > 0) + return(EPERM); + ap_open_count++; + break; +#endif + default: + return (ENXIO); + } + return (0); +} + +/*ARGSUSED*/ +int +mmclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ +#ifdef APERTURE + if (minor(dev) == 4) + ap_open_count--; +#endif + return (0); +} + +/*ARGSUSED*/ +int +mmrw(dev_t dev, struct uio *uio, int flags) +{ + vaddr_t o, v; + int c; + struct iovec *iov; + int error = 0; + static int physlock; + + if (minor(dev) == 0) { + /* lock against other uses of shared vmmap */ + while (physlock > 0) { + physlock++; + error = tsleep((caddr_t)&physlock, PZERO | PCATCH, + "mmrw", 0); + if (error) + return (error); + } + physlock = 1; + } + while (uio->uio_resid > 0 && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("mmrw"); + continue; + } + switch (minor(dev)) { + +/* minor device 0 is physical memory */ + case 0: + v = uio->uio_offset; + pmap_enter(pmap_kernel(), (vaddr_t)vmmap, + trunc_page(v), uio->uio_rw == UIO_READ ? + VM_PROT_READ : VM_PROT_WRITE, PMAP_WIRED); + pmap_update(pmap_kernel()); + o = uio->uio_offset & PGOFSET; + c = min(uio->uio_resid, (int)(NBPG - o)); + error = uiomove((caddr_t)vmmap + o, c, uio); + pmap_remove(pmap_kernel(), (vaddr_t)vmmap, + (vaddr_t)vmmap + NBPG); + pmap_update(pmap_kernel()); + continue; + +/* minor device 1 is kernel memory */ + case 1: + v = uio->uio_offset; + c = min(iov->iov_len, MAXPHYS); + if (!uvm_kernacc((caddr_t)v, c, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) + return (EFAULT); + error = uiomove((caddr_t)v, c, uio); + continue; + +/* minor device 2 is EOF/RATHOLE */ + case 2: + if (uio->uio_rw == UIO_WRITE) + uio->uio_resid = 0; + return (0); + +/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */ + case 12: + if (uio->uio_rw == UIO_WRITE) { + c = iov->iov_len; + break; + } + if (zeropage == NULL) { + zeropage = (caddr_t) + malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + bzero(zeropage, PAGE_SIZE); + } + c = min(iov->iov_len, PAGE_SIZE); + error = uiomove(zeropage, c, uio); + continue; + + default: + return (ENXIO); + } + iov->iov_base += c; + iov->iov_len -= c; + uio->uio_offset += c; + uio->uio_resid -= c; + } + if (minor(dev) == 0) { + if (physlock > 1) + wakeup((caddr_t)&physlock); + physlock = 0; + } + return (error); +} + +paddr_t +mmmmap(dev, off, prot) + dev_t dev; + off_t off; + int prot; +{ + struct proc *p = curproc; /* XXX */ + + switch (minor(dev)) { +/* minor device 0 is physical memory */ + case 0: + if ((paddr_t)off > (paddr_t)ctob(physmem) && suser(p, 0) != 0) + return -1; + return btop((paddr_t)off); + +#ifdef APERTURE +/* minor device 4 is aperture driver */ + case 4: + switch (allowaperture) { + case 1: + /* Allow mapping of the VGA framebuffer & BIOS only */ + if ((off >= VGA_START && off <= BIOS_END) || + (unsigned)off > (unsigned)ctob(physmem)) + return btop((paddr_t)off); + else + return -1; + case 2: + /* Allow mapping of the whole 1st megabyte + for x86emu */ + if (off <= BIOS_END || + (unsigned)off > (unsigned)ctob(physmem)) + return btop((paddr_t)off); + else + return -1; + default: + return -1; + } + +#endif + default: + return -1; + } +} + +int +mmioctl(dev, cmd, data, flags, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + return (ENODEV); +} + diff --git a/sys/arch/amd64/amd64/microtime.S b/sys/arch/amd64/amd64/microtime.S new file mode 100644 index 00000000000..2e64a7e585a --- /dev/null +++ b/sys/arch/amd64/amd64/microtime.S @@ -0,0 +1,111 @@ +/* $OpenBSD: microtime.S,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: microtime.S,v 1.1 2003/04/26 18:39:30 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + */ + +#include <machine/asm.h> +#include <dev/isa/isareg.h> +#include <dev/ic/i8253reg.h> + +#include "assym.h" + +#define IRQ_BIT(irq_num) (1 << ((irq_num) & 7)) +#define IRQ_BYTE(irq_num) ((irq_num) >> 3) + +ENTRY(i8254_microtime) + # clear registers and do whatever we can up front + xorl %edx,%edx + movl $(TIMER_SEL0|TIMER_LATCH),%eax + + cli # disable interrupts + + # select timer 0 and latch its counter + outb %al,$IO_TIMER1+TIMER_MODE + inb $IO_ICU1,%al # as close to timer latch as possible + movb %al,%ch # %ch is current ICU mask + + # Read counter value into [%al %dl], LSB first + inb $IO_TIMER1+TIMER_CNTR0,%al + movb %al,%dl # %dl has LSB + inb $IO_TIMER1+TIMER_CNTR0,%al # %al has MSB + + # save state of IIR in ICU, and of ipending, for later perusal + movb CPUVAR(IPENDING) + IRQ_BYTE(0),%cl + + # save the current value of _time + movq _C_LABEL(time)(%rip),%r8 # get time.tv_sec + movq (_C_LABEL(time)+8)(%rip),%r9 # and time.tv_usec + + sti # enable interrupts, we're done + + # At this point we've collected all the state we need to + # compute the time. First figure out if we've got a pending + # interrupt. If the IRQ0 bit is set in ipending we've taken + # a clock interrupt without incrementing time, so we bump + # time.tv_usec by a tick. Otherwise if the ICU shows a pending + # interrupt for IRQ0 we (or the caller) may have blocked an interrupt + # with the cli. If the counter is not a very small value (3 as + # a heuristic), i.e. in pre-interrupt state, we add a tick to + # time.tv_usec + + testb $IRQ_BIT(0),%cl # pending interrupt? + jnz 1f # yes, increment count + + testb $IRQ_BIT(0),%ch # hardware interrupt pending? + jz 2f # no, continue + testb %al,%al # MSB zero? + jnz 1f # no, add a tick + cmpb $3,%dl # is this small number? + jbe 2f # yes, continue +1: addq _C_LABEL(isa_timer_tick)(%rip),%r9 # add a tick + + # We've corrected for pending interrupts. Now do a table lookup + # based on each of the high and low order counter bytes to increment + # time.tv_usec +2: leaq _C_LABEL(isa_timer_msb_table)(%rip),%rsi + movw (%rsi,%rax,2),%ax + subw (%rsi,%rdx,2),%ax + addq %rax,%r9 # add msb increment + + # Normalize the struct timeval. We know the previous increments + # will be less than a second, so we'll only need to adjust accordingly + cmpq $1000000,%r9 # carry in timeval? + jb 3f + subq $1000000,%r9 # adjust usec + incq %r8 # bump sec + +3: movq %r8,(%rdi) # tvp->tv_sec = sec + movq %r9,8(%rdi) # tvp->tv_usec = usec + + ret diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c new file mode 100644 index 00000000000..09ac35327c5 --- /dev/null +++ b/sys/arch/amd64/amd64/pmap.c @@ -0,0 +1,3835 @@ +/* $OpenBSD: pmap.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pmap.c,v 1.3 2003/05/08 18:13:13 thorpej Exp $ */ + +/* + * + * Copyright (c) 1997 Charles D. Cranor and Washington University. + * 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 Charles D. Cranor and + * Washington University. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 2001 (c) Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +/* + * This is the i386 pmap modified and generalized to support x86-64 + * as well. The idea is to hide the upper N levels of the page tables + * inside pmap_get_ptp, pmap_free_ptp and pmap_growkernel. The rest + * is mostly untouched, except that it uses some more generalized + * macros and interfaces. + * + * This pmap has been tested on the i386 as well, and it can be easily + * adapted to PAE. + * + * fvdl@wasabisystems.com 18-Jun-2001 + */ + +/* + * pmap.c: i386 pmap module rewrite + * Chuck Cranor <chuck@ccrc.wustl.edu> + * 11-Aug-97 + * + * history of this pmap module: in addition to my own input, i used + * the following references for this rewrite of the i386 pmap: + * + * [1] the NetBSD i386 pmap. this pmap appears to be based on the + * BSD hp300 pmap done by Mike Hibler at University of Utah. + * it was then ported to the i386 by William Jolitz of UUNET + * Technologies, Inc. Then Charles M. Hannum of the NetBSD + * project fixed some bugs and provided some speed ups. + * + * [2] the FreeBSD i386 pmap. this pmap seems to be the + * Hibler/Jolitz pmap, as modified for FreeBSD by John S. Dyson + * and David Greenman. + * + * [3] the Mach pmap. this pmap, from CMU, seems to have migrated + * between several processors. the VAX version was done by + * Avadis Tevanian, Jr., and Michael Wayne Young. the i386 + * version was done by Lance Berc, Mike Kupfer, Bob Baron, + * David Golub, and Richard Draves. the alpha version was + * done by Alessandro Forin (CMU/Mach) and Chris Demetriou + * (NetBSD/alpha). + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/pool.h> +#include <sys/user.h> +#include <sys/kernel.h> + +#include <uvm/uvm.h> + +#include <machine/atomic.h> +#include <machine/cpu.h> +#include <machine/specialreg.h> +#include <machine/gdt.h> + +#include <dev/isa/isareg.h> +#include <machine/isa_machdep.h> + +/* + * general info: + * + * - for an explanation of how the i386 MMU hardware works see + * the comments in <machine/pte.h>. + * + * - for an explanation of the general memory structure used by + * this pmap (including the recursive mapping), see the comments + * in <machine/pmap.h>. + * + * this file contains the code for the "pmap module." the module's + * job is to manage the hardware's virtual to physical address mappings. + * note that there are two levels of mapping in the VM system: + * + * [1] the upper layer of the VM system uses vm_map's and vm_map_entry's + * to map ranges of virtual address space to objects/files. for + * example, the vm_map may say: "map VA 0x1000 to 0x22000 read-only + * to the file /bin/ls starting at offset zero." note that + * the upper layer mapping is not concerned with how individual + * vm_pages are mapped. + * + * [2] the lower layer of the VM system (the pmap) maintains the mappings + * from virtual addresses. it is concerned with which vm_page is + * mapped where. for example, when you run /bin/ls and start + * at page 0x1000 the fault routine may lookup the correct page + * of the /bin/ls file and then ask the pmap layer to establish + * a mapping for it. + * + * note that information in the lower layer of the VM system can be + * thrown away since it can easily be reconstructed from the info + * in the upper layer. + * + * data structures we use include: + * + * - struct pmap: describes the address space of one thread + * - struct pv_entry: describes one <PMAP,VA> mapping of a PA + * - struct pv_head: there is one pv_head per managed page of + * physical memory. the pv_head points to a list of pv_entry + * structures which describe all the <PMAP,VA> pairs that this + * page is mapped in. this is critical for page based operations + * such as pmap_page_protect() [change protection on _all_ mappings + * of a page] + * - pv_page/pv_page_info: pv_entry's are allocated out of pv_page's. + * if we run out of pv_entry's we allocate a new pv_page and free + * its pv_entrys. + * - pmap_remove_record: a list of virtual addresses whose mappings + * have been changed. used for TLB flushing. + */ + +/* + * memory allocation + * + * - there are three data structures that we must dynamically allocate: + * + * [A] new process' page directory page (PDP) + * - plan 1: done at pmap_create() we use + * uvm_km_alloc(kernel_map, PAGE_SIZE) [fka kmem_alloc] to do this + * allocation. + * + * if we are low in free physical memory then we sleep in + * uvm_km_alloc -- in this case this is ok since we are creating + * a new pmap and should not be holding any locks. + * + * if the kernel is totally out of virtual space + * (i.e. uvm_km_alloc returns NULL), then we panic. + * + * XXX: the fork code currently has no way to return an "out of + * memory, try again" error code since uvm_fork [fka vm_fork] + * is a void function. + * + * [B] new page tables pages (PTP) + * call uvm_pagealloc() + * => success: zero page, add to pm_pdir + * => failure: we are out of free vm_pages, let pmap_enter() + * tell UVM about it. + * + * note: for kernel PTPs, we start with NKPTP of them. as we map + * kernel memory (at uvm_map time) we check to see if we've grown + * the kernel pmap. if so, we call the optional function + * pmap_growkernel() to grow the kernel PTPs in advance. + * + * [C] pv_entry structures + * - plan 1: try to allocate one off the free list + * => success: done! + * => failure: no more free pv_entrys on the list + * - plan 2: try to allocate a new pv_page to add a chunk of + * pv_entrys to the free list + * [a] obtain a free, unmapped, VA in kmem_map. either + * we have one saved from a previous call, or we allocate + * one now using a "vm_map_lock_try" in uvm_map + * => success: we have an unmapped VA, continue to [b] + * => failure: unable to lock kmem_map or out of VA in it. + * move on to plan 3. + * [b] allocate a page for the VA + * => success: map it in, free the pv_entry's, DONE! + * => failure: no free vm_pages, etc. + * save VA for later call to [a], go to plan 3. + * If we fail, we simply let pmap_enter() tell UVM about it. + */ + +/* + * locking + * + * we have the following locks that we must contend with: + * + * "normal" locks: + * + * - pmap_main_lock + * this lock is used to prevent deadlock and/or provide mutex + * access to the pmap system. most operations lock the pmap + * structure first, then they lock the pv_lists (if needed). + * however, some operations such as pmap_page_protect lock + * the pv_lists and then lock pmaps. in order to prevent a + * cycle, we require a mutex lock when locking the pv_lists + * first. thus, the "pmap = >pv_list" lockers must gain a + * read-lock on pmap_main_lock before locking the pmap. and + * the "pv_list => pmap" lockers must gain a write-lock on + * pmap_main_lock before locking. since only one thread + * can write-lock a lock at a time, this provides mutex. + * + * "simple" locks: + * + * - pmap lock (per pmap, part of uvm_object) + * this lock protects the fields in the pmap structure including + * the non-kernel PDEs in the PDP, and the PTEs. it also locks + * in the alternate PTE space (since that is determined by the + * entry in the PDP). + * + * - pvh_lock (per pv_head) + * this lock protects the pv_entry list which is chained off the + * pv_head structure for a specific managed PA. it is locked + * when traversing the list (e.g. adding/removing mappings, + * syncing R/M bits, etc.) + * + * - pvalloc_lock + * this lock protects the data structures which are used to manage + * the free list of pv_entry structures. + * + * - pmaps_lock + * this lock protects the list of active pmaps (headed by "pmaps"). + * we lock it when adding or removing pmaps from this list. + * + * XXX: would be nice to have per-CPU VAs for the above 4 + */ + +/* + * locking data structures + */ + +vaddr_t ptp_masks[] = PTP_MASK_INITIALIZER; +int ptp_shifts[] = PTP_SHIFT_INITIALIZER; +long nkptp[] = NKPTP_INITIALIZER; +long nkptpmax[] = NKPTPMAX_INITIALIZER; +long nbpd[] = NBPD_INITIALIZER; +pd_entry_t *normal_pdes[] = PDES_INITIALIZER; +pd_entry_t *alternate_pdes[] = APDES_INITIALIZER; + +/* int nkpde = NKPTP; */ + +struct simplelock pvalloc_lock; +struct simplelock pmaps_lock; + +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) +struct lock pmap_main_lock; +#define PMAP_MAP_TO_HEAD_LOCK() \ + (void) spinlockmgr(&pmap_main_lock, LK_SHARED, NULL) +#define PMAP_MAP_TO_HEAD_UNLOCK() \ + (void) spinlockmgr(&pmap_main_lock, LK_RELEASE, NULL) + +#define PMAP_HEAD_TO_MAP_LOCK() \ + (void) spinlockmgr(&pmap_main_lock, LK_EXCLUSIVE, NULL) +#define PMAP_HEAD_TO_MAP_UNLOCK() \ + (void) spinlockmgr(&pmap_main_lock, LK_RELEASE, NULL) + +#else + +#define PMAP_MAP_TO_HEAD_LOCK() /* null */ +#define PMAP_MAP_TO_HEAD_UNLOCK() /* null */ + +#define PMAP_HEAD_TO_MAP_LOCK() /* null */ +#define PMAP_HEAD_TO_MAP_UNLOCK() /* null */ + +#endif + +#define COUNT(x) /* nothing */ + +/* + * TLB Shootdown: + * + * When a mapping is changed in a pmap, the TLB entry corresponding to + * the virtual address must be invalidated on all processors. In order + * to accomplish this on systems with multiple processors, messages are + * sent from the processor which performs the mapping change to all + * processors on which the pmap is active. For other processors, the + * ASN generation numbers for that processor is invalidated, so that + * the next time the pmap is activated on that processor, a new ASN + * will be allocated (which implicitly invalidates all TLB entries). + * + * Shootdown job queue entries are allocated using a simple special- + * purpose allocator for speed. + */ +struct pmap_tlb_shootdown_job { + TAILQ_ENTRY(pmap_tlb_shootdown_job) pj_list; + vaddr_t pj_va; /* virtual address */ + pmap_t pj_pmap; /* the pmap which maps the address */ + pt_entry_t pj_pte; /* the PTE bits */ + struct pmap_tlb_shootdown_job *pj_nextfree; +}; + +#define PMAP_TLB_SHOOTDOWN_JOB_ALIGN 64 +union pmap_tlb_shootdown_job_al { + struct pmap_tlb_shootdown_job pja_job; + char pja_align[PMAP_TLB_SHOOTDOWN_JOB_ALIGN]; +}; + +struct pmap_tlb_shootdown_q { + TAILQ_HEAD(, pmap_tlb_shootdown_job) pq_head; + int pq_pte; /* aggregate PTE bits */ + int pq_count; /* number of pending requests */ + struct simplelock pq_slock; /* spin lock on queue */ + int pq_flushg; /* pending flush global */ + int pq_flushu; /* pending flush user */ +} pmap_tlb_shootdown_q[X86_MAXPROCS]; + +#define PMAP_TLB_MAXJOBS 16 + +void pmap_tlb_shootdown_q_drain(struct pmap_tlb_shootdown_q *); +struct pmap_tlb_shootdown_job *pmap_tlb_shootdown_job_get + (struct pmap_tlb_shootdown_q *); +void pmap_tlb_shootdown_job_put(struct pmap_tlb_shootdown_q *, + struct pmap_tlb_shootdown_job *); + +struct simplelock pmap_tlb_shootdown_job_lock; +union pmap_tlb_shootdown_job_al *pj_page, *pj_free; + +/* + * global data structures + */ + +struct pmap kernel_pmap_store; /* the kernel's pmap (proc0) */ + +/* + * pmap_pg_g: if our processor supports PG_G in the PTE then we + * set pmap_pg_g to PG_G (otherwise it is zero). + */ + +int pmap_pg_g = 0; + +#ifdef LARGEPAGES +/* + * pmap_largepages: if our processor supports PG_PS and we are + * using it, this is set to TRUE. + */ + +int pmap_largepages; +#endif + +/* + * i386 physical memory comes in a big contig chunk with a small + * hole toward the front of it... the following 4 paddr_t's + * (shared with machdep.c) describe the physical address space + * of this machine. + */ +paddr_t avail_start; /* PA of first available physical page */ +paddr_t avail_end; /* PA of last available physical page */ + +/* + * other data structures + */ + +pt_entry_t protection_codes[8]; /* maps MI prot to i386 prot code */ +boolean_t pmap_initialized = FALSE; /* pmap_init done yet? */ + +/* + * pv_page management structures: locked by pvalloc_lock + */ + +TAILQ_HEAD(pv_pagelist, pv_page); +struct pv_pagelist pv_freepages; /* list of pv_pages with free entrys */ +struct pv_pagelist pv_unusedpgs; /* list of unused pv_pages */ +unsigned int pv_nfpvents; /* # of free pv entries */ +struct pv_page *pv_initpage; /* bootstrap page from kernel_map */ +vaddr_t pv_cachedva; /* cached VA for later use */ + +#define PVE_LOWAT (PVE_PER_PVPAGE / 2) /* free pv_entry low water mark */ +#define PVE_HIWAT (PVE_LOWAT + (PVE_PER_PVPAGE * 2)) + /* high water mark */ + +/* + * linked list of all non-kernel pmaps + */ + +struct pmap_head pmaps; + +/* + * pool that pmap structures are allocated from + */ + +struct pool pmap_pmap_pool; + + +/* + * MULTIPROCESSOR: special VA's/ PTE's are actually allocated inside a + * X86_MAXPROCS*NPTECL array of PTE's, to avoid cache line thrashing + * due to false sharing. + */ + +#ifdef MULTIPROCESSOR +#define PTESLEW(pte, id) ((pte)+(id)*NPTECL) +#define VASLEW(va,id) ((va)+(id)*NPTECL*PAGE_SIZE) +#else +#define PTESLEW(pte, id) (pte) +#define VASLEW(va,id) (va) +#endif + +/* + * special VAs and the PTEs that map them + */ +pt_entry_t *csrc_pte, *cdst_pte, *zero_pte, *ptp_pte, *early_zero_pte; +caddr_t csrcp, cdstp, zerop, ptpp, early_zerop; + +/* + * pool and cache that PDPs are allocated from + */ + +struct pool pmap_pdp_pool; +struct pool_cache pmap_pdp_cache; +u_int pmap_pdp_cache_generation; + +int pmap_pdp_ctor(void *, void *, int); + +caddr_t vmmap; /* XXX: used by mem.c... it should really uvm_map_reserve it */ + +extern vaddr_t msgbuf_vaddr; +extern paddr_t msgbuf_paddr; + +extern vaddr_t idt_vaddr; /* we allocate IDT early */ +extern paddr_t idt_paddr; + +#ifdef _LP64 +extern vaddr_t lo32_vaddr; +extern vaddr_t lo32_paddr; +#endif + +vaddr_t virtual_avail; +extern int end; + +#if defined(I586_CPU) +/* stuff to fix the pentium f00f bug */ +extern vaddr_t pentium_idt_vaddr; +#endif + +/* + * local prototypes + */ + +static struct pv_entry *pmap_add_pvpage(struct pv_page *, boolean_t); +static struct pv_entry *pmap_alloc_pv(struct pmap *, int); /* see codes below */ +#define ALLOCPV_NEED 0 /* need PV now */ +#define ALLOCPV_TRY 1 /* just try to allocate, don't steal */ +#define ALLOCPV_NONEED 2 /* don't need PV, just growing cache */ +struct pv_entry *pmap_alloc_pvpage(struct pmap *, int); +static void pmap_enter_pv(struct pv_head *, + struct pv_entry *, struct pmap *, vaddr_t, struct vm_page *); +static void pmap_free_pv(struct pmap *, struct pv_entry *); +static void pmap_free_pvs(struct pmap *, struct pv_entry *); +static void pmap_free_pv_doit(struct pv_entry *); +void pmap_free_pvpage(void); +struct vm_page *pmap_get_ptp(struct pmap *, vaddr_t, pd_entry_t **); +static struct vm_page *pmap_find_ptp(struct pmap *, vaddr_t, paddr_t, int); +void pmap_free_ptp(struct pmap *, struct vm_page *, + vaddr_t, pt_entry_t *, pd_entry_t **, int32_t *); +static void pmap_freepage(struct pmap *, struct vm_page *, int); +static boolean_t pmap_is_curpmap(struct pmap *); +static boolean_t pmap_is_active(struct pmap *, int); +static void pmap_map_ptes(struct pmap *, pt_entry_t **, pd_entry_t ***); +static struct pv_entry *pmap_remove_pv(struct pv_head *, struct pmap *, vaddr_t); +void pmap_do_remove(struct pmap *, vaddr_t, vaddr_t, int); +boolean_t pmap_remove_pte(struct pmap *, struct vm_page *, pt_entry_t *, + vaddr_t, int32_t *, int); +void pmap_remove_ptes(struct pmap *, struct vm_page *, vaddr_t, + vaddr_t, vaddr_t, int32_t *, int); +#define PMAP_REMOVE_ALL 0 /* remove all mappings */ +#define PMAP_REMOVE_SKIPWIRED 1 /* skip wired mappings */ + +static vaddr_t pmap_tmpmap_pa(paddr_t); +static pt_entry_t *pmap_tmpmap_pvepte(struct pv_entry *); +static void pmap_tmpunmap_pa(void); +static void pmap_tmpunmap_pvepte(struct pv_entry *); +static void pmap_unmap_ptes(struct pmap *); +boolean_t pmap_get_physpage(vaddr_t, int, paddr_t *); +boolean_t pmap_pdes_valid(vaddr_t, pd_entry_t **, pd_entry_t *); +void pmap_alloc_level(pd_entry_t **, vaddr_t, int, long *); + +/* + * p m a p i n l i n e h e l p e r f u n c t i o n s + */ + +/* + * pmap_is_curpmap: is this pmap the one currently loaded [in %cr3]? + * of course the kernel is always loaded + */ + +__inline static boolean_t +pmap_is_curpmap(pmap) + struct pmap *pmap; +{ + return((pmap == pmap_kernel()) || + (pmap->pm_pdirpa == (paddr_t) rcr3())); +} + +/* + * pmap_is_active: is this pmap loaded into the specified processor's %cr3? + */ + +__inline static boolean_t +pmap_is_active(pmap, cpu_id) + struct pmap *pmap; + int cpu_id; +{ + + return (pmap == pmap_kernel() || + (pmap->pm_cpus & (1U << cpu_id)) != 0); +} + +/* + * pmap_tmpmap_pa: map a page in for tmp usage + */ + +__inline static vaddr_t +pmap_tmpmap_pa(pa) + paddr_t pa; +{ +#ifdef MULTIPROCESSOR + int id = cpu_number(); +#endif + pt_entry_t *ptpte = PTESLEW(ptp_pte, id); + caddr_t ptpva = VASLEW(ptpp, id); +#if defined(DIAGNOSTIC) + if (*ptpte) + panic("pmap_tmpmap_pa: ptp_pte in use?"); +#endif + *ptpte = PG_V | PG_RW | pa; /* always a new mapping */ + return((vaddr_t)ptpva); +} + +/* + * pmap_tmpunmap_pa: unmap a tmp use page (undoes pmap_tmpmap_pa) + */ + +__inline static void +pmap_tmpunmap_pa() +{ +#ifdef MULTIPROCESSOR + int id = cpu_number(); +#endif + pt_entry_t *ptpte = PTESLEW(ptp_pte, id); + caddr_t ptpva = VASLEW(ptpp, id); +#if defined(DIAGNOSTIC) + if (!pmap_valid_entry(*ptp_pte)) + panic("pmap_tmpunmap_pa: our pte invalid?"); +#endif + *ptpte = 0; /* zap! */ + pmap_update_pg((vaddr_t)ptpva); +#ifdef MULTIPROCESSOR + /* + * No need for tlb shootdown here, since ptp_pte is per-CPU. + */ +#endif +} + +/* + * pmap_tmpmap_pvepte: get a quick mapping of a PTE for a pv_entry + * + * => do NOT use this on kernel mappings [why? because pv_ptp may be NULL] + */ + +__inline static pt_entry_t * +pmap_tmpmap_pvepte(pve) + struct pv_entry *pve; +{ +#ifdef DIAGNOSTIC + if (pve->pv_pmap == pmap_kernel()) + panic("pmap_tmpmap_pvepte: attempt to map kernel"); +#endif + + /* is it current pmap? use direct mapping... */ + if (pmap_is_curpmap(pve->pv_pmap)) + return(vtopte(pve->pv_va)); + + return(((pt_entry_t *)pmap_tmpmap_pa(VM_PAGE_TO_PHYS(pve->pv_ptp))) + + ptei((unsigned long)pve->pv_va)); +} + +/* + * pmap_tmpunmap_pvepte: release a mapping obtained with pmap_tmpmap_pvepte + */ + +__inline static void +pmap_tmpunmap_pvepte(pve) + struct pv_entry *pve; +{ + /* was it current pmap? if so, return */ + if (pmap_is_curpmap(pve->pv_pmap)) + return; + + pmap_tmpunmap_pa(); +} + +__inline static void +pmap_apte_flush(struct pmap *pmap) +{ +#if defined(MULTIPROCESSOR) + struct pmap_tlb_shootdown_q *pq; + struct cpu_info *ci, *self = curcpu(); + CPU_INFO_ITERATOR cii; + int s; +#endif + + tlbflush(); /* flush TLB on current processor */ +#if defined(MULTIPROCESSOR) + /* + * Flush the APTE mapping from all other CPUs that + * are using the pmap we are using (who's APTE space + * is the one we've just modified). + * + * XXXthorpej -- find a way to defer the IPI. + */ + for (CPU_INFO_FOREACH(cii, ci)) { + if (ci == self) + continue; + if (pmap_is_active(pmap, ci->ci_cpuid)) { + pq = &pmap_tlb_shootdown_q[ci->ci_cpuid]; + s = splipi(); +#ifdef MULTIPROCESSOR + __cpu_simple_lock(&pq->pq_slock); +#endif + pq->pq_flushu++; +#ifdef MULTIPROCESSOR + __cpu_simple_unlock(&pq->pq_slock); +#endif + splx(s); + x86_send_ipi(ci, X86_IPI_TLB); + } + } +#endif +} + +/* + * pmap_map_ptes: map a pmap's PTEs into KVM and lock them in + * + * => we lock enough pmaps to keep things locked in + * => must be undone with pmap_unmap_ptes before returning + */ + +__inline static void +pmap_map_ptes(pmap, ptepp, pdeppp) + struct pmap *pmap; + pt_entry_t **ptepp; + pd_entry_t ***pdeppp; +{ + pd_entry_t opde, npde; + + /* the kernel's pmap is always accessible */ + if (pmap == pmap_kernel()) { + *ptepp = PTE_BASE; + *pdeppp = normal_pdes; + return; + } + + /* if curpmap then we are always mapped */ + if (pmap_is_curpmap(pmap)) { + simple_lock(&pmap->pm_lock); + *ptepp = PTE_BASE; + *pdeppp = normal_pdes; + return; + } + + /* need to lock both curpmap and pmap: use ordered locking */ + if ((unsigned long) pmap < (unsigned long) curpcb->pcb_pmap) { + simple_lock(&pmap->pm_lock); + simple_lock(&curpcb->pcb_pmap->pm_lock); + } else { + simple_lock(&curpcb->pcb_pmap->pm_lock); + simple_lock(&pmap->pm_lock); + } + + /* need to load a new alternate pt space into curpmap? */ + opde = *APDP_PDE; + if (!pmap_valid_entry(opde) || (opde & PG_FRAME) != pmap->pm_pdirpa) { + npde = (pd_entry_t) (pmap->pm_pdirpa | PG_RW | PG_V); + *APDP_PDE = npde; + if (pmap_valid_entry(opde)) + pmap_apte_flush(curpcb->pcb_pmap); + } + *ptepp = APTE_BASE; + *pdeppp = alternate_pdes; +} + +/* + * pmap_unmap_ptes: unlock the PTE mapping of "pmap" + */ + +__inline static void +pmap_unmap_ptes(pmap) + struct pmap *pmap; +{ + if (pmap == pmap_kernel()) { + return; + } + if (pmap_is_curpmap(pmap)) { + simple_unlock(&pmap->pm_lock); + } else { +#if defined(MULTIPROCESSOR) + *APDP_PDE = 0; + pmap_apte_flush(curpcb->pcb_pmap); +#endif + COUNT(apdp_pde_unmap); + simple_unlock(&pmap->pm_lock); + simple_unlock(&curpcb->pcb_pmap->pm_lock); + } +} + +/* + * p m a p k e n t e r f u n c t i o n s + * + * functions to quickly enter/remove pages from the kernel address + * space. pmap_kremove is exported to MI kernel. we make use of + * the recursive PTE mappings. + */ + +/* + * pmap_kenter_pa: enter a kernel mapping without R/M (pv_entry) tracking + * + * => no need to lock anything, assume va is already allocated + * => should be faster than normal pmap enter function + */ + +void +pmap_kenter_pa(va, pa, prot) + vaddr_t va; + paddr_t pa; + vm_prot_t prot; +{ + pt_entry_t *pte, opte, npte; + + if (va < VM_MIN_KERNEL_ADDRESS) + pte = vtopte(va); + else + pte = kvtopte(va); + + npte = pa | ((prot & VM_PROT_WRITE) ? PG_RW : PG_RO) | + PG_V | pmap_pg_g; + opte = pmap_pte_set(pte, npte); /* zap! */ +#ifdef LARGEPAGES + /* XXX For now... */ + if (opte & PG_PS) + panic("pmap_kenter_pa: PG_PS"); +#endif + if (pmap_valid_entry(opte)) { +#if defined(MULTIPROCESSOR) + int32_t cpumask = 0; + + pmap_tlb_shootdown(pmap_kernel(), va, opte, &cpumask); + pmap_tlb_shootnow(cpumask); +#else + /* Don't bother deferring in the single CPU case. */ + pmap_update_pg(va); +#endif + } +} + +/* + * pmap_kremove: remove a kernel mapping(s) without R/M (pv_entry) tracking + * + * => no need to lock anything + * => caller must dispose of any vm_page mapped in the va range + * => note: not an inline function + * => we assume the va is page aligned and the len is a multiple of PAGE_SIZE + * => we assume kernel only unmaps valid addresses and thus don't bother + * checking the valid bit before doing TLB flushing + */ + +void +pmap_kremove(va, len) + vaddr_t va; + vsize_t len; +{ + pt_entry_t *pte, opte; + int32_t cpumask = 0; + + len >>= PAGE_SHIFT; + for ( /* null */ ; len ; len--, va += PAGE_SIZE) { + if (va < VM_MIN_KERNEL_ADDRESS) + pte = vtopte(va); + else + pte = kvtopte(va); + opte = pmap_pte_set(pte, 0); /* zap! */ +#ifdef LARGEPAGES + /* XXX For now... */ + if (opte & PG_PS) + panic("pmap_kremove: PG_PS"); +#endif +#ifdef DIAGNOSTIC + if (opte & PG_PVLIST) + panic("pmap_kremove: PG_PVLIST mapping for 0x%lx", + va); +#endif + pmap_tlb_shootdown(pmap_kernel(), va, opte, &cpumask); + } + pmap_tlb_shootnow(cpumask); +} + +/* + * p m a p i n i t f u n c t i o n s + * + * pmap_bootstrap and pmap_init are called during system startup + * to init the pmap module. pmap_bootstrap() does a low level + * init just to get things rolling. pmap_init() finishes the job. + */ + +/* + * pmap_bootstrap: get the system in a state where it can run with VM + * properly enabled (called before main()). the VM system is + * fully init'd later... + * + * => on i386, locore.s has already enabled the MMU by allocating + * a PDP for the kernel, and nkpde PTP's for the kernel. + * => kva_start is the first free virtual address in kernel space + */ + +void +pmap_bootstrap(kva_start) + vaddr_t kva_start; +{ + vaddr_t kva, kva_end; + struct pmap *kpm; + pt_entry_t *pte; + int i; + unsigned long p1i; + + /* + * define the voundaries of the managed kernel virtual address + * space. + */ + + virtual_avail = kva_start; /* first free KVA */ + + /* + * set up protection_codes: we need to be able to convert from + * a MI protection code (some combo of VM_PROT...) to something + * we can jam into a i386 PTE. + */ + + protection_codes[VM_PROT_NONE] = 0; /* --- */ + protection_codes[VM_PROT_EXECUTE] = PG_RO; /* --x */ + protection_codes[VM_PROT_READ] = PG_RO; /* -r- */ + protection_codes[VM_PROT_READ|VM_PROT_EXECUTE] = PG_RO; /* -rx */ + protection_codes[VM_PROT_WRITE] = PG_RW; /* w-- */ + protection_codes[VM_PROT_WRITE|VM_PROT_EXECUTE] = PG_RW;/* w-x */ + protection_codes[VM_PROT_WRITE|VM_PROT_READ] = PG_RW; /* wr- */ + protection_codes[VM_PROT_ALL] = PG_RW; /* wrx */ + + /* + * now we init the kernel's pmap + * + * the kernel pmap's pm_obj is not used for much. however, in + * user pmaps the pm_obj contains the list of active PTPs. + * the pm_obj currently does not have a pager. it might be possible + * to add a pager that would allow a process to read-only mmap its + * own page tables (fast user level vtophys?). this may or may not + * be useful. + */ + + kpm = pmap_kernel(); + for (i = 0; i < PTP_LEVELS - 1; i++) { + simple_lock_init(&kpm->pm_obj[i].vmobjlock); + kpm->pm_obj[i].pgops = NULL; + TAILQ_INIT(&kpm->pm_obj[i].memq); + kpm->pm_obj[i].uo_npages = 0; + kpm->pm_obj[i].uo_refs = 1; + kpm->pm_ptphint[i] = NULL; + } + memset(&kpm->pm_list, 0, sizeof(kpm->pm_list)); /* pm_list not used */ + kpm->pm_pdir = (pd_entry_t *)(proc0.p_addr->u_pcb.pcb_cr3 + KERNBASE); + kpm->pm_pdirpa = (u_int32_t) proc0.p_addr->u_pcb.pcb_cr3; + kpm->pm_stats.wired_count = kpm->pm_stats.resident_count = + btop(kva_start - VM_MIN_KERNEL_ADDRESS); + + /* + * the above is just a rough estimate and not critical to the proper + * operation of the system. + */ + + curpcb->pcb_pmap = kpm; /* proc0's pcb */ + + /* + * enable global TLB entries if they are supported + */ + + if (cpu_feature & CPUID_PGE) { + lcr4(rcr4() | CR4_PGE); /* enable hardware (via %cr4) */ + pmap_pg_g = PG_G; /* enable software */ + + /* add PG_G attribute to already mapped kernel pages */ +#if KERNBASE == VM_MIN_KERNEL_ADDRESS + for (kva = VM_MIN_KERNEL_ADDRESS ; kva < virtual_avail ; +#else + kva_end = roundup((vaddr_t)&end, PAGE_SIZE); + for (kva = KERNBASE; kva < kva_end ; +#endif + kva += PAGE_SIZE) { + p1i = pl1_i(kva); + if (pmap_valid_entry(PTE_BASE[p1i])) + PTE_BASE[p1i] |= PG_G; + } + } + +#if defined(LARGEPAGES) && 0 /* XXX non-functional right now */ + /* + * enable large pages of they are supported. + */ + + if (cpu_feature & CPUID_PSE) { + paddr_t pa; + pd_entry_t *pde; + extern char _etext; + + lcr4(rcr4() | CR4_PSE); /* enable hardware (via %cr4) */ + pmap_largepages = 1; /* enable software */ + + /* + * the TLB must be flushed after enabling large pages + * on Pentium CPUs, according to section 3.6.2.2 of + * "Intel Architecture Software Developer's Manual, + * Volume 3: System Programming". + */ + tlbflush(); + + /* + * now, remap the kernel text using large pages. we + * assume that the linker has properly aligned the + * .data segment to a 4MB boundary. + */ + kva_end = roundup((vaddr_t)&_etext, NBPD); + for (pa = 0, kva = KERNBASE; kva < kva_end; + kva += NBPD, pa += NBPD) { + pde = &kpm->pm_pdir[pdei(kva)]; + *pde = pa | pmap_pg_g | PG_PS | + PG_KR | PG_V; /* zap! */ + tlbflush(); + } + } +#endif /* LARGEPAGES */ + +#if VM_MIN_KERNEL_ADDRESS != KERNBASE + /* + * zero_pte is stuck at the end of mapped space for the kernel + * image (disjunct from kva space). This is done so that it + * can safely be used in pmap_growkernel (pmap_get_physpage), + * when it's called for the first time. + * XXXfvdl fix this for MULTIPROCESSOR later. + */ + + early_zerop = (caddr_t)(KERNBASE + NKL2_KIMG_ENTRIES * NBPD_L2); + early_zero_pte = PTE_BASE + pl1_i((unsigned long)early_zerop); +#endif + + /* + * now we allocate the "special" VAs which are used for tmp mappings + * by the pmap (and other modules). we allocate the VAs by advancing + * virtual_avail (note that there are no pages mapped at these VAs). + * we find the PTE that maps the allocated VA via the linear PTE + * mapping. + */ + + pte = PTE_BASE + pl1_i(virtual_avail); + +#ifdef MULTIPROCESSOR + /* + * Waste some VA space to avoid false sharing of cache lines + * for page table pages: Give each possible CPU a cache line + * of PTE's (8) to play with, though we only need 4. We could + * recycle some of this waste by putting the idle stacks here + * as well; we could waste less space if we knew the largest + * CPU ID beforehand. + */ + csrcp = (caddr_t) virtual_avail; csrc_pte = pte; + + cdstp = (caddr_t) virtual_avail+PAGE_SIZE; cdst_pte = pte+1; + + zerop = (caddr_t) virtual_avail+PAGE_SIZE*2; zero_pte = pte+2; + + ptpp = (caddr_t) virtual_avail+PAGE_SIZE*3; ptp_pte = pte+3; + + virtual_avail += PAGE_SIZE * X86_MAXPROCS * NPTECL; + pte += X86_MAXPROCS * NPTECL; +#else + csrcp = (caddr_t) virtual_avail; csrc_pte = pte; /* allocate */ + virtual_avail += PAGE_SIZE; pte++; /* advance */ + + cdstp = (caddr_t) virtual_avail; cdst_pte = pte; + virtual_avail += PAGE_SIZE; pte++; + + zerop = (caddr_t) virtual_avail; zero_pte = pte; + virtual_avail += PAGE_SIZE; pte++; + + ptpp = (caddr_t) virtual_avail; ptp_pte = pte; + virtual_avail += PAGE_SIZE; pte++; +#endif + +#if VM_MIN_KERNEL_ADDRESS == KERNBASE + early_zerop = zerop; + early_zero_pte = zero_pte; +#endif + + pte = (void *)0xdeadbeef; + + /* XXX: vmmap used by mem.c... should be uvm_map_reserve */ + /* XXXfvdl PTEs not needed here */ + vmmap = (char *)virtual_avail; /* don't need pte */ + virtual_avail += PAGE_SIZE; pte++; + + msgbuf_vaddr = virtual_avail; /* don't need pte */ + virtual_avail += round_page(MSGBUFSIZE); + pte += x86_btop(round_page(MSGBUFSIZE)); + + idt_vaddr = virtual_avail; /* don't need pte */ + virtual_avail += 2 * PAGE_SIZE; pte += 2; + idt_paddr = avail_start; /* steal a page */ + avail_start += 2 * PAGE_SIZE; + +#if defined(I586_CPU) + /* pentium f00f bug stuff */ + pentium_idt_vaddr = virtual_avail; /* don't need pte */ + virtual_avail += PAGE_SIZE; pte++; +#endif + +#ifdef _LP64 + /* + * Grab a page below 4G for things that need it (i.e. + * having an initial %cr3 for the MP trampoline). + */ + lo32_vaddr = virtual_avail; + virtual_avail += PAGE_SIZE; pte++; + lo32_paddr = avail_start; + avail_start += PAGE_SIZE; +#endif + + /* + * now we reserve some VM for mapping pages when doing a crash dump + */ + + virtual_avail = reserve_dumppages(virtual_avail); + + /* + * init the static-global locks and global lists. + */ + +#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) + spinlockinit(&pmap_main_lock, "pmaplk", 0); +#endif + simple_lock_init(&pvalloc_lock); + simple_lock_init(&pmaps_lock); + LIST_INIT(&pmaps); + TAILQ_INIT(&pv_freepages); + TAILQ_INIT(&pv_unusedpgs); + + /* + * initialize the pmap pool. + */ + + pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl", + &pool_allocator_nointr); + + /* + * Initialize the TLB shootdown queues. + */ + + simple_lock_init(&pmap_tlb_shootdown_job_lock); + + for (i = 0; i < X86_MAXPROCS; i++) { + TAILQ_INIT(&pmap_tlb_shootdown_q[i].pq_head); + simple_lock_init(&pmap_tlb_shootdown_q[i].pq_slock); + } + + /* + * initialize the PDE pool and cache. + */ + + pool_init(&pmap_pdp_pool, PAGE_SIZE, 0, 0, 0, "pdppl", + &pool_allocator_nointr); + pool_cache_init(&pmap_pdp_cache, &pmap_pdp_pool, + pmap_pdp_ctor, NULL, NULL); + + /* + * ensure the TLB is sync'd with reality by flushing it... + */ + + tlbflush(); +} + +/* + * Pre-allocate PTPs for low memory, so that 1:1 mappings for various + * trampoline code can be entered. + */ +void +pmap_prealloc_lowmem_ptps(void) +{ + pd_entry_t *pdes; + int level; + paddr_t newp; + + pdes = pmap_kernel()->pm_pdir; + level = PTP_LEVELS; + for (;;) { + newp = avail_start; + avail_start += PAGE_SIZE; + *early_zero_pte = (newp & PG_FRAME) | PG_V | PG_RW; + pmap_update_pg((vaddr_t)early_zerop); + memset(early_zerop, 0, PAGE_SIZE); + pdes[pl_i(0, level)] = (newp & PG_FRAME) | PG_V | PG_RW; + level--; + if (level <= 1) + break; + pdes = normal_pdes[level - 2]; + } +} + +/* + * pmap_init: called from uvm_init, our job is to get the pmap + * system ready to manage mappings... this mainly means initing + * the pv_entry stuff. + */ + +void +pmap_init() +{ + int lcv; + unsigned int npages, i; + vaddr_t addr; + vsize_t s; + + /* + * compute the number of pages we have and then allocate RAM + * for each pages' pv_head and saved attributes. + */ + + npages = 0; + for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) + npages += (vm_physmem[lcv].end - vm_physmem[lcv].start); + s = (vsize_t) (sizeof(struct pv_head) * npages + + sizeof(char) * npages); + s = round_page(s); + addr = (vaddr_t) uvm_km_zalloc(kernel_map, s); + if (addr == 0) + panic("pmap_init: unable to allocate pv_heads"); + + /* + * init all pv_head's and attrs in one memset + */ + + /* allocate pv_head stuff first */ + for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) { + vm_physmem[lcv].pmseg.pvhead = (struct pv_head *) addr; + addr = (vaddr_t)(vm_physmem[lcv].pmseg.pvhead + + (vm_physmem[lcv].end - vm_physmem[lcv].start)); + for (i = 0; + i < (vm_physmem[lcv].end - vm_physmem[lcv].start); i++) { + simple_lock_init( + &vm_physmem[lcv].pmseg.pvhead[i].pvh_lock); + } + } + + /* now allocate attrs */ + for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) { + vm_physmem[lcv].pmseg.attrs = (unsigned char *)addr; + addr = (vaddr_t)(vm_physmem[lcv].pmseg.attrs + + (vm_physmem[lcv].end - vm_physmem[lcv].start)); + } + +#ifdef LOCKDEBUG + /* + * Now, initialize all the pv_head locks. + * We only do this if LOCKDEBUG because we know that initialized locks + * are always all-zero if !LOCKDEBUG. + */ + for (lcv = 0; lcv < vm_nphysseg ; lcv++) { + int off, npages; + struct pmap_physseg *pmsegp; + + npages = vm_physmem[lcv].end - vm_physmem[lcv].start; + pmsegp = &vm_physmem[lcv].pmseg; + + for (off = 0; off <npages; off++) + simple_lock_init(&pmsegp->pvhead[off].pvh_lock); + + } +#endif + + /* + * now we need to free enough pv_entry structures to allow us to get + * the kmem_map allocated and inited (done after this + * function is finished). to do this we allocate one bootstrap page out + * of kernel_map and use it to provide an initial pool of pv_entry + * structures. we never free this page. + */ + + pv_initpage = (struct pv_page *) uvm_km_alloc(kernel_map, PAGE_SIZE); + if (pv_initpage == NULL) + panic("pmap_init: pv_initpage"); + pv_cachedva = 0; /* a VA we have allocated but not used yet */ + pv_nfpvents = 0; + (void) pmap_add_pvpage(pv_initpage, FALSE); + + pj_page = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE); + if (pj_page == NULL) + panic("pmap_init: pj_page"); + + for (i = 0; + i < (PAGE_SIZE / sizeof (union pmap_tlb_shootdown_job_al) - 1); + i++) + pj_page[i].pja_job.pj_nextfree = &pj_page[i + 1].pja_job; + pj_page[i].pja_job.pj_nextfree = NULL; + pj_free = &pj_page[0]; + + /* + * done: pmap module is up (and ready for business) + */ + + pmap_initialized = TRUE; +} + +/* + * p v _ e n t r y f u n c t i o n s + */ + +/* + * pv_entry allocation functions: + * the main pv_entry allocation functions are: + * pmap_alloc_pv: allocate a pv_entry structure + * pmap_free_pv: free one pv_entry + * pmap_free_pvs: free a list of pv_entrys + * + * the rest are helper functions + */ + +/* + * pmap_alloc_pv: inline function to allocate a pv_entry structure + * => we lock pvalloc_lock + * => if we fail, we call out to pmap_alloc_pvpage + * => 3 modes: + * ALLOCPV_NEED = we really need a pv_entry, even if we have to steal it + * ALLOCPV_TRY = we want a pv_entry, but not enough to steal + * ALLOCPV_NONEED = we are trying to grow our free list, don't really need + * one now + * + * "try" is for optional functions like pmap_copy(). + */ + +__inline static struct pv_entry * +pmap_alloc_pv(pmap, mode) + struct pmap *pmap; + int mode; +{ + struct pv_page *pvpage; + struct pv_entry *pv; + + simple_lock(&pvalloc_lock); + + pvpage = TAILQ_FIRST(&pv_freepages); + if (pvpage != NULL) { + pvpage->pvinfo.pvpi_nfree--; + if (pvpage->pvinfo.pvpi_nfree == 0) { + /* nothing left in this one? */ + TAILQ_REMOVE(&pv_freepages, pvpage, pvinfo.pvpi_list); + } + pv = pvpage->pvinfo.pvpi_pvfree; + KASSERT(pv); + pvpage->pvinfo.pvpi_pvfree = pv->pv_next; + pv_nfpvents--; /* took one from pool */ + } else { + pv = NULL; /* need more of them */ + } + + /* + * if below low water mark or we didn't get a pv_entry we try and + * create more pv_entrys ... + */ + + if (pv_nfpvents < PVE_LOWAT || pv == NULL) { + if (pv == NULL) + pv = pmap_alloc_pvpage(pmap, (mode == ALLOCPV_TRY) ? + mode : ALLOCPV_NEED); + else + (void) pmap_alloc_pvpage(pmap, ALLOCPV_NONEED); + } + + simple_unlock(&pvalloc_lock); + return(pv); +} + +/* + * pmap_alloc_pvpage: maybe allocate a new pvpage + * + * if need_entry is false: try and allocate a new pv_page + * if need_entry is true: try and allocate a new pv_page and return a + * new pv_entry from it. if we are unable to allocate a pv_page + * we make a last ditch effort to steal a pv_page from some other + * mapping. if that fails, we panic... + * + * => we assume that the caller holds pvalloc_lock + */ + +struct pv_entry * +pmap_alloc_pvpage(pmap, mode) + struct pmap *pmap; + int mode; +{ + struct vm_page *pg; + struct pv_page *pvpage; + struct pv_entry *pv; + int s; + + /* + * if we need_entry and we've got unused pv_pages, allocate from there + */ + + pvpage = TAILQ_FIRST(&pv_unusedpgs); + if (mode != ALLOCPV_NONEED && pvpage != NULL) { + + /* move it to pv_freepages list */ + TAILQ_REMOVE(&pv_unusedpgs, pvpage, pvinfo.pvpi_list); + TAILQ_INSERT_HEAD(&pv_freepages, pvpage, pvinfo.pvpi_list); + + /* allocate a pv_entry */ + pvpage->pvinfo.pvpi_nfree--; /* can't go to zero */ + pv = pvpage->pvinfo.pvpi_pvfree; + KASSERT(pv); + pvpage->pvinfo.pvpi_pvfree = pv->pv_next; + pv_nfpvents--; /* took one from pool */ + return(pv); + } + + /* + * see if we've got a cached unmapped VA that we can map a page in. + * if not, try to allocate one. + */ + + s = splvm(); /* must protect kmem_map with splvm! */ + if (pv_cachedva == 0) { + pv_cachedva = uvm_km_kmemalloc(kmem_map, uvmexp.kmem_object, + PAGE_SIZE, UVM_KMF_TRYLOCK|UVM_KMF_VALLOC); + if (pv_cachedva == 0) { + splx(s); + return (NULL); + } + } + + /* + * we have a VA, now let's try and allocate a page. + */ + if (!simple_lock_try(&uvmexp.kmem_object->vmobjlock)) { + splx(s); + return (NULL); + } + + pg = uvm_pagealloc(uvmexp.kmem_object, pv_cachedva - + vm_map_min(kernel_map), NULL, UVM_PGA_USERESERVE); + if (pg) + pg->flags &= ~PG_BUSY; /* never busy */ + + simple_unlock(&uvmexp.kmem_object->vmobjlock); + splx(s); + + if (pg == NULL) + return (NULL); + + /* + * add a mapping for our new pv_page and free its entrys (save one!) + * + * NOTE: If we are allocating a PV page for the kernel pmap, the + * pmap is already locked! (...but entering the mapping is safe...) + */ + + pmap_kenter_pa(pv_cachedva, VM_PAGE_TO_PHYS(pg), + VM_PROT_READ | VM_PROT_WRITE); + pmap_update(pmap_kernel()); + pvpage = (struct pv_page *) pv_cachedva; + pv_cachedva = 0; + return (pmap_add_pvpage(pvpage, mode != ALLOCPV_NONEED)); +} + +/* + * pmap_add_pvpage: add a pv_page's pv_entrys to the free list + * + * => caller must hold pvalloc_lock + * => if need_entry is true, we allocate and return one pv_entry + */ + +static struct pv_entry * +pmap_add_pvpage(pvp, need_entry) + struct pv_page *pvp; + boolean_t need_entry; +{ + int tofree, lcv; + + /* do we need to return one? */ + tofree = (need_entry) ? PVE_PER_PVPAGE - 1 : PVE_PER_PVPAGE; + + pvp->pvinfo.pvpi_pvfree = NULL; + pvp->pvinfo.pvpi_nfree = tofree; + for (lcv = 0 ; lcv < tofree ; lcv++) { + pvp->pvents[lcv].pv_next = pvp->pvinfo.pvpi_pvfree; + pvp->pvinfo.pvpi_pvfree = &pvp->pvents[lcv]; + } + if (need_entry) + TAILQ_INSERT_TAIL(&pv_freepages, pvp, pvinfo.pvpi_list); + else + TAILQ_INSERT_TAIL(&pv_unusedpgs, pvp, pvinfo.pvpi_list); + pv_nfpvents += tofree; + return((need_entry) ? &pvp->pvents[lcv] : NULL); +} + +/* + * pmap_free_pv_doit: actually free a pv_entry + * + * => do not call this directly! instead use either + * 1. pmap_free_pv ==> free a single pv_entry + * 2. pmap_free_pvs => free a list of pv_entrys + * => we must be holding pvalloc_lock + */ + +__inline static void +pmap_free_pv_doit(pv) + struct pv_entry *pv; +{ + struct pv_page *pvp; + + pvp = (struct pv_page *) x86_trunc_page(pv); + pv_nfpvents++; + pvp->pvinfo.pvpi_nfree++; + + /* nfree == 1 => fully allocated page just became partly allocated */ + if (pvp->pvinfo.pvpi_nfree == 1) { + TAILQ_INSERT_HEAD(&pv_freepages, pvp, pvinfo.pvpi_list); + } + + /* free it */ + pv->pv_next = pvp->pvinfo.pvpi_pvfree; + pvp->pvinfo.pvpi_pvfree = pv; + + /* + * are all pv_page's pv_entry's free? move it to unused queue. + */ + + if (pvp->pvinfo.pvpi_nfree == PVE_PER_PVPAGE) { + TAILQ_REMOVE(&pv_freepages, pvp, pvinfo.pvpi_list); + TAILQ_INSERT_HEAD(&pv_unusedpgs, pvp, pvinfo.pvpi_list); + } +} + +/* + * pmap_free_pv: free a single pv_entry + * + * => we gain the pvalloc_lock + */ + +__inline static void +pmap_free_pv(pmap, pv) + struct pmap *pmap; + struct pv_entry *pv; +{ + simple_lock(&pvalloc_lock); + pmap_free_pv_doit(pv); + + /* + * Can't free the PV page if the PV entries were associated with + * the kernel pmap; the pmap is already locked. + */ + if (pv_nfpvents > PVE_HIWAT && TAILQ_FIRST(&pv_unusedpgs) != NULL && + pmap != pmap_kernel()) + pmap_free_pvpage(); + + simple_unlock(&pvalloc_lock); +} + +/* + * pmap_free_pvs: free a list of pv_entrys + * + * => we gain the pvalloc_lock + */ + +__inline static void +pmap_free_pvs(pmap, pvs) + struct pmap *pmap; + struct pv_entry *pvs; +{ + struct pv_entry *nextpv; + + simple_lock(&pvalloc_lock); + + for ( /* null */ ; pvs != NULL ; pvs = nextpv) { + nextpv = pvs->pv_next; + pmap_free_pv_doit(pvs); + } + + /* + * Can't free the PV page if the PV entries were associated with + * the kernel pmap; the pmap is already locked. + */ + if (pv_nfpvents > PVE_HIWAT && TAILQ_FIRST(&pv_unusedpgs) != NULL && + pmap != pmap_kernel()) + pmap_free_pvpage(); + + simple_unlock(&pvalloc_lock); +} + + +/* + * pmap_free_pvpage: try and free an unused pv_page structure + * + * => assume caller is holding the pvalloc_lock and that + * there is a page on the pv_unusedpgs list + * => if we can't get a lock on the kmem_map we try again later + */ + +void +pmap_free_pvpage() +{ + int s; + struct vm_map *map; + struct vm_map_entry *dead_entries; + struct pv_page *pvp; + + s = splvm(); /* protect kmem_map */ + + pvp = TAILQ_FIRST(&pv_unusedpgs); + + /* + * note: watch out for pv_initpage which is allocated out of + * kernel_map rather than kmem_map. + */ + + if (pvp == pv_initpage) + map = kernel_map; + else + map = kmem_map; + if (vm_map_lock_try(map)) { + + /* remove pvp from pv_unusedpgs */ + TAILQ_REMOVE(&pv_unusedpgs, pvp, pvinfo.pvpi_list); + + /* unmap the page */ + dead_entries = NULL; + uvm_unmap_remove(map, (vaddr_t)pvp, ((vaddr_t)pvp) + PAGE_SIZE, + &dead_entries); + vm_map_unlock(map); + + if (dead_entries != NULL) + uvm_unmap_detach(dead_entries, 0); + + pv_nfpvents -= PVE_PER_PVPAGE; /* update free count */ + } + if (pvp == pv_initpage) + /* no more initpage, we've freed it */ + pv_initpage = NULL; + + splx(s); +} + +/* + * main pv_entry manipulation functions: + * pmap_enter_pv: enter a mapping onto a pv_head list + * pmap_remove_pv: remove a mappiing from a pv_head list + * + * NOTE: pmap_enter_pv expects to lock the pvh itself + * pmap_remove_pv expects te caller to lock the pvh before calling + */ + +/* + * pmap_enter_pv: enter a mapping onto a pv_head lst + * + * => caller should hold the proper lock on pmap_main_lock + * => caller should have pmap locked + * => we will gain the lock on the pv_head and allocate the new pv_entry + * => caller should adjust ptp's wire_count before calling + */ + +__inline static void +pmap_enter_pv(pvh, pve, pmap, va, ptp) + struct pv_head *pvh; + struct pv_entry *pve; /* preallocated pve for us to use */ + struct pmap *pmap; + vaddr_t va; + struct vm_page *ptp; /* PTP in pmap that maps this VA */ +{ + pve->pv_pmap = pmap; + pve->pv_va = va; + pve->pv_ptp = ptp; /* NULL for kernel pmap */ + simple_lock(&pvh->pvh_lock); /* lock pv_head */ + pve->pv_next = pvh->pvh_list; /* add to ... */ + pvh->pvh_list = pve; /* ... locked list */ + simple_unlock(&pvh->pvh_lock); /* unlock, done! */ +} + +/* + * pmap_remove_pv: try to remove a mapping from a pv_list + * + * => caller should hold proper lock on pmap_main_lock + * => pmap should be locked + * => caller should hold lock on pv_head [so that attrs can be adjusted] + * => caller should adjust ptp's wire_count and free PTP if needed + * => we return the removed pve + */ + +__inline static struct pv_entry * +pmap_remove_pv(pvh, pmap, va) + struct pv_head *pvh; + struct pmap *pmap; + vaddr_t va; +{ + struct pv_entry *pve, **prevptr; + + prevptr = &pvh->pvh_list; /* previous pv_entry pointer */ + pve = *prevptr; + while (pve) { + if (pve->pv_pmap == pmap && pve->pv_va == va) { /* match? */ + *prevptr = pve->pv_next; /* remove it! */ + break; + } + prevptr = &pve->pv_next; /* previous pointer */ + pve = pve->pv_next; /* advance */ + } + return(pve); /* return removed pve */ +} + +/* + * p t p f u n c t i o n s + */ + +static __inline struct vm_page * +pmap_find_ptp(struct pmap *pmap, vaddr_t va, paddr_t pa, int level) +{ + int lidx = level - 1; + struct vm_page *pg; + + if (pa != (paddr_t)-1 && pmap->pm_ptphint[lidx] && + pa == VM_PAGE_TO_PHYS(pmap->pm_ptphint[lidx])) { + return (pmap->pm_ptphint[lidx]); + } + if (lidx == 0) + pg = uvm_pagelookup(&pmap->pm_obj[lidx], ptp_va2o(va, level)); + else { + simple_lock(&pmap->pm_obj[lidx].vmobjlock); + pg = uvm_pagelookup(&pmap->pm_obj[lidx], ptp_va2o(va, level)); + simple_unlock(&pmap->pm_obj[lidx].vmobjlock); + } + return pg; +} + +static __inline void +pmap_freepage(struct pmap *pmap, struct vm_page *ptp, int level) +{ + int lidx; + struct uvm_object *obj; + + lidx = level - 1; + + obj = &pmap->pm_obj[lidx]; + pmap->pm_stats.resident_count--; + if (lidx != 0) + simple_lock(&obj->vmobjlock); + if (pmap->pm_ptphint[lidx] == ptp) + pmap->pm_ptphint[lidx] = TAILQ_FIRST(&obj->memq); + ptp->wire_count = 0; + uvm_pagefree(ptp); + if (lidx != 0) + simple_unlock(&obj->vmobjlock); +} + +void +pmap_free_ptp(struct pmap *pmap, struct vm_page *ptp, vaddr_t va, + pt_entry_t *ptes, pd_entry_t **pdes, int32_t *cpumaskp) +{ + unsigned long index; + int level; + vaddr_t invaladdr; + pd_entry_t opde; + + level = 1; + do { + pmap_freepage(pmap, ptp, level); + index = pl_i(va, level + 1); + opde = pmap_pte_set(&pdes[level - 1][index], 0); + invaladdr = level == 1 ? (vaddr_t)ptes : + (vaddr_t)pdes[level - 2]; + pmap_tlb_shootdown(curpcb->pcb_pmap, + invaladdr + index * PAGE_SIZE, + opde, cpumaskp); +#if defined(MULTIPROCESSOR) + invaladdr = level == 1 ? (vaddr_t)PTE_BASE : + (vaddr_t)normal_pdes[level - 2]; + pmap_tlb_shootdown(pmap, invaladdr + index * PAGE_SIZE, opde, + cpumaskp); +#endif + if (level < PTP_LEVELS - 1) { + ptp = pmap_find_ptp(pmap, va, (paddr_t)-1, level + 1); + ptp->wire_count--; + if (ptp->wire_count > 1) + break; + } + } while (++level < PTP_LEVELS); +} + +/* + * pmap_get_ptp: get a PTP (if there isn't one, allocate a new one) + * + * => pmap should NOT be pmap_kernel() + * => pmap should be locked + */ + + +struct vm_page * +pmap_get_ptp(struct pmap *pmap, vaddr_t va, pd_entry_t **pdes) +{ + struct vm_page *ptp, *pptp; + int i; + unsigned long index; + pd_entry_t *pva; + paddr_t ppa, pa; + struct uvm_object *obj; + + ptp = NULL; + pa = (paddr_t)-1; + + /* + * Loop through all page table levels seeing if we need to + * add a new page to that level. + */ + for (i = PTP_LEVELS; i > 1; i--) { + /* + * Save values from previous round. + */ + pptp = ptp; + ppa = pa; + + index = pl_i(va, i); + pva = pdes[i - 2]; + + if (pmap_valid_entry(pva[index])) { + ppa = pva[index] & PG_FRAME; + ptp = NULL; + continue; + } + + obj = &pmap->pm_obj[i-2]; + /* + * XXX pm_obj[0] is pm_lock, which is already locked. + */ + if (i != 2) + simple_lock(&obj->vmobjlock); + ptp = uvm_pagealloc(obj, ptp_va2o(va, i - 1), NULL, + UVM_PGA_USERESERVE|UVM_PGA_ZERO); + if (i != 2) + simple_unlock(&obj->vmobjlock); + + if (ptp == NULL) + return NULL; + + ptp->flags &= ~PG_BUSY; /* never busy */ + ptp->wire_count = 1; + pmap->pm_ptphint[i - 2] = ptp; + pa = VM_PAGE_TO_PHYS(ptp); + pva[index] = (pd_entry_t) (pa | PG_u | PG_RW | PG_V); + pmap->pm_stats.resident_count++; + /* + * If we're not in the top level, increase the + * wire count of the parent page. + */ + if (i < PTP_LEVELS) { + if (pptp == NULL) + pptp = pmap_find_ptp(pmap, va, ppa, i); +#ifdef DIAGNOSTIC + if (pptp == NULL) + panic("pde page disappeared"); +#endif + pptp->wire_count++; + } + } + + /* + * ptp is not NULL if we just allocated a new ptp. If it's + * still NULL, we must look up the existing one. + */ + if (ptp == NULL) { + ptp = pmap_find_ptp(pmap, va, ppa, 1); +#ifdef DIAGNOSTIC + if (ptp == NULL) { + printf("va %lx ppa %lx\n", (unsigned long)va, + (unsigned long)ppa); + panic("pmap_get_ptp: unmanaged user PTP"); + } +#endif + } + + pmap->pm_ptphint[0] = ptp; + return(ptp); +} + +/* + * p m a p l i f e c y c l e f u n c t i o n s + */ + +/* + * pmap_pdp_ctor: constructor for the PDP cache. + */ + +int +pmap_pdp_ctor(void *arg, void *object, int flags) +{ + pd_entry_t *pdir = object; + paddr_t pdirpa; + int npde; + + /* + * NOTE: The `pmap_lock' is held when the PDP is allocated. + * WE MUST NOT BLOCK! + */ + + /* fetch the physical address of the page directory. */ + (void) pmap_extract(pmap_kernel(), (vaddr_t) pdir, &pdirpa); + + /* zero init area */ + memset(pdir, 0, PDIR_SLOT_PTE * sizeof(pd_entry_t)); + + /* put in recursibve PDE to map the PTEs */ + pdir[PDIR_SLOT_PTE] = pdirpa | PG_V | PG_KW; + + npde = nkptp[PTP_LEVELS - 1]; + + /* put in kernel VM PDEs */ + memcpy(&pdir[PDIR_SLOT_KERN], &PDP_BASE[PDIR_SLOT_KERN], + npde * sizeof(pd_entry_t)); + + /* zero the rest */ + memset(&pdir[PDIR_SLOT_KERN + npde], 0, + (NTOPLEVEL_PDES - (PDIR_SLOT_KERN + npde)) * sizeof(pd_entry_t)); + +#if VM_MIN_KERNEL_ADDRESS != KERNBASE + pdir[pl4_pi(KERNBASE)] = PDP_BASE[pl4_pi(KERNBASE)]; +#endif + + return (0); +} + +/* + * pmap_create: create a pmap + * + * => note: old pmap interface took a "size" args which allowed for + * the creation of "software only" pmaps (not in bsd). + */ + +struct pmap * +pmap_create() +{ + struct pmap *pmap; + int i; + u_int gen; + + pmap = pool_get(&pmap_pmap_pool, PR_WAITOK); + + /* init uvm_object */ + for (i = 0; i < PTP_LEVELS - 1; i++) { + simple_lock_init(&pmap->pm_obj[i].vmobjlock); + pmap->pm_obj[i].pgops = NULL; /* not a mappable object */ + TAILQ_INIT(&pmap->pm_obj[i].memq); + pmap->pm_obj[i].uo_npages = 0; + pmap->pm_obj[i].uo_refs = 1; + pmap->pm_ptphint[i] = NULL; + } + pmap->pm_stats.wired_count = 0; + pmap->pm_stats.resident_count = 1; /* count the PDP allocd below */ + pmap->pm_flags = 0; + + /* init the LDT */ + pmap->pm_ldt = NULL; + pmap->pm_ldt_len = 0; + pmap->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL); + + /* allocate PDP */ + + /* + * we need to lock pmaps_lock to prevent nkpde from changing on + * us. note that there is no need to splvm to protect us from + * malloc since malloc allocates out of a submap and we should + * have already allocated kernel PTPs to cover the range... + * + * NOTE: WE MUST NOT BLOCK WHILE HOLDING THE `pmap_lock', nor + * ust we call pmap_growkernel() while holding it! + */ + +try_again: + gen = pmap_pdp_cache_generation; + pmap->pm_pdir = pool_cache_get(&pmap_pdp_cache, PR_WAITOK); + + simple_lock(&pmaps_lock); + + if (gen != pmap_pdp_cache_generation) { + simple_unlock(&pmaps_lock); + pool_cache_destruct_object(&pmap_pdp_cache, pmap->pm_pdir); + goto try_again; + } + + pmap->pm_pdirpa = pmap->pm_pdir[PDIR_SLOT_PTE] & PG_FRAME; + + LIST_INSERT_HEAD(&pmaps, pmap, pm_list); + + simple_unlock(&pmaps_lock); + + return (pmap); +} + +/* + * pmap_destroy: drop reference count on pmap. free pmap if + * reference count goes to zero. + */ + +void +pmap_destroy(pmap) + struct pmap *pmap; +{ + struct vm_page *pg; + int refs; + int i; + + /* + * drop reference count + */ + + simple_lock(&pmap->pm_lock); + refs = --pmap->pm_obj[0].uo_refs; + simple_unlock(&pmap->pm_lock); + if (refs > 0) { + return; + } + + /* + * reference count is zero, free pmap resources and then free pmap. + */ + + /* + * remove it from global list of pmaps + */ + + simple_lock(&pmaps_lock); + LIST_REMOVE(pmap, pm_list); + simple_unlock(&pmaps_lock); + + /* + * free any remaining PTPs + */ + + for (i = 0; i < PTP_LEVELS - 1; i++) { + while ((pg = TAILQ_FIRST(&pmap->pm_obj[i].memq)) != NULL) { + KASSERT((pg->flags & PG_BUSY) == 0); + + pg->wire_count = 0; + uvm_pagefree(pg); + } + } + + /* + * MULTIPROCESSOR -- no need to flush out of other processors' + * APTE space because we do that in pmap_unmap_ptes(). + */ + /* XXX: need to flush it out of other processor's APTE space? */ + pool_cache_put(&pmap_pdp_cache, pmap->pm_pdir); + +#ifdef USER_LDT + if (pmap->pm_flags & PMF_USER_LDT) { + /* + * no need to switch the LDT; this address space is gone, + * nothing is using it. + * + * No need to lock the pmap for ldt_free (or anything else), + * we're the last one to use it. + */ + ldt_free(pmap); + uvm_km_free(kernel_map, (vaddr_t)pmap->pm_ldt, + pmap->pm_ldt_len); + } +#endif + + pool_put(&pmap_pmap_pool, pmap); +} + +/* + * Add a reference to the specified pmap. + */ + +void +pmap_reference(pmap) + struct pmap *pmap; +{ + simple_lock(&pmap->pm_lock); + pmap->pm_obj[0].uo_refs++; + simple_unlock(&pmap->pm_lock); +} + +#if defined(PMAP_FORK) +/* + * pmap_fork: perform any necessary data structure manipulation when + * a VM space is forked. + */ + +void +pmap_fork(pmap1, pmap2) + struct pmap *pmap1, *pmap2; +{ + simple_lock(&pmap1->pm_lock); + simple_lock(&pmap2->pm_lock); + +#ifdef USER_LDT + /* Copy the LDT, if necessary. */ + if (pmap1->pm_flags & PMF_USER_LDT) { + char *new_ldt; + size_t len; + + len = pmap1->pm_ldt_len; + new_ldt = (char *)uvm_km_alloc(kernel_map, len); + memcpy(new_ldt, pmap1->pm_ldt, len); + pmap2->pm_ldt = new_ldt; + pmap2->pm_ldt_len = pmap1->pm_ldt_len; + pmap2->pm_flags |= PMF_USER_LDT; + ldt_alloc(pmap2, new_ldt, len); + } +#endif /* USER_LDT */ + + simple_unlock(&pmap2->pm_lock); + simple_unlock(&pmap1->pm_lock); +} +#endif /* PMAP_FORK */ + +#ifdef USER_LDT +/* + * pmap_ldt_cleanup: if the pmap has a local LDT, deallocate it, and + * restore the default. + */ + +void +pmap_ldt_cleanup(struct proc *p) +{ + struct pcb *pcb = &p->p_addr->u_pcb; + pmap_t pmap = p->->p_vmspace->vm_map.pmap; + char *old_ldt = NULL; + size_t len = 0; + + simple_lock(&pmap->pm_lock); + + if (pmap->pm_flags & PMF_USER_LDT) { + ldt_free(pmap); + pmap->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL); + pcb->pcb_ldt_sel = pmap->pm_ldt_sel; + if (pcb == curpcb) + lldt(pcb->pcb_ldt_sel); + old_ldt = pmap->pm_ldt; + len = pmap->pm_ldt_len; + pmap->pm_ldt = NULL; + pmap->pm_ldt_len = 0; + pmap->pm_flags &= ~PMF_USER_LDT; + } + + simple_unlock(&pmap->pm_lock); + + if (old_ldt != NULL) + uvm_km_free(kernel_map, (vaddr_t)old_ldt, len); +} +#endif /* USER_LDT */ + +/* + * pmap_activate: activate a process' pmap (fill in %cr3 and LDT info) + * + * => called from cpu_switch() + * => if p is the curproc, then load it into the MMU + */ + +void +pmap_activate(struct proc *p) +{ + struct pcb *pcb = &p->p_addr->u_pcb; + struct pmap *pmap = p->p_vmspace->vm_map.pmap; + + pcb->pcb_pmap = pmap; + pcb->pcb_ldt_sel = pmap->pm_ldt_sel; + pcb->pcb_cr3 = pmap->pm_pdirpa; + if (p == curproc) + lcr3(pcb->pcb_cr3); + if (pcb == curpcb) + lldt(pcb->pcb_ldt_sel); + + /* + * mark the pmap in use by this processor. + */ + x86_atomic_setbits_ul(&pmap->pm_cpus, (1U << cpu_number())); +} + +/* + * pmap_deactivate: deactivate a process' pmap + */ + +void +pmap_deactivate(struct proc *p) +{ + struct pmap *pmap = p->p_vmspace->vm_map.pmap; + + /* + * mark the pmap no longer in use by this processor. + */ + x86_atomic_clearbits_ul(&pmap->pm_cpus, (1U << cpu_number())); + +} + +/* + * end of lifecycle functions + */ + +/* + * some misc. functions + */ + +boolean_t +pmap_pdes_valid(vaddr_t va, pd_entry_t **pdes, pd_entry_t *lastpde) +{ + int i; + unsigned long index; + pd_entry_t pde; + + for (i = PTP_LEVELS; i > 1; i--) { + index = pl_i(va, i); + pde = pdes[i - 2][index]; + if ((pde & PG_V) == 0) + return FALSE; + } + if (lastpde != NULL) + *lastpde = pde; + return TRUE; +} + +/* + * pmap_extract: extract a PA for the given VA + */ + +boolean_t +pmap_extract(pmap, va, pap) + struct pmap *pmap; + vaddr_t va; + paddr_t *pap; +{ + pt_entry_t *ptes, pte; + pd_entry_t pde, **pdes; + + pmap_map_ptes(pmap, &ptes, &pdes); + if (pmap_pdes_valid(va, pdes, &pde) == FALSE) { + pmap_unmap_ptes(pmap); + return FALSE; + } + pte = ptes[pl1_i(va)]; + pmap_unmap_ptes(pmap); + +#ifdef LARGEPAGES + if (pde & PG_PS) { + if (pap != NULL) + *pap = (pde & PG_LGFRAME) | (va & ~PG_LGFRAME); + return (TRUE); + } +#endif + + + if (__predict_true((pte & PG_V) != 0)) { + if (pap != NULL) + *pap = (pte & PG_FRAME) | (va & ~PG_FRAME); + return (TRUE); + } + + return FALSE; +} + + +/* + * vtophys: virtual address to physical address. For use by + * machine-dependent code only. + */ + +paddr_t +vtophys(va) + vaddr_t va; +{ + paddr_t pa; + + if (pmap_extract(pmap_kernel(), va, &pa) == TRUE) + return (pa); + return (0); +} + + +/* + * pmap_map: map a range of PAs into kvm + * + * => used during crash dump + * => XXX: pmap_map() should be phased out? + */ + +vaddr_t +pmap_map(va, spa, epa, prot) + vaddr_t va; + paddr_t spa, epa; + vm_prot_t prot; +{ + while (spa < epa) { + pmap_enter(pmap_kernel(), va, spa, prot, 0); + va += PAGE_SIZE; + spa += PAGE_SIZE; + } + pmap_update(pmap_kernel()); + return va; +} + + +/* + * pmap_zero_page: zero a page + */ + +void +pmap_zero_page(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + +#ifdef MULTIPROCESSOR + int id = cpu_number(); +#endif + pt_entry_t *zpte = PTESLEW(zero_pte, id); + caddr_t zerova = VASLEW(zerop, id); + +#ifdef DIAGNOSTIC + if (*zpte) + panic("pmap_zero_page: lock botch"); +#endif + + *zpte = (pa & PG_FRAME) | PG_V | PG_RW; /* map in */ + pmap_update_pg((vaddr_t)zerova); /* flush TLB */ + + memset(zerova, 0, PAGE_SIZE); /* zero */ +#ifdef DIAGNOSTIC + *zpte = 0; /* zap! */ +#endif +} + +/* + * pmap_pagezeroidle: the same, for the idle loop page zero'er. + * Returns TRUE if the page was zero'd, FALSE if we aborted for + * some reason. + */ + +boolean_t +pmap_pageidlezero(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); +#ifdef MULTIPROCESSOR + int id = cpu_number(); +#endif + pt_entry_t *zpte = PTESLEW(zero_pte, id); + caddr_t zerova = VASLEW(zerop, id); + boolean_t rv = TRUE; + int *ptr; + unsigned int i; + +printf("pmap_pageidlezero()\n"); +#ifdef DIAGNOSTIC + if (*zpte) + panic("pmap_zero_page_uncached: lock botch"); +#endif + *zpte = (pa & PG_FRAME) | PG_V | PG_RW | PG_N; /* map in */ + pmap_update_pg((vaddr_t)zerova); /* flush TLB */ + for (i = 0, ptr = (int *) zerova; i < PAGE_SIZE / sizeof(int); i++) { + if (whichqs != 0) { + + /* + * A process has become ready. Abort now, + * so we don't keep it waiting while we + * do slow memory access to finish this + * page. + */ + + rv = FALSE; + break; + } + *ptr++ = 0; + } + +#ifdef DIAGNOSTIC + *zpte = 0; /* zap! */ +#endif + return (rv); +} + +/* + * pmap_copy_page: copy a page + */ + +void +pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg) +{ + paddr_t srcpa = VM_PAGE_TO_PHYS(srcpg); + paddr_t dstpa = VM_PAGE_TO_PHYS(dstpg); +#ifdef MULTIPROCESSOR + int id = cpu_number(); +#endif + pt_entry_t *spte = PTESLEW(csrc_pte,id); + pt_entry_t *dpte = PTESLEW(cdst_pte,id); + caddr_t csrcva = VASLEW(csrcp, id); + caddr_t cdstva = VASLEW(cdstp, id); + +#ifdef DIAGNOSTIC + if (*spte || *dpte) + panic("pmap_copy_page: lock botch"); +#endif + + *spte = (srcpa & PG_FRAME) | PG_V | PG_RW; + *dpte = (dstpa & PG_FRAME) | PG_V | PG_RW; + pmap_update_2pg((vaddr_t)csrcva, (vaddr_t)cdstva); + memcpy(cdstva, csrcva, PAGE_SIZE); +#ifdef DIAGNOSTIC + *spte = *dpte = 0; /* zap! */ +#endif +} + +/* + * p m a p r e m o v e f u n c t i o n s + * + * functions that remove mappings + */ + +/* + * pmap_remove_ptes: remove PTEs from a PTP + * + * => must have proper locking on pmap_master_lock + * => caller must hold pmap's lock + * => PTP must be mapped into KVA + * => PTP should be null if pmap == pmap_kernel() + */ + +void +pmap_remove_ptes(pmap, ptp, ptpva, startva, endva, cpumaskp, flags) + struct pmap *pmap; + struct vm_page *ptp; + vaddr_t ptpva; + vaddr_t startva, endva; + int32_t *cpumaskp; + int flags; +{ + struct pv_entry *pv_tofree = NULL; /* list of pv_entrys to free */ + struct pv_entry *pve; + pt_entry_t *pte = (pt_entry_t *) ptpva; + pt_entry_t opte; + int bank, off; + + /* + * note that ptpva points to the PTE that maps startva. this may + * or may not be the first PTE in the PTP. + * + * we loop through the PTP while there are still PTEs to look at + * and the wire_count is greater than 1 (because we use the wire_count + * to keep track of the number of real PTEs in the PTP). + */ + + for (/*null*/; startva < endva && (ptp == NULL || ptp->wire_count > 1) + ; pte++, startva += PAGE_SIZE) { + if (!pmap_valid_entry(*pte)) + continue; /* VA not mapped */ + if ((flags & PMAP_REMOVE_SKIPWIRED) && (*pte & PG_W)) { + continue; + } + + /* atomically save the old PTE and zap! it */ + opte = pmap_pte_set(pte, 0); + + if (opte & PG_W) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + pmap_tlb_shootdown(pmap, startva, opte, cpumaskp); + + if (ptp) + ptp->wire_count--; /* dropping a PTE */ + + /* + * if we are not on a pv_head list we are done. + */ + + if ((opte & PG_PVLIST) == 0) { +#ifdef DIAGNOSTIC + if (vm_physseg_find(btop(opte & PG_FRAME), &off) + != -1) + panic("pmap_remove_ptes: managed page without " + "PG_PVLIST for 0x%lx", startva); +#endif + continue; + } + + bank = vm_physseg_find(btop(opte & PG_FRAME), &off); +#ifdef DIAGNOSTIC + if (bank == -1) + panic("pmap_remove_ptes: unmanaged page marked " + "PG_PVLIST, va = 0x%lx, pa = 0x%lx", + startva, (u_long)(opte & PG_FRAME)); +#endif + + /* sync R/M bits */ + simple_lock(&vm_physmem[bank].pmseg.pvhead[off].pvh_lock); + vm_physmem[bank].pmseg.attrs[off] |= (opte & (PG_U|PG_M)); + pve = pmap_remove_pv(&vm_physmem[bank].pmseg.pvhead[off], pmap, + startva); + simple_unlock(&vm_physmem[bank].pmseg.pvhead[off].pvh_lock); + + if (pve) { + pve->pv_next = pv_tofree; + pv_tofree = pve; + } + + /* end of "for" loop: time for next pte */ + } + if (pv_tofree) + pmap_free_pvs(pmap, pv_tofree); +} + + +/* + * pmap_remove_pte: remove a single PTE from a PTP + * + * => must have proper locking on pmap_master_lock + * => caller must hold pmap's lock + * => PTP must be mapped into KVA + * => PTP should be null if pmap == pmap_kernel() + * => returns true if we removed a mapping + */ + +boolean_t +pmap_remove_pte(pmap, ptp, pte, va, cpumaskp, flags) + struct pmap *pmap; + struct vm_page *ptp; + pt_entry_t *pte; + vaddr_t va; + int32_t *cpumaskp; + int flags; +{ + pt_entry_t opte; + int bank, off; + struct pv_entry *pve; + + if (!pmap_valid_entry(*pte)) + return(FALSE); /* VA not mapped */ + if ((flags & PMAP_REMOVE_SKIPWIRED) && (*pte & PG_W)) { + return(FALSE); + } + + /* atomically save the old PTE and zap! it */ + opte = pmap_pte_set(pte, 0); + + if (opte & PG_W) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + if (ptp) + ptp->wire_count--; /* dropping a PTE */ + + pmap_tlb_shootdown(pmap, va, opte, cpumaskp); + + /* + * if we are not on a pv_head list we are done. + */ + + if ((opte & PG_PVLIST) == 0) { +#ifdef DIAGNOSTIC + if (vm_physseg_find(btop(opte & PG_FRAME), &off) != -1) { + printf("pmap_remove_pte: managed page without " + "PG_PVLIST for 0x%lx\n", va); + Debugger(); + } +#endif + return(TRUE); + } + + bank = vm_physseg_find(btop(opte & PG_FRAME), &off); +#ifdef DIAGNOSTIC + if (bank == -1) + panic("pmap_remove_pte: unmanaged page marked " + "PG_PVLIST, va = 0x%lx, pa = 0x%lx", va, + (u_long)(opte & PG_FRAME)); +#endif + + /* sync R/M bits */ + simple_lock(&vm_physmem[bank].pmseg.pvhead[off].pvh_lock); + vm_physmem[bank].pmseg.attrs[off] |= (opte & (PG_U|PG_M)); + pve = pmap_remove_pv(&vm_physmem[bank].pmseg.pvhead[off], pmap, va); + simple_unlock(&vm_physmem[bank].pmseg.pvhead[off].pvh_lock); + + if (pve) + pmap_free_pv(pmap, pve); + return(TRUE); +} + +/* + * pmap_remove: top level mapping removal function + * + * => caller should not be holding any pmap locks + */ + +void +pmap_remove(pmap, sva, eva) + struct pmap *pmap; + vaddr_t sva, eva; +{ + pmap_do_remove(pmap, sva, eva, PMAP_REMOVE_ALL); +} + +/* + * pmap_do_remove: mapping removal guts + * + * => caller should not be holding any pmap locks + */ + +void +pmap_do_remove(pmap, sva, eva, flags) + struct pmap *pmap; + vaddr_t sva, eva; + int flags; +{ + pt_entry_t *ptes; + pd_entry_t **pdes, pde; + boolean_t result; + paddr_t ptppa; + vaddr_t blkendva; + struct vm_page *ptp; + int32_t cpumask = 0; + + /* + * we lock in the pmap => pv_head direction + */ + + PMAP_MAP_TO_HEAD_LOCK(); + pmap_map_ptes(pmap, &ptes, &pdes); /* locks pmap */ + + /* + * removing one page? take shortcut function. + */ + + if (sva + PAGE_SIZE == eva) { + if (pmap_pdes_valid(sva, pdes, &pde)) { + + /* PA of the PTP */ + ptppa = pde & PG_FRAME; + + /* get PTP if non-kernel mapping */ + + if (pmap == pmap_kernel()) { + /* we never free kernel PTPs */ + ptp = NULL; + } else { + ptp = pmap_find_ptp(pmap, sva, ptppa, 1); +#ifdef DIAGNOSTIC + if (ptp == NULL) + panic("pmap_remove: unmanaged " + "PTP detected"); +#endif + } + + /* do it! */ + result = pmap_remove_pte(pmap, ptp, + &ptes[pl1_i(sva)], sva, &cpumask, flags); + + /* + * if mapping removed and the PTP is no longer + * being used, free it! + */ + + if (result && ptp && ptp->wire_count <= 1) + pmap_free_ptp(pmap, ptp, sva, ptes, pdes, + &cpumask); + } + + pmap_tlb_shootnow(cpumask); + pmap_unmap_ptes(pmap); /* unlock pmap */ + PMAP_MAP_TO_HEAD_UNLOCK(); + return; + } + + cpumask = 0; + + for (/* null */ ; sva < eva ; sva = blkendva) { + + /* determine range of block */ + blkendva = x86_round_pdr(sva+1); + if (blkendva > eva) + blkendva = eva; + + /* + * XXXCDC: our PTE mappings should never be removed + * with pmap_remove! if we allow this (and why would + * we?) then we end up freeing the pmap's page + * directory page (PDP) before we are finished using + * it when we hit in in the recursive mapping. this + * is BAD. + * + * long term solution is to move the PTEs out of user + * address space. and into kernel address space (up + * with APTE). then we can set VM_MAXUSER_ADDRESS to + * be VM_MAX_ADDRESS. + */ + + if (pl_i(sva, PTP_LEVELS) == PDIR_SLOT_PTE) + /* XXXCDC: ugly hack to avoid freeing PDP here */ + continue; + + if (!pmap_pdes_valid(sva, pdes, &pde)) + continue; + + /* PA of the PTP */ + ptppa = pde & PG_FRAME; + + /* get PTP if non-kernel mapping */ + if (pmap == pmap_kernel()) { + /* we never free kernel PTPs */ + ptp = NULL; + } else { + ptp = pmap_find_ptp(pmap, sva, ptppa, 1); +#ifdef DIAGNOSTIC + if (ptp == NULL) + panic("pmap_remove: unmanaged PTP " + "detected"); +#endif + } + pmap_remove_ptes(pmap, ptp, + (vaddr_t)&ptes[pl1_i(sva)], sva, blkendva, &cpumask, flags); + + /* if PTP is no longer being used, free it! */ + if (ptp && ptp->wire_count <= 1) { + pmap_free_ptp(pmap, ptp, sva, ptes,pdes, + &cpumask); + } + } + + pmap_tlb_shootnow(cpumask); + pmap_unmap_ptes(pmap); + PMAP_MAP_TO_HEAD_UNLOCK(); +} + +/* + * pmap_page_remove: remove a managed vm_page from all pmaps that map it + * + * => we set pv_head => pmap locking + * => R/M bits are sync'd back to attrs + */ + +void +pmap_page_remove(pg) + struct vm_page *pg; +{ + int bank, off; + struct pv_head *pvh; + struct pv_entry *pve, *npve, **prevptr, *killlist = NULL; + pt_entry_t *ptes, opte; + pd_entry_t **pdes; +#ifdef DIAGNOSTIC + pd_entry_t pde; +#endif + int32_t cpumask = 0; + + /* XXX: vm_page should either contain pv_head or have a pointer to it */ + bank = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), &off); + if (bank == -1) { + printf("pmap_page_remove: unmanaged page?\n"); + return; + } + + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + if (pvh->pvh_list == NULL) { + return; + } + + /* set pv_head => pmap locking */ + PMAP_HEAD_TO_MAP_LOCK(); + + /* XXX: needed if we hold head->map lock? */ + simple_lock(&pvh->pvh_lock); + + for (prevptr = &pvh->pvh_list, pve = pvh->pvh_list; + pve != NULL; pve = npve) { + npve = pve->pv_next; + pmap_map_ptes(pve->pv_pmap, &ptes, &pdes); /* locks pmap */ + +#ifdef DIAGNOSTIC + if (pve->pv_ptp && pmap_pdes_valid(pve->pv_va, pdes, &pde) && + (pde & PG_FRAME) != VM_PAGE_TO_PHYS(pve->pv_ptp)) { + printf("pmap_page_remove: pg=%p: va=%lx, pv_ptp=%p\n", + pg, pve->pv_va, pve->pv_ptp); + printf("pmap_page_remove: PTP's phys addr: " + "actual=%lx, recorded=%lx\n", + (unsigned long)(pde & PG_FRAME), + VM_PAGE_TO_PHYS(pve->pv_ptp)); + panic("pmap_page_remove: mapped managed page has " + "invalid pv_ptp field"); + } +#endif + + /* atomically save the old PTE and zap! it */ + opte = pmap_pte_set(&ptes[pl1_i(pve->pv_va)], 0); + + if (opte & PG_W) + pve->pv_pmap->pm_stats.wired_count--; + pve->pv_pmap->pm_stats.resident_count--; + + pmap_tlb_shootdown(pve->pv_pmap, pve->pv_va, opte, &cpumask); + + /* sync R/M bits */ + vm_physmem[bank].pmseg.attrs[off] |= (opte & (PG_U|PG_M)); + + /* update the PTP reference count. free if last reference. */ + if (pve->pv_ptp) { + pve->pv_ptp->wire_count--; + if (pve->pv_ptp->wire_count <= 1) { + pmap_free_ptp(pve->pv_pmap, pve->pv_ptp, + pve->pv_va, ptes, pdes, &cpumask); + } + } + pmap_unmap_ptes(pve->pv_pmap); /* unlocks pmap */ + *prevptr = npve; /* remove it */ + pve->pv_next = killlist; /* mark it for death */ + killlist = pve; + } + pmap_free_pvs(NULL, killlist); + pvh->pvh_list = NULL; + simple_unlock(&pvh->pvh_lock); + PMAP_HEAD_TO_MAP_UNLOCK(); + pmap_tlb_shootnow(cpumask); +} + +/* + * p m a p a t t r i b u t e f u n c t i o n s + * functions that test/change managed page's attributes + * since a page can be mapped multiple times we must check each PTE that + * maps it by going down the pv lists. + */ + +/* + * pmap_test_attrs: test a page's attributes + * + * => we set pv_head => pmap locking + */ + +boolean_t +pmap_test_attrs(pg, testbits) + struct vm_page *pg; + unsigned testbits; +{ + int bank, off; + unsigned char *myattrs; + struct pv_head *pvh; + struct pv_entry *pve; + pt_entry_t *ptes, pte; + pd_entry_t **pdes; + + /* XXX: vm_page should either contain pv_head or have a pointer to it */ + bank = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), &off); + if (bank == -1) { + printf("pmap_test_attrs: unmanaged page?\n"); + return(FALSE); + } + + /* + * before locking: see if attributes are already set and if so, + * return! + */ + + myattrs = &vm_physmem[bank].pmseg.attrs[off]; + if (*myattrs & testbits) + return(TRUE); + + /* test to see if there is a list before bothering to lock */ + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + if (pvh->pvh_list == NULL) { + return(FALSE); + } + + /* nope, gonna have to do it the hard way */ + PMAP_HEAD_TO_MAP_LOCK(); + /* XXX: needed if we hold head->map lock? */ + simple_lock(&pvh->pvh_lock); + + for (pve = pvh->pvh_list; pve != NULL && (*myattrs & testbits) == 0; + pve = pve->pv_next) { + pmap_map_ptes(pve->pv_pmap, &ptes, &pdes); + pte = ptes[pl1_i(pve->pv_va)]; + pmap_unmap_ptes(pve->pv_pmap); + *myattrs |= pte; + } + + /* + * note that we will exit the for loop with a non-null pve if + * we have found the bits we are testing for. + */ + + simple_unlock(&pvh->pvh_lock); + PMAP_HEAD_TO_MAP_UNLOCK(); + return((*myattrs & testbits) != 0); +} + +/* + * pmap_clear_attrs: change a page's attributes + * + * => we set pv_head => pmap locking + * => we return TRUE if we cleared one of the bits we were asked to + */ + +boolean_t +pmap_clear_attrs(pg, clearbits) + struct vm_page *pg; + unsigned clearbits; +{ + int bank, off; + unsigned result; + struct pv_head *pvh; + struct pv_entry *pve; + pt_entry_t *ptes, opte; + pd_entry_t **pdes; + unsigned char *myattrs; + int32_t cpumask = 0; + + /* XXX: vm_page should either contain pv_head or have a pointer to it */ + bank = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), &off); + if (bank == -1) { + printf("pmap_change_attrs: unmanaged page?\n"); + return(FALSE); + } + + PMAP_HEAD_TO_MAP_LOCK(); + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + /* XXX: needed if we hold head->map lock? */ + simple_lock(&pvh->pvh_lock); + + myattrs = &vm_physmem[bank].pmseg.attrs[off]; + result = *myattrs & clearbits; + *myattrs &= ~clearbits; + + for (pve = pvh->pvh_list; pve != NULL; pve = pve->pv_next) { + pmap_map_ptes(pve->pv_pmap, &ptes, &pdes); /* locks pmap */ +#ifdef DIAGNOSTIC + if (!pmap_pdes_valid(pve->pv_va, pdes, NULL)) + panic("pmap_change_attrs: mapping without PTP " + "detected"); +#endif + + opte = ptes[pl1_i(pve->pv_va)]; + if (opte & clearbits) { + result |= (opte & clearbits); + pmap_pte_clearbits(&ptes[pl1_i(pve->pv_va)], + (opte & clearbits)); + pmap_tlb_shootdown(pve->pv_pmap, pve->pv_va, opte, + &cpumask); + } + pmap_unmap_ptes(pve->pv_pmap); /* unlocks pmap */ + } + + simple_unlock(&pvh->pvh_lock); + PMAP_HEAD_TO_MAP_UNLOCK(); + + pmap_tlb_shootnow(cpumask); + + return(result != 0); +} + +/* + * p m a p p r o t e c t i o n f u n c t i o n s + */ + +/* + * pmap_page_protect: change the protection of all recorded mappings + * of a managed page + * + * => NOTE: this is an inline function in pmap.h + */ + +/* see pmap.h */ + +/* + * pmap_protect: set the protection in of the pages in a pmap + * + * => NOTE: this is an inline function in pmap.h + */ + +/* see pmap.h */ + +/* + * pmap_write_protect: write-protect pages in a pmap + */ + +void +pmap_write_protect(pmap, sva, eva, prot) + struct pmap *pmap; + vaddr_t sva, eva; + vm_prot_t prot; +{ + pt_entry_t *ptes, *spte, *epte; + pd_entry_t **pdes; + vaddr_t blockend; + int32_t cpumask = 0; + + pmap_map_ptes(pmap, &ptes, &pdes); /* locks pmap */ + + /* should be ok, but just in case ... */ + sva &= PG_FRAME; + eva &= PG_FRAME; + + for (/* null */ ; sva < eva ; sva = blockend) { + + blockend = (sva & L2_FRAME) + NBPD_L2; + if (blockend > eva) + blockend = eva; + + /* + * XXXCDC: our PTE mappings should never be write-protected! + * + * long term solution is to move the PTEs out of user + * address space. and into kernel address space (up + * with APTE). then we can set VM_MAXUSER_ADDRESS to + * be VM_MAX_ADDRESS. + */ + + /* XXXCDC: ugly hack to avoid freeing PDP here */ + if (pl_i(sva, PTP_LEVELS) == PDIR_SLOT_PTE) + continue; + + /* empty block? */ + if (!pmap_pdes_valid(sva, pdes, NULL)) + continue; + +#ifdef DIAGNOSTIC + if (sva >= VM_MAXUSER_ADDRESS && + sva < VM_MAX_ADDRESS) + panic("pmap_write_protect: PTE space"); +#endif + + spte = &ptes[pl1_i(sva)]; + epte = &ptes[pl1_i(blockend)]; + + for (/*null */; spte < epte ; spte++) { + if ((*spte & (PG_RW|PG_V)) == (PG_RW|PG_V)) { + pmap_pte_clearbits(spte, PG_RW); + pmap_tlb_shootdown(pmap, ptob(spte - ptes), + *spte, &cpumask); + } + } + } + + pmap_tlb_shootnow(cpumask); + pmap_unmap_ptes(pmap); /* unlocks pmap */ +} + +/* + * end of protection functions + */ + +/* + * pmap_unwire: clear the wired bit in the PTE + * + * => mapping should already be in map + */ + +void +pmap_unwire(pmap, va) + struct pmap *pmap; + vaddr_t va; +{ + pt_entry_t *ptes; + pd_entry_t **pdes; + + pmap_map_ptes(pmap, &ptes, &pdes); /* locks pmap */ + + if (pmap_pdes_valid(va, pdes, NULL)) { + +#ifdef DIAGNOSTIC + if (!pmap_valid_entry(ptes[pl1_i(va)])) + panic("pmap_unwire: invalid (unmapped) va 0x%lx", va); +#endif + if ((ptes[pl1_i(va)] & PG_W) != 0) { + ptes[pl1_i(va)] &= ~PG_W; + pmap->pm_stats.wired_count--; + } +#ifdef DIAGNOSTIC + else { + printf("pmap_unwire: wiring for pmap %p va 0x%lx " + "didn't change!\n", pmap, va); + } +#endif + pmap_unmap_ptes(pmap); /* unlocks map */ + } +#ifdef DIAGNOSTIC + else { + panic("pmap_unwire: invalid PDE"); + } +#endif +} + +/* + * pmap_collect: free resources held by a pmap + * + * => optional function. + * => called when a process is swapped out to free memory. + */ + +void +pmap_collect(pmap) + struct pmap *pmap; +{ + /* + * free all of the pt pages by removing the physical mappings + * for its entire address space. + */ + +/* pmap_do_remove(pmap, VM_MIN_ADDRESS, VM_MAX_ADDRESS, + PMAP_REMOVE_SKIPWIRED); +*/ +} + +/* + * pmap_copy: copy mappings from one pmap to another + * + * => optional function + * void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) + */ + +/* + * defined as macro in pmap.h + */ + +/* + * pmap_enter: enter a mapping into a pmap + * + * => must be done "now" ... no lazy-evaluation + * => we set pmap => pv_head locking + */ + +int +pmap_enter(pmap, va, pa, prot, flags) + struct pmap *pmap; + vaddr_t va; + paddr_t pa; + vm_prot_t prot; + int flags; +{ + pt_entry_t *ptes, opte, npte; + pd_entry_t **pdes; + struct vm_page *ptp; + struct pv_head *pvh; + struct pv_entry *pve; + int bank, off, error; + int ptpdelta, wireddelta, resdelta; + boolean_t wired = (flags & PMAP_WIRED) != 0; + +#ifdef DIAGNOSTIC + /* sanity check: totally out of range? */ + if (va >= VM_MAX_KERNEL_ADDRESS) + panic("pmap_enter: too big"); + + if (va == (vaddr_t) PDP_BASE || va == (vaddr_t) APDP_BASE) + panic("pmap_enter: trying to map over PDP/APDP!"); + + /* sanity check: kernel PTPs should already have been pre-allocated */ + if (va >= VM_MIN_KERNEL_ADDRESS && + !pmap_valid_entry(pmap->pm_pdir[pl_i(va, PTP_LEVELS)])) + panic("pmap_enter: missing kernel PTP for va %lx!", va); + +#endif + + /* get lock */ + PMAP_MAP_TO_HEAD_LOCK(); + + /* + * map in ptes and get a pointer to our PTP (unless we are the kernel) + */ + + pmap_map_ptes(pmap, &ptes, &pdes); /* locks pmap */ + if (pmap == pmap_kernel()) { + ptp = NULL; + } else { + ptp = pmap_get_ptp(pmap, va, pdes); + if (ptp == NULL) { + if (flags & PMAP_CANFAIL) { + error = ENOMEM; + goto out; + } + panic("pmap_enter: get ptp failed"); + } + } + opte = ptes[pl1_i(va)]; /* old PTE */ + + /* + * is there currently a valid mapping at our VA? + */ + + if (pmap_valid_entry(opte)) { + /* + * first, calculate pm_stats updates. resident count will not + * change since we are replacing/changing a valid mapping. + * wired count might change... + */ + + resdelta = 0; + if (wired && (opte & PG_W) == 0) + wireddelta = 1; + else if (!wired && (opte & PG_W) != 0) + wireddelta = -1; + else + wireddelta = 0; + ptpdelta = 0; + + /* + * is the currently mapped PA the same as the one we + * want to map? + */ + + if ((opte & PG_FRAME) == pa) { + + /* if this is on the PVLIST, sync R/M bit */ + if (opte & PG_PVLIST) { + bank = vm_physseg_find(atop(pa), &off); +#ifdef DIAGNOSTIC + if (bank == -1) + panic("pmap_enter: same pa PG_PVLIST " + "mapping with unmanaged page " + "pa = 0x%lx (0x%lx)", pa, + atop(pa)); +#endif + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + simple_lock(&pvh->pvh_lock); + vm_physmem[bank].pmseg.attrs[off] |= opte; + simple_unlock(&pvh->pvh_lock); + } else { + pvh = NULL; /* ensure !PG_PVLIST */ + } + goto enter_now; + } + + /* + * changing PAs: we must remove the old one first + */ + + /* + * if current mapping is on a pvlist, + * remove it (sync R/M bits) + */ + + if (opte & PG_PVLIST) { + bank = vm_physseg_find(atop(opte & PG_FRAME), &off); +#ifdef DIAGNOSTIC + if (bank == -1) + panic("pmap_enter: PG_PVLIST mapping with " + "unmanaged page " + "pa = 0x%lx (0x%lx)", pa, atop(pa)); +#endif + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + simple_lock(&pvh->pvh_lock); + pve = pmap_remove_pv(pvh, pmap, va); + vm_physmem[bank].pmseg.attrs[off] |= opte; + simple_unlock(&pvh->pvh_lock); + } else { + pve = NULL; + } + } else { /* opte not valid */ + pve = NULL; + resdelta = 1; + if (wired) + wireddelta = 1; + else + wireddelta = 0; + if (ptp) + ptpdelta = 1; + else + ptpdelta = 0; + } + + /* + * pve is either NULL or points to a now-free pv_entry structure + * (the latter case is if we called pmap_remove_pv above). + * + * if this entry is to be on a pvlist, enter it now. + */ + + bank = vm_physseg_find(atop(pa), &off); + if (pmap_initialized && bank != -1) { + pvh = &vm_physmem[bank].pmseg.pvhead[off]; + if (pve == NULL) { + pve = pmap_alloc_pv(pmap, ALLOCPV_NEED); + if (pve == NULL) { + if (flags & PMAP_CANFAIL) { + error = ENOMEM; + goto out; + } + panic("pmap_enter: no pv entries available"); + } + } + /* lock pvh when adding */ + pmap_enter_pv(pvh, pve, pmap, va, ptp); + } else { + + /* new mapping is not PG_PVLIST. free pve if we've got one */ + pvh = NULL; /* ensure !PG_PVLIST */ + if (pve) + pmap_free_pv(pmap, pve); + } + +enter_now: + /* + * at this point pvh is !NULL if we want the PG_PVLIST bit set + */ + + pmap->pm_stats.resident_count += resdelta; + pmap->pm_stats.wired_count += wireddelta; + if (ptp) + ptp->wire_count += ptpdelta; + npte = pa | protection_codes[prot] | PG_V; + if (pvh) + npte |= PG_PVLIST; + if (wired) + npte |= PG_W; + if (va < VM_MAXUSER_ADDRESS) + npte |= PG_u; + else if (va < VM_MAX_ADDRESS) + npte |= (PG_u | PG_RW); /* XXXCDC: no longer needed? */ + if (pmap == pmap_kernel()) + npte |= pmap_pg_g; + + ptes[pl1_i(va)] = npte; /* zap! */ + + /* + * If we changed anything other than modified/used bits, + * flush the TLB. (is this overkill?) + */ + if ((opte & ~(PG_M|PG_U)) != npte) { +#if defined(MULTIPROCESSOR) + int32_t cpumask = 0; + + pmap_tlb_shootdown(pmap, va, opte, &cpumask); + pmap_tlb_shootnow(cpumask); +#else + /* Don't bother deferring in the single CPU case. */ + if (pmap_is_curpmap(pmap)) + pmap_update_pg(va); +#endif + } + + error = 0; + +out: + pmap_unmap_ptes(pmap); + PMAP_MAP_TO_HEAD_UNLOCK(); + + return error; +} + +boolean_t +pmap_get_physpage(va, level, paddrp) + vaddr_t va; + int level; + paddr_t *paddrp; +{ + struct vm_page *ptp; + struct pmap *kpm = pmap_kernel(); + + if (uvm.page_init_done == FALSE) { + /* + * we're growing the kernel pmap early (from + * uvm_pageboot_alloc()). this case must be + * handled a little differently. + */ + + if (uvm_page_physget(paddrp) == FALSE) + panic("pmap_get_physpage: out of memory"); + *early_zero_pte = (*paddrp & PG_FRAME) | PG_V | PG_RW; + pmap_update_pg((vaddr_t)early_zerop); + memset(early_zerop, 0, PAGE_SIZE); + } else { + ptp = uvm_pagealloc(&kpm->pm_obj[level - 1], + ptp_va2o(va, level), NULL, + UVM_PGA_USERESERVE|UVM_PGA_ZERO); + if (ptp == NULL) + panic("pmap_get_physpage: out of memory"); + ptp->flags &= ~PG_BUSY; + ptp->wire_count = 1; + *paddrp = VM_PAGE_TO_PHYS(ptp); + } + kpm->pm_stats.resident_count++; + return TRUE; +} + +/* + * Allocate the amount of specified ptps for a ptp level, and populate + * all levels below accordingly, mapping virtual addresses starting at + * kva. + * + * Used by pmap_growkernel. + */ +void +pmap_alloc_level(pdes, kva, lvl, needed_ptps) + pd_entry_t **pdes; + vaddr_t kva; + int lvl; + long *needed_ptps; +{ + unsigned long i; + vaddr_t va; + paddr_t pa; + unsigned long index, endindex; + int level; + pd_entry_t *pdep; + + for (level = lvl; level > 1; level--) { + if (level == PTP_LEVELS) + pdep = pmap_kernel()->pm_pdir; + else + pdep = pdes[level - 2]; + va = kva; + index = pl_i(kva, level); + endindex = index + needed_ptps[level - 1]; + /* + * XXX special case for first time call. + */ + if (nkptp[level - 1] != 0) + index++; + else + endindex--; + + for (i = index; i <= endindex; i++) { + pmap_get_physpage(va, level - 1, &pa); + pdep[i] = pa | PG_RW | PG_V; + nkptp[level - 1]++; + va += nbpd[level - 1]; + } + } +} + +/* + * pmap_growkernel: increase usage of KVM space + * + * => we allocate new PTPs for the kernel and install them in all + * the pmaps on the system. + */ + +static vaddr_t pmap_maxkvaddr = VM_MIN_KERNEL_ADDRESS; + +vaddr_t +pmap_growkernel(maxkvaddr) + vaddr_t maxkvaddr; +{ + struct pmap *kpm = pmap_kernel(), *pm; + int s, i; + unsigned newpdes; + long needed_kptp[PTP_LEVELS], target_nptp, old; + + if (maxkvaddr <= pmap_maxkvaddr) + return pmap_maxkvaddr; + + maxkvaddr = round_pdr(maxkvaddr); + old = nkptp[PTP_LEVELS - 1]; + /* + * This loop could be optimized more, but pmap_growkernel() + * is called infrequently. + */ + for (i = PTP_LEVELS - 1; i >= 1; i--) { + target_nptp = pl_i(maxkvaddr, i + 1) - + pl_i(VM_MIN_KERNEL_ADDRESS, i + 1); + /* + * XXX only need to check toplevel. + */ + if (target_nptp > nkptpmax[i]) + panic("out of KVA space"); + needed_kptp[i] = target_nptp - nkptp[i] + 1; + } + + + s = splhigh(); /* to be safe */ + simple_lock(&kpm->pm_lock); + pmap_alloc_level(normal_pdes, pmap_maxkvaddr, PTP_LEVELS, + needed_kptp); + + /* + * If the number of top level entries changed, update all + * pmaps. + */ + if (needed_kptp[PTP_LEVELS - 1] != 0) { + newpdes = nkptp[PTP_LEVELS - 1] - old; + simple_lock(&pmaps_lock); + LIST_FOREACH(pm, &pmaps, pm_list) { + memcpy(&pm->pm_pdir[PDIR_SLOT_KERN + old], + &kpm->pm_pdir[PDIR_SLOT_KERN + old], + newpdes * sizeof (pd_entry_t)); + } + + /* Invalidate the PDP cache. */ + pool_cache_invalidate(&pmap_pdp_cache); + pmap_pdp_cache_generation++; + + simple_unlock(&pmaps_lock); + } + pmap_maxkvaddr = maxkvaddr; + simple_unlock(&kpm->pm_lock); + splx(s); + + return maxkvaddr; +} + +#ifdef DEBUG +void pmap_dump(struct pmap *, vaddr_t, vaddr_t); + +/* + * pmap_dump: dump all the mappings from a pmap + * + * => caller should not be holding any pmap locks + */ + +void +pmap_dump(pmap, sva, eva) + struct pmap *pmap; + vaddr_t sva, eva; +{ + pt_entry_t *ptes, *pte; + pd_entry_t **pdes; + vaddr_t blkendva; + + /* + * if end is out of range truncate. + * if (end == start) update to max. + */ + + if (eva > VM_MAXUSER_ADDRESS || eva <= sva) + eva = VM_MAXUSER_ADDRESS; + + /* + * we lock in the pmap => pv_head direction + */ + + PMAP_MAP_TO_HEAD_LOCK(); + pmap_map_ptes(pmap, &ptes, &pdes); /* locks pmap */ + + /* + * dumping a range of pages: we dump in PTP sized blocks (4MB) + */ + + for (/* null */ ; sva < eva ; sva = blkendva) { + + /* determine range of block */ + blkendva = round_pdr(sva+1); + if (blkendva > eva) + blkendva = eva; + + /* valid block? */ + if (!pmap_pdes_valid(sva, pdes, NULL)) + continue; + + pte = &ptes[pl1_i(sva)]; + for (/* null */; sva < blkendva ; sva += PAGE_SIZE, pte++) { + if (!pmap_valid_entry(*pte)) + continue; + printf("va %#lx -> pa %#lx (pte=%#lx)\n", + sva, *pte, *pte & PG_FRAME); + } + } + pmap_unmap_ptes(pmap); + PMAP_MAP_TO_HEAD_UNLOCK(); +} +#endif + +/******************** TLB shootdown code ********************/ + + +void +pmap_tlb_shootnow(int32_t cpumask) +{ +#ifdef MULTIPROCESSOR + struct cpu_info *ci, *self; + CPU_INFO_ITERATOR cii; + int s; +#ifdef DIAGNOSTIC + int count = 0; +#endif +#endif + + if (cpumask == 0) + return; + +#ifdef MULTIPROCESSOR + self = curcpu(); + s = splipi(); + self->ci_tlb_ipi_mask = cpumask; +#endif + + pmap_do_tlb_shootdown(0); /* do *our* work. */ + +#ifdef MULTIPROCESSOR + splx(s); + + /* + * Send the TLB IPI to other CPUs pending shootdowns. + */ + for (CPU_INFO_FOREACH(cii, ci)) { + if (ci == self) + continue; + if (cpumask & (1U << ci->ci_cpuid)) + if (x86_send_ipi(ci, X86_IPI_TLB) != 0) + x86_atomic_clearbits_ul(&self->ci_tlb_ipi_mask, + (1U << ci->ci_cpuid)); + } + + while (self->ci_tlb_ipi_mask != 0) +#ifdef DIAGNOSTIC + if (count++ > 10000000) + panic("TLB IPI rendezvous failed (mask %x)", + self->ci_tlb_ipi_mask); +#else + /* XXX insert pause instruction */ + ; +#endif +#endif +} + +/* + * pmap_tlb_shootdown: + * + * Cause the TLB entry for pmap/va to be shot down. + */ +void +pmap_tlb_shootdown(pmap, va, pte, cpumaskp) + pmap_t pmap; + vaddr_t va; + pt_entry_t pte; + int32_t *cpumaskp; +{ + struct cpu_info *ci, *self = curcpu(); + struct pmap_tlb_shootdown_q *pq; + struct pmap_tlb_shootdown_job *pj; + CPU_INFO_ITERATOR cii; + int s; + +#ifdef LARGEPAGES + if (pte & PG_PS) + va &= PG_LGFRAME; +#endif + + if (pmap_initialized == FALSE || cpus_attached == 0) { + pmap_update_pg(va); + return; + } + + s = splipi(); +#if 0 + printf("dshootdown %lx\n", va); +#endif + + for (CPU_INFO_FOREACH(cii, ci)) { + /* Note: we queue shootdown events for ourselves here! */ + if (pmap_is_active(pmap, ci->ci_cpuid) == 0) + continue; + if (ci != self && !(ci->ci_flags & CPUF_RUNNING)) + continue; + pq = &pmap_tlb_shootdown_q[ci->ci_cpuid]; +#if defined(MULTIPROCESSOR) + simple_lock(&pq->pq_slock); +#endif + + /* + * If there's a global flush already queued, or a + * non-global flush, and this pte doesn't have the G + * bit set, don't bother. + */ + if (pq->pq_flushg > 0 || + (pq->pq_flushu > 0 && (pte & pmap_pg_g) == 0)) { +#if defined(MULTIPROCESSOR) + simple_unlock(&pq->pq_slock); +#endif + continue; + } + +#ifdef I386_CPU + /* + * i386 CPUs can't invalidate a single VA, only + * flush the entire TLB, so don't bother allocating + * jobs for them -- just queue a `flushu'. + * + * XXX note that this can be executed for non-i386 + * when called * early (before identifycpu() has set + * cpu_class) + */ + if (cpu_class == CPUCLASS_386) { + pq->pq_flushu++; + *cpumaskp |= 1U << ci->ci_cpuid; + continue; + } +#endif + + pj = pmap_tlb_shootdown_job_get(pq); + pq->pq_pte |= pte; + if (pj == NULL) { + /* + * Couldn't allocate a job entry. + * Kill it now for this cpu, unless the failure + * was due to too many pending flushes; otherwise, + * tell other cpus to kill everything.. + */ + if (ci == self && pq->pq_count < PMAP_TLB_MAXJOBS) { + pmap_update_pg(va); +#if defined(MULTIPROCESSOR) + simple_unlock(&pq->pq_slock); +#endif + continue; + } else { + if (pq->pq_pte & pmap_pg_g) + pq->pq_flushg++; + else + pq->pq_flushu++; + /* + * Since we've nailed the whole thing, + * drain the job entries pending for that + * processor. + */ + pmap_tlb_shootdown_q_drain(pq); + *cpumaskp |= 1U << ci->ci_cpuid; + } + } else { + pj->pj_pmap = pmap; + pj->pj_va = va; + pj->pj_pte = pte; + TAILQ_INSERT_TAIL(&pq->pq_head, pj, pj_list); + *cpumaskp |= 1U << ci->ci_cpuid; + } +#if defined(MULTIPROCESSOR) + simple_unlock(&pq->pq_slock); +#endif + } + splx(s); +} + +/* + * pmap_do_tlb_shootdown: + * + * Process pending TLB shootdown operations for this processor. + */ +void +pmap_do_tlb_shootdown(struct cpu_info *self) +{ + u_long cpu_id = cpu_number(); + struct pmap_tlb_shootdown_q *pq = &pmap_tlb_shootdown_q[cpu_id]; + struct pmap_tlb_shootdown_job *pj; + int s; +#ifdef MULTIPROCESSOR + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; +#endif + + s = splipi(); + +#ifdef MULTIPROCESSOR + simple_lock(&pq->pq_slock); +#endif + + if (pq->pq_flushg) { + COUNT(flushg); + tlbflushg(); + pq->pq_flushg = 0; + pq->pq_flushu = 0; + pmap_tlb_shootdown_q_drain(pq); + } else { + /* + * TLB flushes for PTEs with PG_G set may be in the queue + * after a flushu, they need to be dealt with. + */ + if (pq->pq_flushu) { + COUNT(flushu); + tlbflush(); + } + while ((pj = TAILQ_FIRST(&pq->pq_head)) != NULL) { + TAILQ_REMOVE(&pq->pq_head, pj, pj_list); + + if ((!pq->pq_flushu && pmap_is_curpmap(pj->pj_pmap)) || + (pj->pj_pte & pmap_pg_g)) + pmap_update_pg(pj->pj_va); + + pmap_tlb_shootdown_job_put(pq, pj); + } + + pq->pq_flushu = pq->pq_pte = 0; + } + +#ifdef MULTIPROCESSOR + for (CPU_INFO_FOREACH(cii, ci)) + x86_atomic_clearbits_ul(&ci->ci_tlb_ipi_mask, + (1U << cpu_id)); + simple_unlock(&pq->pq_slock); +#endif + + splx(s); +} + + +/* + * pmap_tlb_shootdown_q_drain: + * + * Drain a processor's TLB shootdown queue. We do not perform + * the shootdown operations. This is merely a convenience + * function. + * + * Note: We expect the queue to be locked. + */ +void +pmap_tlb_shootdown_q_drain(pq) + struct pmap_tlb_shootdown_q *pq; +{ + struct pmap_tlb_shootdown_job *pj; + + while ((pj = TAILQ_FIRST(&pq->pq_head)) != NULL) { + TAILQ_REMOVE(&pq->pq_head, pj, pj_list); + pmap_tlb_shootdown_job_put(pq, pj); + } + pq->pq_pte = 0; +} + +/* + * pmap_tlb_shootdown_job_get: + * + * Get a TLB shootdown job queue entry. This places a limit on + * the number of outstanding jobs a processor may have. + * + * Note: We expect the queue to be locked. + */ +struct pmap_tlb_shootdown_job * +pmap_tlb_shootdown_job_get(pq) + struct pmap_tlb_shootdown_q *pq; +{ + struct pmap_tlb_shootdown_job *pj; + + if (pq->pq_count >= PMAP_TLB_MAXJOBS) + return (NULL); + +#ifdef MULTIPROCESSOR + simple_lock(&pmap_tlb_shootdown_job_lock); +#endif + if (pj_free == NULL) { +#ifdef MULTIPROCESSOR + simple_unlock(&pmap_tlb_shootdown_job_lock); +#endif + return NULL; + } + pj = &pj_free->pja_job; + pj_free = + (union pmap_tlb_shootdown_job_al *)pj_free->pja_job.pj_nextfree; +#ifdef MULTIPROCESSOR + simple_unlock(&pmap_tlb_shootdown_job_lock); +#endif + + pq->pq_count++; + return (pj); +} + +/* + * pmap_tlb_shootdown_job_put: + * + * Put a TLB shootdown job queue entry onto the free list. + * + * Note: We expect the queue to be locked. + */ +void +pmap_tlb_shootdown_job_put(pq, pj) + struct pmap_tlb_shootdown_q *pq; + struct pmap_tlb_shootdown_job *pj; +{ + +#ifdef DIAGNOSTIC + if (pq->pq_count == 0) + panic("pmap_tlb_shootdown_job_put: queue length inconsistency"); +#endif +#ifdef MULTIPROCESSOR + simple_lock(&pmap_tlb_shootdown_job_lock); +#endif + pj->pj_nextfree = &pj_free->pja_job; + pj_free = (union pmap_tlb_shootdown_job_al *)pj; +#ifdef MULTIPROCESSOR + simple_unlock(&pmap_tlb_shootdown_job_lock); +#endif + + pq->pq_count--; +} + +void +pmap_virtual_space(vaddr_t *vstartp, vaddr_t *vendp) +{ + *vstartp = virtual_avail; + *vendp = VM_MAX_KERNEL_ADDRESS; +} diff --git a/sys/arch/amd64/amd64/process_machdep.c b/sys/arch/amd64/amd64/process_machdep.c new file mode 100644 index 00000000000..cb8650eb822 --- /dev/null +++ b/sys/arch/amd64/amd64/process_machdep.c @@ -0,0 +1,193 @@ +/* $OpenBSD: process_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: process_machdep.c,v 1.1 2003/04/26 18:39:31 fvdl Exp $ */ + +/*- + * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +/* + * This file may seem a bit stylized, but that so that it's easier to port. + * Functions to be implemented here are: + * + * process_read_regs(proc, regs) + * Get the current user-visible register set from the process + * and copy it into the regs structure (<machine/reg.h>). + * The process is stopped at the time read_regs is called. + * + * process_write_regs(proc, regs) + * Update the current register set from the passed in regs + * structure. Take care to avoid clobbering special CPU + * registers or privileged bits in the PSL. + * The process is stopped at the time write_regs is called. + * + * process_sstep(proc) + * Arrange for the process to trap after executing a single instruction. + * + * process_set_pc(proc) + * Set the process's program counter. + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/vnode.h> +#include <sys/ptrace.h> + +#include <uvm/uvm_extern.h> + +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/segments.h> +#include <machine/fpu.h> + +static __inline struct trapframe *process_frame(struct proc *); +static __inline struct fxsave64 *process_fpframe(struct proc *); +#if 0 +static __inline int verr_gdt(struct pmap *, int sel); +static __inline int verr_ldt(struct pmap *, int sel); +#endif + +static __inline struct trapframe * +process_frame(struct proc *p) +{ + + return (p->p_md.md_regs); +} + +static __inline struct fxsave64 * +process_fpframe(struct proc *p) +{ + + return (&p->p_addr->u_pcb.pcb_savefpu.fp_fxsave); +} + +int +process_read_regs(struct proc *p, struct reg *regs) +{ + struct trapframe *tf = process_frame(p); + + memcpy(regs, tf, sizeof (*regs)); + + return (0); +} + +int +process_read_fpregs(struct proc *p, struct fpreg *regs) +{ + struct fxsave64 *frame = process_fpframe(p); + + if (p->p_md.md_flags & MDP_USEDFPU) { + fpusave_proc(p, 1); + } else { + u_int16_t cw; + + /* + * Fake a FNINIT. + * The initial control word was already set by setregs(), so + * save it temporarily. + */ + cw = frame->fx_fcw; + memset(frame, 0, sizeof(*regs)); + frame->fx_fcw = cw; + frame->fx_fsw = 0x0000; + frame->fx_ftw = 0xff; + p->p_md.md_flags |= MDP_USEDFPU; + } + + memcpy(®s->fxstate, frame, sizeof(*regs)); + return (0); +} + +int +process_write_regs(struct proc *p, struct reg *regp) +{ + struct trapframe *tf = process_frame(p); + long *regs = regp->regs; + + /* + * Check for security violations. + */ + if (((regs[_REG_RFL] ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 || + !USERMODE(regs[_REG_CS], regs[_REG_RFL])) + return (EINVAL); + + memcpy(tf, regs, sizeof (*tf)); + + return (0); +} + +int +process_write_fpregs(struct proc *p, struct fpreg *regs) +{ + struct fxsave64 *frame = process_fpframe(p); + + if (p->p_md.md_flags & MDP_USEDFPU) { + fpusave_proc(p, 0); + } else { + p->p_md.md_flags |= MDP_USEDFPU; + } + + memcpy(frame, ®s->fxstate, sizeof(*regs)); + return (0); +} + +int +process_sstep(struct proc *p, int sstep) +{ + struct trapframe *tf = process_frame(p); + + if (sstep) + tf->tf_rflags |= PSL_T; + else + tf->tf_rflags &= ~PSL_T; + + return (0); +} + +int +process_set_pc(struct proc *p, caddr_t addr) +{ + struct trapframe *tf = process_frame(p); + + if ((u_int64_t)addr > VM_MAXUSER_ADDRESS) + return EINVAL; + tf->tf_rip = (u_int64_t)addr; + + return (0); +} diff --git a/sys/arch/amd64/amd64/softintr.c b/sys/arch/amd64/amd64/softintr.c new file mode 100644 index 00000000000..57ce947e086 --- /dev/null +++ b/sys/arch/amd64/amd64/softintr.c @@ -0,0 +1,168 @@ +/* $OpenBSD: softintr.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: softintr.c,v 1.1 2003/02/26 21:26:12 fvdl Exp $ */ + +/*- + * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + */ + +/* + * Generic soft interrupt implementation for NetBSD/x86. + */ + +#include <sys/param.h> +#include <sys/malloc.h> + +#include <machine/intr.h> + +#include <uvm/uvm_extern.h> + +struct x86_soft_intr x86_soft_intrs[X86_NSOFTINTR]; + +const int x86_soft_intr_to_ssir[X86_NSOFTINTR] = { + SIR_CLOCK, + SIR_NET, + SIR_SERIAL, +}; + +/* + * softintr_init: + * + * Initialize the software interrupt system. + */ +void +softintr_init(void) +{ + struct x86_soft_intr *si; + int i; + + for (i = 0; i < X86_NSOFTINTR; i++) { + si = &x86_soft_intrs[i]; + TAILQ_INIT(&si->softintr_q); + simple_lock_init(&si->softintr_slock); + si->softintr_ssir = x86_soft_intr_to_ssir[i]; + } +} + +/* + * softintr_dispatch: + * + * Process pending software interrupts. + */ +void +softintr_dispatch(int which) +{ + struct x86_soft_intr *si = &x86_soft_intrs[which]; + struct x86_soft_intrhand *sih; + int s; + + for (;;) { + x86_softintr_lock(si, s); + sih = TAILQ_FIRST(&si->softintr_q); + if (sih == NULL) { + x86_softintr_unlock(si, s); + break; + } + TAILQ_REMOVE(&si->softintr_q, sih, sih_q); + sih->sih_pending = 0; + x86_softintr_unlock(si, s); + + uvmexp.softs++; + (*sih->sih_fn)(sih->sih_arg); + } +} + +/* + * softintr_establish: [interface] + * + * Register a software interrupt handler. + */ +void * +softintr_establish(int ipl, void (*func)(void *), void *arg) +{ + struct x86_soft_intr *si; + struct x86_soft_intrhand *sih; + int which; + + switch (ipl) { + case IPL_SOFTCLOCK: + which = X86_SOFTINTR_SOFTCLOCK; + break; + + case IPL_SOFTNET: + which = X86_SOFTINTR_SOFTNET; + break; + + case IPL_TTY: + case IPL_SOFTSERIAL: + which = X86_SOFTINTR_SOFTSERIAL; + break; + + default: + panic("softintr_establish"); + } + + si = &x86_soft_intrs[which]; + + sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT); + if (__predict_true(sih != NULL)) { + sih->sih_intrhead = si; + sih->sih_fn = func; + sih->sih_arg = arg; + sih->sih_pending = 0; + } + return (sih); +} + +/* + * softintr_disestablish: [interface] + * + * Unregister a software interrupt handler. + */ +void +softintr_disestablish(void *arg) +{ + struct x86_soft_intrhand *sih = arg; + struct x86_soft_intr *si = sih->sih_intrhead; + int s; + + x86_softintr_lock(si, s); + if (sih->sih_pending) { + TAILQ_REMOVE(&si->softintr_q, sih, sih_q); + sih->sih_pending = 0; + } + x86_softintr_unlock(si, s); + + free(sih, M_DEVBUF); +} diff --git a/sys/arch/amd64/amd64/spl.S b/sys/arch/amd64/amd64/spl.S new file mode 100644 index 00000000000..c9b674ff648 --- /dev/null +++ b/sys/arch/amd64/amd64/spl.S @@ -0,0 +1,184 @@ +/* $NetBSD: spl.S,v 1.1 2003/04/26 18:39:32 fvdl Exp $ */ + +/* + * Copyright (c) 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +#define ALIGN_TEXT .align 16,0x90 + +#include <machine/asm.h> +#include <machine/psl.h> +#include <machine/trap.h> +#include <machine/segments.h> +#include <machine/frameasm.h> + +#include "assym.h" + + .text + +#if 0 +#if defined(PROF) || defined(GPROF) +/* + * XXXX TODO + */ + .globl _C_LABEL(splhigh), _C_LABEL(splx) + + ALIGN_TEXT +_C_LABEL(splhigh): + movl $IPL_HIGH,%eax + xchgl %eax,CPUVAR(ILEVEL) + ret + + ALIGN_TEXT +_C_LABEL(splx): + movl 4(%esp),%eax + movl %eax,CPUVAR(ILEVEL) + testl %eax,%eax + jnz _C_LABEL(Xspllower) + ret +#endif /* PROF || GPROF */ +#endif + +/* + * Process pending interrupts. + * + * Important registers: + * ebx - cpl + * r13 - address to resume loop at + * + * It is important that the bit scan instruction is bsr, it will get + * the highest 2 bits (currently the IPI and clock handlers) first, + * to avoid deadlocks where one CPU sends an IPI, another one is at + * splipi() and defers it, lands in here via splx(), and handles + * a lower-prio one first, which needs to take the kernel lock --> + * the sending CPU will never see the that CPU accept the IPI + * (see pmap_tlb_shootnow). + */ +IDTVEC(spllower) + pushq %rbx + pushq %r13 + pushq %r12 + movl %edi,%ebx + leaq 1f(%rip),%r13 # address to resume loop at +1: movl %ebx,%eax # get cpl + movl CPUVAR(IUNMASK)(,%rax,4),%eax + cli + andl CPUVAR(IPENDING),%eax # any non-masked bits left? + jz 2f + sti + bsrl %eax,%eax + btrl %eax,CPUVAR(IPENDING) + jnc 1b + movq CPUVAR(ISOURCES)(,%rax,8),%rax + jmp *IS_RECURSE(%rax) +2: + movl %ebx,CPUVAR(ILEVEL) + sti + popq %r12 + popq %r13 + popq %rbx + ret + +/* + * Handle return from interrupt after device handler finishes. + * + * Important registers: + * ebx - cpl to restore + * r13 - address to resume loop at + */ +IDTVEC(doreti) + popq %rbx # get previous priority + decl CPUVAR(IDEPTH) + leaq 1f(%rip),%r13 +1: movl %ebx,%eax + movl CPUVAR(IUNMASK)(,%rax,4),%eax + cli + andl CPUVAR(IPENDING),%eax + jz 2f + sti + bsrl %eax,%eax # slow, but not worth optimizing + btrl %eax,CPUVAR(IPENDING) + jnc 1b # some intr cleared the in-memory bit + movq CPUVAR(ISOURCES)(,%rax, 8),%rax + jmp *IS_RESUME(%rax) +2: /* Check for ASTs on exit to user mode. */ + movl %ebx,CPUVAR(ILEVEL) +5: CHECK_ASTPENDING(%r11) + je 3f + testb $SEL_RPL,TF_CS(%rsp) + jz 3f +4: CLEAR_ASTPENDING(%r11) + sti + movl $T_ASTFLT,TF_TRAPNO(%rsp) /* XXX undo later.. */ + /* Pushed T_ASTFLT into tf_trapno on entry. */ + call _C_LABEL(trap) + cli + jmp 5b +3: INTRFASTEXIT diff --git a/sys/arch/amd64/amd64/swapgeneric.c b/sys/arch/amd64/amd64/swapgeneric.c new file mode 100644 index 00000000000..cf0a65e8f0a --- /dev/null +++ b/sys/arch/amd64/amd64/swapgeneric.c @@ -0,0 +1,57 @@ +/* $OpenBSD: swapgeneric.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: swapgeneric.c,v 1.12 1996/05/03 19:42:28 christos Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)swapgeneric.c 5.5 (Berkeley) 5/9/91 + */ + +/* + * fake swapgeneric.c -- should do this differently. + */ + +#include <sys/param.h> +#include <sys/conf.h> + +int (*mountroot)(void) = NULL; + +dev_t rootdev = NODEV; +dev_t dumpdev = NODEV; + +struct swdevt swdevt[] = { + { NODEV, 0, 0 }, /* to be filled in */ + { NODEV, 0, 0 } +}; diff --git a/sys/arch/amd64/amd64/sys_machdep.c b/sys/arch/amd64/amd64/sys_machdep.c new file mode 100644 index 00000000000..098c523ea68 --- /dev/null +++ b/sys/arch/amd64/amd64/sys_machdep.c @@ -0,0 +1,466 @@ +/* $OpenBSD: sys_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: sys_machdep.c,v 1.1 2003/04/26 18:39:32 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +/* + * XXXfvdl check USER_LDT + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/file.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/buf.h> +#include <sys/signal.h> + +#include <sys/mount.h> +#include <sys/syscallargs.h> + +#include <uvm/uvm_extern.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/gdt.h> +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/sysarch.h> +#include <machine/mtrr.h> + +#if defined(PERFCTRS) && 0 +#include <machine/pmc.h> +#endif + +extern struct vm_map *kernel_map; + +#if 0 +int x86_64_get_ioperm(struct proc *, void *, register_t *); +int x86_64_set_ioperm(struct proc *, void *, register_t *); +#endif +int x86_64_iopl(struct proc *, void *, register_t *); +int x86_64_get_mtrr(struct proc *, void *, register_t *); +int x86_64_set_mtrr(struct proc *, void *, register_t *); + +/* XXXfvdl disabled USER_LDT stuff until I check this stuff */ + +#if defined(USER_LDT) && 0 +int +x86_64_get_ldt(p, args, retval) + struct proc *p; + void *args; + register_t *retval; +{ + int error; + pmap_t pmap = p->p_vmspace->vm_map.pmap; + int nldt, num; + union descriptor *lp; + struct x86_64_get_ldt_args ua; + + if ((error = copyin(args, &ua, sizeof(ua))) != 0) + return (error); + +#ifdef LDT_DEBUG + printf("x86_64_get_ldt: start=%d num=%d descs=%p\n", ua.start, + ua.num, ua.desc); +#endif + + if (ua.start < 0 || ua.num < 0) + return (EINVAL); + + /* + * XXX LOCKING. + */ + + if (pmap->pm_flags & PMF_USER_LDT) { + nldt = pmap->pm_ldt_len; + lp = pmap->pm_ldt; + } else { + nldt = NLDT; + lp = ldt; + } + + if (ua.start > nldt) + return (EINVAL); + + lp += ua.start; + num = min(ua.num, nldt - ua.start); + + error = copyout(lp, ua.desc, num * sizeof(union descriptor)); + if (error) + return (error); + + *retval = num; + return (0); +} + +int +x86_64_set_ldt(p, args, retval) + struct proc *p; + void *args; + register_t *retval; +{ + int error, i, n; + struct pcb *pcb = &p->p_addr->u_pcb; + pmap_t pmap = p->p_vmspace->vm_map.pmap; + struct x86_64_set_ldt_args ua; + union descriptor desc; + + if ((error = copyin(args, &ua, sizeof(ua))) != 0) + return (error); + +#ifdef LDT_DEBUG + printf("x86_64_set_ldt: start=%d num=%d descs=%p\n", ua.start, + ua.num, ua.desc); +#endif + + if (ua.start < 0 || ua.num < 0) + return (EINVAL); + if (ua.start > 8192 || (ua.start + ua.num) > 8192) + return (EINVAL); + + /* + * XXX LOCKING + */ + + /* allocate user ldt */ + if (pmap->pm_ldt == 0 || (ua.start + ua.num) > pmap->pm_ldt_len) { + size_t old_len, new_len; + union descriptor *old_ldt, *new_ldt; + + if (pmap->pm_flags & PMF_USER_LDT) { + old_len = pmap->pm_ldt_len * sizeof(union descriptor); + old_ldt = pmap->pm_ldt; + } else { + old_len = NLDT * sizeof(union descriptor); + old_ldt = ldt; + pmap->pm_ldt_len = 512; + } + while ((ua.start + ua.num) > pmap->pm_ldt_len) + pmap->pm_ldt_len *= 2; + new_len = pmap->pm_ldt_len * sizeof(union descriptor); + new_ldt = (union descriptor *)uvm_km_alloc(kernel_map, new_len); + memcpy(new_ldt, old_ldt, old_len); + memset((caddr_t)new_ldt + old_len, 0, new_len - old_len); + pmap->pm_ldt = new_ldt; + + if (pmap->pm_flags & PCB_USER_LDT) + ldt_free(pmap); + else + pmap->pm_flags |= PCB_USER_LDT; + ldt_alloc(pmap, new_ldt, new_len); + pcb->pcb_ldt_sel = pmap->pm_ldt_sel; + if (pcb == curpcb) + lldt(pcb->pcb_ldt_sel); + + /* + * XXX Need to notify other processors which may be + * XXX currently using this pmap that they need to + * XXX re-load the LDT. + */ + + if (old_ldt != ldt) + uvm_km_free(kernel_map, (vaddr_t)old_ldt, old_len); +#ifdef LDT_DEBUG + printf("x86_64_set_ldt(%d): new_ldt=%p\n", p->p_pid, new_ldt); +#endif + } + + if (pcb == curpcb) + savectx(curpcb); + error = 0; + + /* Check descriptors for access violations. */ + for (i = 0, n = ua.start; i < ua.num; i++, n++) { + if ((error = copyin(&ua.desc[i], &desc, sizeof(desc))) != 0) + return (error); + + switch (desc.sd.sd_type) { + case SDT_SYSNULL: + desc.sd.sd_p = 0; + break; + case SDT_SYS286CGT: + case SDT_SYS386CGT: + /* + * Only allow call gates targeting a segment + * in the LDT or a user segment in the fixed + * part of the gdt. Segments in the LDT are + * constrained (below) to be user segments. + */ + if (desc.gd.gd_p != 0 && !ISLDT(desc.gd.gd_selector) && + ((IDXSEL(desc.gd.gd_selector) >= NGDT) || + (gdt[IDXSEL(desc.gd.gd_selector)].sd.sd_dpl != + SEL_UPL))) + return (EACCES); + break; + case SDT_MEMEC: + case SDT_MEMEAC: + case SDT_MEMERC: + case SDT_MEMERAC: + /* Must be "present" if executable and conforming. */ + if (desc.sd.sd_p == 0) + return (EACCES); + break; + case SDT_MEMRO: + case SDT_MEMROA: + case SDT_MEMRW: + case SDT_MEMRWA: + case SDT_MEMROD: + case SDT_MEMRODA: + case SDT_MEMRWD: + case SDT_MEMRWDA: + case SDT_MEME: + case SDT_MEMEA: + case SDT_MEMER: + case SDT_MEMERA: + break; + default: + /* Only care if it's present. */ + if (desc.sd.sd_p != 0) + return (EACCES); + break; + } + + if (desc.sd.sd_p != 0) { + /* Only user (ring-3) descriptors may be present. */ + if (desc.sd.sd_dpl != SEL_UPL) + return (EACCES); + } + } + + /* Now actually replace the descriptors. */ + for (i = 0, n = ua.start; i < ua.num; i++, n++) { + if ((error = copyin(&ua.desc[i], &desc, sizeof(desc))) != 0) + goto out; + + pmap->pm_ldt[n] = desc; + } + + *retval = ua.start; + +out: + return (error); +} +#endif /* USER_LDT */ + +int +x86_64_iopl(struct proc *p, void *args, register_t *retval) +{ + int error; + struct trapframe *tf = p->p_md.md_regs; + struct x86_64_iopl_args ua; + + if (securelevel > 1) + return EPERM; + + if ((error = suser(p, 0)) != 0) + return error; + + if ((error = copyin(args, &ua, sizeof(ua))) != 0) + return error; + + if (ua.iopl) + tf->tf_rflags |= PSL_IOPL; + else + tf->tf_rflags &= ~PSL_IOPL; + + return 0; +} + +#if 0 + +int +x86_64_get_ioperm(p, args, retval) + struct proc *p; + void *args; + register_t *retval; +{ + int error; + struct pcb *pcb = &p->p_addr->u_pcb; + struct x86_64_get_ioperm_args ua; + + if ((error = copyin(args, &ua, sizeof(ua))) != 0) + return (error); + + return copyout(pcb->pcb_iomap, ua.iomap, sizeof(pcb->pcb_iomap)); +} + +int +x86_64_set_ioperm(p, args, retval) + struct proc *p; + void *args; + register_t *retval; +{ + int error; + struct pcb *pcb = &p->p_addr->u_pcb; + struct x86_64_set_ioperm_args ua; + + if (securelevel > 1) + return EPERM; + + if ((error = suser(p, 0)) != 0) + return error; + + if ((error = copyin(args, &ua, sizeof(ua))) != 0) + return (error); + + return copyin(ua.iomap, pcb->pcb_iomap, sizeof(pcb->pcb_iomap)); +} + +#endif + +#ifdef MTRR + +int +x86_64_get_mtrr(struct proc *p, void *args, register_t *retval) +{ + struct x86_64_get_mtrr_args ua; + int error, n; + + if (mtrr_funcs == NULL) + return ENOSYS; + + error = copyin(args, &ua, sizeof ua); + if (error != 0) + return error; + + error = copyin(ua.n, &n, sizeof n); + if (error != 0) + return error; + + error = mtrr_get(ua.mtrrp, &n, p, MTRR_GETSET_USER); + + copyout(&n, ua.n, sizeof (int)); + + return error; +} + +int +x86_64_set_mtrr(struct proc *p, void *args, register_t *retval) +{ + int error, n; + struct x86_64_set_mtrr_args ua; + + if (mtrr_funcs == NULL) + return ENOSYS; + + error = suser(p, 0); + if (error != 0) + return error; + + error = copyin(args, &ua, sizeof ua); + if (error != 0) + return error; + + error = copyin(ua.n, &n, sizeof n); + if (error != 0) + return error; + + error = mtrr_set(ua.mtrrp, &n, p, MTRR_GETSET_USER); + if (n != 0) + mtrr_commit(); + + copyout(&n, ua.n, sizeof n); + + return error; +} +#endif + +int +sys_sysarch(struct proc *p, void *v, register_t *retval) +{ + struct sys_sysarch_args /* { + syscallarg(int) op; + syscallarg(void *) parms; + } */ *uap = v; + int error = 0; + + switch(SCARG(uap, op)) { +#if defined(USER_LDT) && 0 + case X86_64_GET_LDT: + error = x86_64_get_ldt(p, SCARG(uap, parms), retval); + break; + + case X86_64_SET_LDT: + error = x86_64_set_ldt(p, SCARG(uap, parms), retval); + break; +#endif + case X86_64_IOPL: + error = x86_64_iopl(p, SCARG(uap, parms), retval); + break; + +#if 0 + case X86_64_GET_IOPERM: + error = x86_64_get_ioperm(p, SCARG(uap, parms), retval); + break; + + case X86_64_SET_IOPERM: + error = x86_64_set_ioperm(p, SCARG(uap, parms), retval); + break; +#endif +#ifdef MTRR + case X86_64_GET_MTRR: + error = x86_64_get_mtrr(p, SCARG(uap, parms), retval); + break; + case X86_64_SET_MTRR: + error = x86_64_set_mtrr(p, SCARG(uap, parms), retval); + break; +#endif + +#if defined(PERFCTRS) && 0 + case X86_64_PMC_INFO: + error = pmc_info(p, SCARG(uap, parms), retval); + break; + + case X86_64_PMC_STARTSTOP: + error = pmc_startstop(p, SCARG(uap, parms), retval); + break; + + case X86_64_PMC_READ: + error = pmc_read(p, SCARG(uap, parms), retval); + break; +#endif + default: + error = EINVAL; + break; + } + return (error); +} diff --git a/sys/arch/amd64/amd64/syscall.c b/sys/arch/amd64/amd64/syscall.c new file mode 100644 index 00000000000..5c134c8f2b4 --- /dev/null +++ b/sys/arch/amd64/amd64/syscall.c @@ -0,0 +1,341 @@ +/* $OpenBSD: syscall.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: syscall.c,v 1.1 2003/04/26 18:39:32 fvdl Exp $ */ + +/*- + * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/signal.h> +#ifdef KTRACE +#include <sys/ktrace.h> +#endif +#ifdef SYSTRACE +#include <sys/systrace.h> +#endif +#include <sys/syscall.h> + +#include <uvm/uvm_extern.h> + +#include <machine/cpu.h> +#include <machine/psl.h> +#include <machine/userret.h> + +void syscall_intern(struct proc *); +void syscall_plain(struct trapframe); +void syscall_fancy(struct trapframe); + +void +syscall_intern(p) + struct proc *p; +{ +#ifdef KTRACE + if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) { + p->p_md.md_syscall = syscall_fancy; + return; + } +#endif +#ifdef SYSTRACE + if (ISSET(p->p_flag, P_SYSTRACE)) { + p->p_md.md_syscall = syscall_fancy; + return; + } +#endif + p->p_md.md_syscall = syscall_plain; +} + +/* + * syscall(frame): + * System call request from POSIX system call gate interface to kernel. + * Like trap(), argument is call by reference. + */ +void +syscall_plain(frame) + struct trapframe frame; +{ + caddr_t params; + const struct sysent *callp; + struct proc *p; + int error; + int nsys; + size_t argsize, argoff; + register_t code, args[9], rval[2], *argp; + + + uvmexp.syscalls++; + p = curproc; + + code = frame.tf_rax; + nsys = p->p_emul->e_nsysent; + callp = p->p_emul->e_sysent; + argoff = 0; + argp = &args[0]; + + switch (code) { + case SYS_syscall: + case SYS___syscall: + /* + * Code is first argument, followed by actual args. + */ + code = frame.tf_rdi; + argp = &args[1]; + argoff = 1; + break; + default: + break; + } + + if (code < 0 || code >= nsys) + callp += p->p_emul->e_nosys; + else + callp += code; + + argsize = (callp->sy_argsize >> 3) + argoff; + if (argsize) { + switch (MIN(argsize, 6)) { + case 6: + args[5] = frame.tf_r9; + case 5: + args[4] = frame.tf_r8; + case 4: + args[3] = frame.tf_r10; + case 3: + args[2] = frame.tf_rdx; + case 2: + args[1] = frame.tf_rsi; + case 1: + args[0] = frame.tf_rdi; + break; + default: + panic("impossible syscall argsize"); + } + if (argsize > 6) { + argsize -= 6; + params = (caddr_t)frame.tf_rsp + sizeof(register_t); + error = copyin(params, (caddr_t)&args[6], + argsize << 3); + if (error != 0) + goto bad; + } + } + +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, argp); +#endif /* SYSCALL_DEBUG */ + + rval[0] = 0; + rval[1] = 0; + KERNEL_PROC_LOCK(p); + error = (*callp->sy_call)(p, argp, rval); + KERNEL_PROC_UNLOCK(p); + + switch (error) { + case 0: + frame.tf_rax = rval[0]; + frame.tf_rdx = rval[1]; + frame.tf_rflags &= ~PSL_C; /* carry bit */ + break; + case ERESTART: + /* + * The offset to adjust the PC by depends on whether we entered + * the kernel through the trap or call gate. We pushed the + * size of the instruction into tf_err on entry. + */ + frame.tf_rip -= frame.tf_err; + break; + case EJUSTRETURN: + /* nothing to do */ + break; + default: + bad: + frame.tf_rax = error; + frame.tf_rflags |= PSL_C; /* carry bit */ + break; + } + +#ifdef SYSCALL_DEBUG + scdebug_ret(p, code, error, rval); +#endif /* SYSCALL_DEBUG */ + userret(p); +} + +void +syscall_fancy(frame) + struct trapframe frame; +{ + caddr_t params; + const struct sysent *callp; + struct proc *p; + int error; + int nsys; + size_t argsize, argoff; + register_t code, args[9], rval[2], *argp; + + uvmexp.syscalls++; + p = curproc; + + code = frame.tf_rax; + callp = p->p_emul->e_sysent; + nsys = p->p_emul->e_nsysent; + argp = &args[0]; + argoff = 0; + + switch (code) { + case SYS_syscall: + case SYS___syscall: + /* + * Code is first argument, followed by actual args. + */ + code = frame.tf_rdi; + argp = &args[1]; + argoff = 1; + break; + default: + break; + } + + if (code < 0 || code >= nsys) + callp += p->p_emul->e_nosys; + else + callp += code; + + argsize = (callp->sy_argsize >> 3) + argoff; + if (argsize) { + switch (MIN(argsize, 6)) { + case 6: + args[5] = frame.tf_r9; + case 5: + args[4] = frame.tf_r8; + case 4: + args[3] = frame.tf_r10; + case 3: + args[2] = frame.tf_rdx; + case 2: + args[1] = frame.tf_rsi; + case 1: + args[0] = frame.tf_rdi; + break; + default: + panic("impossible syscall argsize"); + } + if (argsize > 6) { + argsize -= 6; + params = (caddr_t)frame.tf_rsp + sizeof(register_t); + error = copyin(params, (caddr_t)&args[6], + argsize << 3); + if (error != 0) + goto bad; + } + } + + KERNEL_PROC_LOCK(p); +#ifdef SYSCALL_DEBUG + scdebug_call(p, code, args); +#endif +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSCALL)) + ktrsyscall(p, code, argsize, args); +#endif + + rval[0] = 0; + rval[1] = 0; +#if NSYSTRACE > 0 + if (ISSET(p->p_flag, P_SYSTRACE)) + error = systrace_redirect(code, p, args, rval); +#endif + error = (*callp->sy_call)(p, argp, rval); + KERNEL_PROC_UNLOCK(p); + switch (error) { + case 0: + frame.tf_rax = rval[0]; + frame.tf_rdx = rval[1]; + frame.tf_rflags &= ~PSL_C; /* carry bit */ + break; + case ERESTART: + /* + * The offset to adjust the PC by depends on whether we entered + * the kernel through the trap or call gate. We pushed the + * size of the instruction into tf_err on entry. + */ + frame.tf_rip -= frame.tf_err; + break; + case EJUSTRETURN: + /* nothing to do */ + break; + default: + bad: + frame.tf_rax = error; + frame.tf_rflags |= PSL_C; /* carry bit */ + break; + } + +#ifdef SYSCALL_DEBUG + KERNEL_PROC_LOCK(p); + scdebug_ret(p, code, error, rval); + KERNEL_PROC_UNLOCK(p); +#endif + userret(p); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) { + KERNEL_PROC_LOCK(p); + ktrsysret(p, code, error, rval[0]); + KERNEL_PROC_UNLOCK(p); + } +#endif +} + +void +child_return(void *arg) +{ + struct proc *p = arg; + struct trapframe *tf = p->p_md.md_regs; + + tf->tf_rax = 0; + tf->tf_rflags &= ~PSL_C; + + KERNEL_PROC_UNLOCK(l); + + userret(p); +#ifdef KTRACE + if (KTRPOINT(p, KTR_SYSRET)) { + KERNEL_PROC_LOCK(p); + ktrsysret(p, SYS_fork, 0, 0); + KERNEL_PROC_UNLOCK(p); + } +#endif +} diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c new file mode 100644 index 00000000000..82f5623731d --- /dev/null +++ b/sys/arch/amd64/amd64/trap.c @@ -0,0 +1,579 @@ +/* $OpenBSD: trap.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: trap.c,v 1.2 2003/05/04 23:51:56 fvdl Exp $ */ + +/*- + * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the University of Utah, and 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. + * + * @(#)trap.c 7.4 (Berkeley) 5/13/91 + */ + +/* + * amd64 Trap and System call handling + */ +#define TRAP_SIGDEBUG + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/acct.h> +#include <sys/kernel.h> +#include <sys/signal.h> +#include <sys/syscall.h> +#include <sys/reboot.h> +#include <sys/pool.h> + +#include <uvm/uvm_extern.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/fpu.h> +#include <machine/psl.h> +#include <machine/reg.h> +#include <machine/trap.h> +#include <machine/userret.h> +#ifdef DDB +#include <machine/db_machdep.h> +#endif + +#include "isa.h" + +#ifdef KGDB +#include <sys/kgdb.h> +#endif + +void trap(struct trapframe); +#if defined(I386_CPU) +int trapwrite(unsigned); +#endif + +const char *trap_type[] = { + "privileged instruction fault", /* 0 T_PRIVINFLT */ + "breakpoint trap", /* 1 T_BPTFLT */ + "arithmetic trap", /* 2 T_ARITHTRAP */ + "asynchronous system trap", /* 3 T_ASTFLT */ + "protection fault", /* 4 T_PROTFLT */ + "trace trap", /* 5 T_TRCTRAP */ + "page fault", /* 6 T_PAGEFLT */ + "alignment fault", /* 7 T_ALIGNFLT */ + "integer divide fault", /* 8 T_DIVIDE */ + "non-maskable interrupt", /* 9 T_NMI */ + "overflow trap", /* 10 T_OFLOW */ + "bounds check fault", /* 11 T_BOUND */ + "FPU not available fault", /* 12 T_DNA */ + "double fault", /* 13 T_DOUBLEFLT */ + "FPU operand fetch fault", /* 14 T_FPOPFLT */ + "invalid TSS fault", /* 15 T_TSSFLT */ + "segment not present fault", /* 16 T_SEGNPFLT */ + "stack fault", /* 17 T_STKFLT */ + "machine check", /* 18 T_MCA */ + "SSE FP exception", /* 19 T_XMM */ + "reserved trap", /* 20 T_RESERVED */ +}; +int trap_types = sizeof trap_type / sizeof trap_type[0]; + +#ifdef DEBUG +int trapdebug = 0; +#endif + +#define IDTVEC(name) __CONCAT(X, name) + +#ifdef TRAP_SIGDEBUG +static void frame_dump(struct trapframe *); +#endif + +/* + * trap(frame): + * Exception, fault, and trap interface to BSD kernel. This + * common code is called from assembly language IDT gate entry + * routines that prepare a suitable stack frame, and restore this + * frame after the exception has been processed. Note that the + * effect is as if the arguments were passed call by reference. + */ +/*ARGSUSED*/ +void +trap(frame) + struct trapframe frame; +{ + struct proc *p = curproc; + int type = (int)frame.tf_trapno; + struct pcb *pcb; + extern char resume_iret[], IDTVEC(oosyscall)[]; +#if 0 + extern char resume_pop_ds[], resume_pop_es[]; +#endif + struct trapframe *vframe; + void *resume; + caddr_t onfault; + int error; + uint64_t cr2; + union sigval sv; + + uvmexp.traps++; + + pcb = (p != NULL && p->p_addr != NULL) ? &p->p_addr->u_pcb : NULL; + +#ifdef DEBUG + if (trapdebug) { + printf("trap %d code %lx eip %lx cs %lx rflags %lx cr2 %lx " + "cpl %x\n", + type, frame.tf_err, frame.tf_rip, frame.tf_cs, + frame.tf_rflags, rcr2(), curcpu()->ci_ilevel); + printf("curproc %p\n", curproc); + if (curproc) + printf("pid %d\n", p->p_pid); + } +#endif + + if (!KERNELMODE(frame.tf_cs, frame.tf_rflags)) { + type |= T_USER; + p->p_md.md_regs = &frame; + } + + switch (type) { + + default: + we_re_toast: +#ifdef KGDB + if (kgdb_trap(type, &frame)) + return; + else { + /* + * If this is a breakpoint, don't panic + * if we're not connected. + */ + if (type == T_BPTFLT) { + printf("kgdb: ignored %s\n", trap_type[type]); + return; + } + } +#endif +#ifdef DDB + if (kdb_trap(type, 0, &frame)) + return; +#endif + if (frame.tf_trapno < trap_types) + printf("fatal %s", trap_type[frame.tf_trapno]); + else + printf("unknown trap %ld", (u_long)frame.tf_trapno); + printf(" in %s mode\n", (type & T_USER) ? "user" : "supervisor"); + printf("trap type %d code %lx rip %lx cs %lx rflags %lx cr2 " + " %lx cpl %x rsp %lx\n", + type, frame.tf_err, (u_long)frame.tf_rip, frame.tf_cs, + frame.tf_rflags, rcr2(), curcpu()->ci_ilevel, frame.tf_rsp); + + /* panic("trap"); */ + boot(RB_HALT); + /*NOTREACHED*/ + + case T_PROTFLT: + case T_SEGNPFLT: + case T_ALIGNFLT: + case T_TSSFLT: + if (p == NULL) + goto we_re_toast; + /* Check for copyin/copyout fault. */ + if (pcb->pcb_onfault != 0) { + error = EFAULT; +copyfault: + frame.tf_rip = (u_int64_t)pcb->pcb_onfault; + frame.tf_rax = error; + return; + } + + /* + * Check for failure during return to user mode. + * + * XXXfvdl check for rex prefix? + * + * We do this by looking at the instruction we faulted on. The + * specific instructions we recognize only happen when + * returning from a trap, syscall, or interrupt. + * + * XXX + * The heuristic used here will currently fail for the case of + * one of the 2 pop instructions faulting when returning from a + * a fast interrupt. This should not be possible. It can be + * fixed by rearranging the trap frame so that the stack format + * at this point is the same as on exit from a `slow' + * interrupt. + */ + switch (*(u_char *)frame.tf_rip) { + case 0xcf: /* iret */ + vframe = (void *)((u_int64_t)&frame.tf_rsp - 44); + resume = resume_iret; + break; +/* + * XXXfvdl these are illegal in long mode (not in compat mode, though) + * and we do not take back the descriptors from the signal context anyway, + * but may do so later for USER_LDT, in which case we need to intercept + * other instructions (movl %eax, %Xs). + */ +#if 0 + case 0x1f: /* popl %ds */ + vframe = (void *)((u_int64_t)&frame.tf_rsp - 4); + resume = resume_pop_ds; + break; + case 0x07: /* popl %es */ + vframe = (void *)((u_int64_t)&frame.tf_rsp - 0); + resume = resume_pop_es; + break; +#endif + default: + goto we_re_toast; + } + if (KERNELMODE(vframe->tf_cs, vframe->tf_rflags)) + goto we_re_toast; + + frame.tf_rip = (u_int64_t)resume; + return; + + case T_PROTFLT|T_USER: /* protection fault */ + case T_TSSFLT|T_USER: + case T_SEGNPFLT|T_USER: + case T_STKFLT|T_USER: + case T_NMI|T_USER: +#ifdef TRAP_SIGDEBUG + printf("pid %d (%s): BUS at rip %lx addr %lx\n", + p->p_pid, p->p_comm, frame.tf_rip, rcr2()); + frame_dump(&frame); +#endif + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGBUS, type & ~T_USER, BUS_OBJERR, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + case T_ALIGNFLT|T_USER: + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGBUS, type & ~T_USER, BUS_ADRALN, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + + case T_PRIVINFLT|T_USER: /* privileged instruction fault */ + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGILL, type & ~T_USER, ILL_PRVOPC, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + case T_FPOPFLT|T_USER: /* coprocessor operand fault */ +#ifdef TRAP_SIGDEBUG + printf("pid %d (%s): ILL at rip %lx addr %lx\n", + p->p_pid, p->p_comm, frame.tf_rip, rcr2()); + frame_dump(&frame); +#endif + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGILL, type & ~T_USER, ILL_COPROC, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + + case T_ASTFLT|T_USER: /* Allow process switch */ + uvmexp.softs++; + if (p->p_flag & P_OWEUPC) { + p->p_flag &= ~P_OWEUPC; + KERNEL_PROC_LOCK(p); + ADDUPROF(p); + KERNEL_PROC_UNLOCK(p); + } + /* Allow a forced task switch. */ + if (curcpu()->ci_want_resched) + preempt(NULL); + goto out; + + case T_DNA|T_USER: { + printf("pid %d killed due to lack of floating point\n", + p->p_pid); + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGKILL, type &~ T_USER, FPE_FLTINV, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + } + + case T_BOUND|T_USER: + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGFPE, type &~ T_USER, FPE_FLTSUB, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + case T_OFLOW|T_USER: + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTOVF, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + case T_DIVIDE|T_USER: + sv.sival_ptr = (void *)frame.tf_rip; + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGFPE, type &~ T_USER, FPE_INTDIV, sv); + KERNEL_PROC_UNLOCK(p); + goto out; + + case T_ARITHTRAP|T_USER: + case T_XMM|T_USER: + fputrap(&frame); + goto out; + + case T_PAGEFLT: /* allow page faults in kernel mode */ + if (p == NULL) + goto we_re_toast; +#ifdef LOCKDEBUG + if (simple_lock_held(&sched_lock)) + goto we_re_toast; +#endif +#ifdef MULTIPROCESSOR + if ((p->p_flag & P_BIGLOCK) == 0) + goto we_re_toast; +#endif + cr2 = rcr2(); + KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE); + goto faultcommon; + + case T_PAGEFLT|T_USER: { /* page fault */ + vaddr_t va, fa; + struct vmspace *vm; + struct vm_map *map; + vm_prot_t ftype; + extern struct vm_map *kernel_map; + unsigned long nss; + + cr2 = rcr2(); + KERNEL_PROC_LOCK(p); +faultcommon: + vm = p->p_vmspace; + if (vm == NULL) + goto we_re_toast; + fa = cr2; + va = trunc_page((vaddr_t)cr2); + /* + * It is only a kernel address space fault iff: + * 1. (type & T_USER) == 0 and + * 2. pcb_onfault not set or + * 3. pcb_onfault set but supervisor space fault + * The last can occur during an exec() copyin where the + * argument space is lazy-allocated. + */ + if (type == T_PAGEFLT && va >= VM_MIN_KERNEL_ADDRESS) + map = kernel_map; + else + map = &vm->vm_map; + if (frame.tf_err & PGEX_W) + ftype = VM_PROT_WRITE; + else + ftype = VM_PROT_READ; + +#ifdef DIAGNOSTIC + if (map == kernel_map && va == 0) { + printf("trap: bad kernel access at %lx\n", va); + goto we_re_toast; + } +#endif + + nss = 0; + if ((caddr_t)va >= vm->vm_maxsaddr + && (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS + && map != kernel_map) { + nss = btoc(USRSTACK-(unsigned long)va); + if (nss > (u_long)btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { + /* + * We used to fail here. However, it may + * just have been an mmap()ed page low + * in the stack, which is legal. If it + * wasn't, uvm_fault() will fail below. + * + * Set nss to 0, since this case is not + * a "stack extension". + */ + nss = 0; + } + } + + /* Fault the original page in. */ + onfault = pcb->pcb_onfault; + pcb->pcb_onfault = NULL; + error = uvm_fault(map, va, 0, ftype); + pcb->pcb_onfault = onfault; + if (error == 0) { + if (nss > (u_long)vm->vm_ssize) + vm->vm_ssize = nss; + + if (type == T_PAGEFLT) { + KERNEL_UNLOCK(); + return; + } + KERNEL_PROC_UNLOCK(p); + goto out; + } + if (error == EACCES) { + error = EFAULT; + } + + if (type == T_PAGEFLT) { + if (pcb->pcb_onfault != 0) { + KERNEL_UNLOCK(); + goto copyfault; + } + printf("uvm_fault(%p, 0x%lx, 0, %d) -> %x\n", + map, va, ftype, error); + goto we_re_toast; + } + if (error == ENOMEM) { + printf("UVM: pid %d (%s), uid %d killed: out of swap\n", + p->p_pid, p->p_comm, + p->p_cred && p->p_ucred ? + (int)p->p_ucred->cr_uid : -1); + sv.sival_ptr = (void *)fa; + trapsignal(p, SIGKILL, T_PAGEFLT, SEGV_MAPERR, sv); + } else { +#ifdef TRAP_SIGDEBUG + printf("pid %d (%s): SEGV at rip %lx addr %lx\n", + p->p_pid, p->p_comm, frame.tf_rip, va); + frame_dump(&frame); +#endif + sv.sival_ptr = (void *)fa; + trapsignal(p, SIGSEGV, T_PAGEFLT, SEGV_MAPERR, sv); + } + if (type == T_PAGEFLT) + KERNEL_UNLOCK(); + else + KERNEL_PROC_UNLOCK(p); + break; + } + + case T_TRCTRAP: + /* Check whether they single-stepped into a lcall. */ + if (frame.tf_rip == (int)IDTVEC(oosyscall)) + return; + if (frame.tf_rip == (int)IDTVEC(oosyscall) + 1) { + frame.tf_rflags &= ~PSL_T; + return; + } + goto we_re_toast; + + case T_BPTFLT|T_USER: /* bpt instruction fault */ + case T_TRCTRAP|T_USER: /* trace trap */ +#ifdef MATH_EMULATE + trace: +#endif + KERNEL_PROC_LOCK(p); + trapsignal(p, SIGTRAP, type &~ T_USER, TRAP_BRKPT, sv); + KERNEL_PROC_UNLOCK(p); + break; + +#if NISA > 0 + case T_NMI: +#if defined(KGDB) || defined(DDB) + /* NMI can be hooked up to a pushbutton for debugging */ + printf ("NMI ... going to debugger\n"); +#ifdef KGDB + + if (kgdb_trap(type, &frame)) + return; +#endif +#ifdef DDB + if (kdb_trap(type, 0, &frame)) + return; +#endif +#endif /* KGDB || DDB */ + /* machine/parity/power fail/"kitchen sink" faults */ + + if (x86_nmi() != 0) + goto we_re_toast; + else + return; +#endif /* NISA > 0 */ + } + + if ((type & T_USER) == 0) + return; +out: + userret(p); +} + +#ifdef TRAP_SIGDEBUG +static void +frame_dump(struct trapframe *tf) +{ + printf("rip %p rsp %p rfl %p\n", + (void *)tf->tf_rip, (void *)tf->tf_rsp, (void *)tf->tf_rflags); + printf("rdi %p rsi %p rdx %p\n", + (void *)tf->tf_rdi, (void *)tf->tf_rsi, (void *)tf->tf_rdx); + printf("rcx %p r8 %p r9 %p\n", + (void *)tf->tf_rcx, (void *)tf->tf_r8, (void *)tf->tf_r9); + printf("r10 %p r11 %p r12 %p\n", + (void *)tf->tf_r10, (void *)tf->tf_r11, (void *)tf->tf_r12); + printf("r13 %p r14 %p r15 %p\n", + (void *)tf->tf_r13, (void *)tf->tf_r14, (void *)tf->tf_r15); + printf("rbp %p rbx %p rax %p\n", + (void *)tf->tf_rbp, (void *)tf->tf_rbx, (void *)tf->tf_rax); +} +#endif diff --git a/sys/arch/amd64/amd64/vector.S b/sys/arch/amd64/amd64/vector.S new file mode 100644 index 00000000000..b2c3819dd2d --- /dev/null +++ b/sys/arch/amd64/amd64/vector.S @@ -0,0 +1,821 @@ +/* $OpenBSD: vector.S,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: vector.S,v 1.2 2003/05/04 23:46:41 fvdl Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +#define ALIGN_TEXT .align 16,0x90 + +#include <machine/i8259.h> +#include <machine/i82093reg.h> +#include <machine/i82489reg.h> +#include <machine/asm.h> +#include <machine/frameasm.h> +#include <machine/segments.h> +#include <machine/trap.h> +#include <machine/intr.h> +#include <machine/psl.h> + +#include <net/netisr.h> + +#include "ioapic.h" +#include "lapic.h" +#include "assym.h" + +/*****************************************************************************/ + +/* + * Trap and fault vector routines + * + * On exit from the kernel to user mode, we always need to check for ASTs. In + * addition, we need to do this atomically; otherwise an interrupt may occur + * which causes an AST, but it won't get processed until the next kernel entry + * (possibly the next clock tick). Thus, we disable interrupt before checking, + * and only enable them again on the final `iret' or before calling the AST + * handler. + */ + +/*****************************************************************************/ + +#define TRAP(a) pushq $(a) ; jmp _C_LABEL(alltraps) +#define ZTRAP(a) pushq $0 ; TRAP(a) + +#define BPTTRAP(a) ZTRAP(a) + + .text +IDTVEC(trap00) + ZTRAP(T_DIVIDE) +IDTVEC(trap01) + BPTTRAP(T_TRCTRAP) +IDTVEC(trap02) + ZTRAP(T_NMI) +IDTVEC(trap03) + BPTTRAP(T_BPTFLT) +IDTVEC(trap04) + ZTRAP(T_OFLOW) +IDTVEC(trap05) + ZTRAP(T_BOUND) +IDTVEC(trap06) + ZTRAP(T_PRIVINFLT) +IDTVEC(trap07) + pushq $0 # dummy error code + pushq $T_DNA + INTRENTRY + sti + movq CPUVAR(SELF),%rdi + call _C_LABEL(fpudna) + INTRFASTEXIT +IDTVEC(trap08) + ZTRAP(T_DOUBLEFLT) +IDTVEC(trap09) + ZTRAP(T_FPOPFLT) +IDTVEC(trap0a) + TRAP(T_TSSFLT) +IDTVEC(trap0b) + TRAP(T_SEGNPFLT) +IDTVEC(trap0c) + TRAP(T_STKFLT) +IDTVEC(trap0d) + TRAP(T_PROTFLT) +IDTVEC(trap0e) + TRAP(T_PAGEFLT) +IDTVEC(intrspurious) +IDTVEC(trap0f) + iretq +IDTVEC(trap10) + ZTRAP(T_ARITHTRAP) +IDTVEC(trap11) + ZTRAP(T_ALIGNFLT) +IDTVEC(trap12) + ZTRAP(T_MCA) +IDTVEC(trap13) + ZTRAP(T_XMM) +IDTVEC(trap14) +IDTVEC(trap15) +IDTVEC(trap16) +IDTVEC(trap17) +IDTVEC(trap18) +IDTVEC(trap19) +IDTVEC(trap1a) +IDTVEC(trap1b) +IDTVEC(trap1c) +IDTVEC(trap1d) +IDTVEC(trap1e) +IDTVEC(trap1f) + /* 20 - 31 reserved for future exp */ + ZTRAP(T_RESERVED) + +IDTVEC(exceptions) + .quad _C_LABEL(Xtrap00), _C_LABEL(Xtrap01) + .quad _C_LABEL(Xtrap02), _C_LABEL(Xtrap03) + .quad _C_LABEL(Xtrap04), _C_LABEL(Xtrap05) + .quad _C_LABEL(Xtrap06), _C_LABEL(Xtrap07) + .quad _C_LABEL(Xtrap08), _C_LABEL(Xtrap09) + .quad _C_LABEL(Xtrap0a), _C_LABEL(Xtrap0b) + .quad _C_LABEL(Xtrap0c), _C_LABEL(Xtrap0d) + .quad _C_LABEL(Xtrap0e), _C_LABEL(Xtrap0f) + .quad _C_LABEL(Xtrap10), _C_LABEL(Xtrap11) + .quad _C_LABEL(Xtrap12), _C_LABEL(Xtrap13) + .quad _C_LABEL(Xtrap14), _C_LABEL(Xtrap15) + .quad _C_LABEL(Xtrap16), _C_LABEL(Xtrap17) + .quad _C_LABEL(Xtrap18), _C_LABEL(Xtrap19) + .quad _C_LABEL(Xtrap1a), _C_LABEL(Xtrap1b) + .quad _C_LABEL(Xtrap1c), _C_LABEL(Xtrap1d) + .quad _C_LABEL(Xtrap1e), _C_LABEL(Xtrap1f) + +/* + * If an error is detected during trap, syscall, or interrupt exit, trap() will + * change %eip to point to one of these labels. We clean up the stack, if + * necessary, and resume as if we were handling a general protection fault. + * This will cause the process to get a SIGBUS. + * + * XXXfvdl currently unused, as pop %ds and pop %es are illegal in long + * mode. However, if the x86-64 port is going to support USER_LDT, we + * may need something like this after all. + */ +NENTRY(resume_iret) + ZTRAP(T_PROTFLT) +#if 0 +NENTRY(resume_pop_ds) + movl $GSEL(GDATA_SEL, SEL_KPL),%eax + movl %eax,%es +NENTRY(resume_pop_es) + movl $T_PROTFLT,TF_TRAPNO(%rsp) + jmp calltrap +#endif + +/* + * All traps go through here. Call the generic trap handler, and + * check for ASTs afterwards. + */ +NENTRY(alltraps) + INTRENTRY + sti +calltrap: +#ifdef DIAGNOSTIC + movl CPUVAR(ILEVEL),%ebx +#endif /* DIAGNOSTIC */ + call _C_LABEL(trap) +2: /* Check for ASTs on exit to user mode. */ + cli + CHECK_ASTPENDING(%r11) + je 1f + testb $SEL_RPL,TF_CS(%rsp) + jz 1f +5: CLEAR_ASTPENDING(%r11) + sti + movl $T_ASTFLT,TF_TRAPNO(%rsp) + call _C_LABEL(trap) + jmp 2b +#ifndef DIAGNOSTIC +1: INTRFASTEXIT +#else /* DIAGNOSTIC */ +1: cmpl CPUVAR(ILEVEL),%ebx + jne 3f + INTRFASTEXIT +3: sti + movabsq $4f,%rdi + movl CPUVAR(ILEVEL),%esi + movl %ebx,%edx + xorq %rax,%rax + call _C_LABEL(printf) +#ifdef DDB + int $3 +#endif /* DDB */ + movl %ebx,CPUVAR(ILEVEL) + jmp 2b +4: .asciz "WARNING: SPL NOT LOWERED ON TRAP EXIT %x %x\n" +#endif /* DIAGNOSTIC */ + + +#define __HAVE_GENERIC_SOFT_INTERRUPTS /* XXX */ + + +/* + * Macros for interrupt entry, call to handler, and exit. + * + * XXX + * The interrupt frame is set up to look like a trap frame. This may be a + * waste. The only handler which needs a frame is the clock handler, and it + * only needs a few bits. Xdoreti() needs a trap frame for handling ASTs, but + * it could easily convert the frame on demand. + * + * The direct costs of setting up a trap frame are two pushq's (error code and + * trap number), an addl to get rid of these, and pushing and popping the + * callee-saved registers %esi, %edi, %ebx, and %ebp twice. + * + * If the interrupt frame is made more flexible, INTR can push %eax first and + * decide the ipending case with less overhead, e.g., by avoiding loading the + * segment registers. + * + */ + +#define MY_COUNT _C_LABEL(uvmexp) + +/* XXX See comment in locore.s */ +#ifdef __ELF__ +#define XINTR(name,num) Xintr_/**/name/**/num +#else +#define XINTR(name,num) _Xintr_/**/name/**/num +#endif + +#if NLAPIC > 0 +#ifdef MULTIPROCESSOR +IDTVEC(recurse_lapic_ipi) + INTR_RECURSE_HWFRAME + pushq $0 + pushq $T_ASTFLT + INTRENTRY +IDTVEC(resume_lapic_ipi) + cli + jmp 1f +IDTVEC(intr_lapic_ipi) + pushq $0 + pushq $T_ASTFLT + INTRENTRY + movl $0,_C_LABEL(local_apic)+LAPIC_EOI + movl CPUVAR(ILEVEL),%ebx + cmpl $IPL_IPI,%ebx + jae 2f +1: + incl CPUVAR(IDEPTH) + movl $IPL_IPI,CPUVAR(ILEVEL) + sti + pushq %rbx + call _C_LABEL(x86_ipi_handler) + jmp _C_LABEL(Xdoreti) +2: + orl $(1 << LIR_IPI),CPUVAR(IPENDING) + sti + INTRFASTEXIT + +#if defined(DDB) +IDTVEC(intrddb) +1: + pushq $0 + pushq $T_BPTFLT + INTRENTRY + movl $0xf,%eax + movq %rax,%cr8 + movl $0,_C_LABEL(local_apic)+LAPIC_EOI + sti + call _C_LABEL(ddb_ipi) + xorl %eax,%eax + movq %rax,%cr8 + INTRFASTEXIT +#endif /* DDB */ +#endif /* MULTIPROCESSOR */ + + /* + * Interrupt from the local APIC timer. + */ +IDTVEC(recurse_lapic_ltimer) + INTR_RECURSE_HWFRAME + pushq $0 + pushq $T_ASTFLT + INTRENTRY +IDTVEC(resume_lapic_ltimer) + cli + jmp 1f +IDTVEC(intr_lapic_ltimer) + pushq $0 + pushq $T_ASTFLT + INTRENTRY + movl $0,_C_LABEL(local_apic)+LAPIC_EOI + movl CPUVAR(ILEVEL),%ebx + cmpl $IPL_CLOCK,%ebx + jae 2f +1: + incl CPUVAR(IDEPTH) + movl $IPL_CLOCK,CPUVAR(ILEVEL) + sti + pushq %rbx + xorq %rdi,%rdi + call _C_LABEL(lapic_clockintr) + jmp _C_LABEL(Xdoreti) +2: + orl $(1 << LIR_TIMER),CPUVAR(IPENDING) + sti + INTRFASTEXIT +#endif /* NLAPIC > 0 */ + +#ifdef MULTIPROCESSOR +#define LOCK_KERNEL call _C_LABEL(x86_intlock) +#define UNLOCK_KERNEL call _C_LABEL(x86_intunlock) +#else +#define LOCK_KERNEL +#define UNLOCK_KERNEL +#endif + +#define voidop(num) + + +/* + * This macro defines the generic stub code. Its arguments modifiy it + * for specific PICs. + */ + +#define INTRSTUB(name, num, early_ack, late_ack, mask, unmask, level_mask) \ +IDTVEC(recurse_/**/name/**/num) ;\ + INTR_RECURSE_HWFRAME ;\ + subq $8,%rsp ;\ + pushq $T_ASTFLT /* trap # for doing ASTs */ ;\ + INTRENTRY ;\ +IDTVEC(resume_/**/name/**/num) \ + movq $IREENT_MAGIC,TF_ERR(%rsp) ;\ + movl %ebx,%r13d ;\ + movq CPUVAR(ISOURCES) + (num) * 8, %r14 ;\ + movl IS_MAXLEVEL(%r14),%ebx ;\ + jmp 1f ;\ +IDTVEC(intr_/**/name/**/num) ;\ + pushq $0 /* dummy error code */ ;\ + pushq $T_ASTFLT /* trap # for doing ASTs */ ;\ + INTRENTRY ;\ + movq CPUVAR(ISOURCES) + (num) * 8, %r14 ;\ + mask(num) /* mask it in hardware */ ;\ + early_ack(num) /* and allow other intrs */ ;\ + testq %r14,%r14 ;\ + jz 9f /* stray */ ;\ + movl IS_MAXLEVEL(%r14),%ebx ;\ + movl CPUVAR(ILEVEL),%r13d ;\ + cmpl %ebx,%r13d ;\ + jae 10f /* currently masked; hold it */ ;\ + incl MY_COUNT+V_INTR /* statistical info */ ;\ + incq IS_EVCNT(%r14) ;\ +1: \ + pushq %r13 ;\ + movl %ebx,CPUVAR(ILEVEL) ;\ + sti ;\ + incl CPUVAR(IDEPTH) ;\ + movq IS_HANDLERS(%r14),%rbx ;\ + LOCK_KERNEL ;\ +6: \ + movl IH_LEVEL(%rbx),%r12d ;\ + cmpl %r13d,%r12d ;\ + jle 7f ;\ + movq IH_ARG(%rbx),%rdi ;\ + testq %rdi, %rdi ;\ + jnz 8f ;\ + movq %rsp, %rdi ;\ +8: movl %r12d,CPUVAR(ILEVEL) ;\ + call *IH_FUN(%rbx) /* call it */ ;\ + movq IH_NEXT(%rbx),%rbx /* next handler in chain */ ;\ + testq %rbx,%rbx ;\ + jnz 6b ;\ +5: \ + UNLOCK_KERNEL ;\ + cli ;\ + unmask(num) /* unmask it in hardware */ ;\ + late_ack(num) ;\ + sti ;\ + jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ +7: \ + UNLOCK_KERNEL ;\ + cli ;\ + orl $(1 << num),CPUVAR(IPENDING) ;\ + level_mask(num) ;\ + late_ack(num) ;\ + sti ;\ + jmp _C_LABEL(Xdoreti) /* lower spl and do ASTs */ ;\ +10: \ + cli ;\ + orl $(1 << num),CPUVAR(IPENDING) ;\ + level_mask(num) ;\ + late_ack(num) ;\ + sti ;\ + INTRFASTEXIT ;\ +9: \ + unmask(num) ;\ + late_ack(num) ;\ + sti ;\ + INTRFASTEXIT + +#define ICUADDR IO_ICU1 + +INTRSTUB(legacy,0,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,1,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,2,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,3,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,4,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,5,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,6,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,7,i8259_asm_ack1,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +#undef ICUADDR +#define ICUADDR IO_ICU2 + +INTRSTUB(legacy,8,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,9,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,10,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,11,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,12,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,13,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,14,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) +INTRSTUB(legacy,15,i8259_asm_ack2,voidop,i8259_asm_mask,i8259_asm_unmask, + voidop) + +#if NIOAPIC > 0 + +INTRSTUB(ioapic_edge,0,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,1,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,2,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,3,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,4,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,5,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,6,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,7,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,8,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,9,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,10,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,11,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,12,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,13,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,14,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,15,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,16,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,17,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,18,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,19,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,20,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,21,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,22,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,23,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,24,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,25,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,26,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,27,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,28,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,29,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,30,voidop,ioapic_asm_ack,voidop,voidop,voidop) +INTRSTUB(ioapic_edge,31,voidop,ioapic_asm_ack,voidop,voidop,voidop) + +INTRSTUB(ioapic_level,0,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,1,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,2,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,3,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,4,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,5,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,6,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,7,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,8,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,9,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,10,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,11,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,12,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,13,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,14,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,15,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,16,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,17,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,18,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,19,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,20,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,21,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,22,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,23,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,24,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,25,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,26,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,27,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,28,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,29,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,30,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) +INTRSTUB(ioapic_level,31,voidop,ioapic_asm_ack,voidop,ioapic_unmask,ioapic_mask) + +#endif + + .globl _C_LABEL(i8259_stubs) +_C_LABEL(i8259_stubs): + .quad _C_LABEL(Xintr_legacy0), _C_LABEL(Xrecurse_legacy0) + .quad _C_LABEL(Xresume_legacy0) + .quad _C_LABEL(Xintr_legacy1), _C_LABEL(Xrecurse_legacy1) + .quad _C_LABEL(Xresume_legacy1) + .quad _C_LABEL(Xintr_legacy2), _C_LABEL(Xrecurse_legacy2) + .quad _C_LABEL(Xresume_legacy2) + .quad _C_LABEL(Xintr_legacy3), _C_LABEL(Xrecurse_legacy3) + .quad _C_LABEL(Xresume_legacy3) + .quad _C_LABEL(Xintr_legacy4), _C_LABEL(Xrecurse_legacy4) + .quad _C_LABEL(Xresume_legacy4) + .quad _C_LABEL(Xintr_legacy5), _C_LABEL(Xrecurse_legacy5) + .quad _C_LABEL(Xresume_legacy5) + .quad _C_LABEL(Xintr_legacy6), _C_LABEL(Xrecurse_legacy6) + .quad _C_LABEL(Xresume_legacy6) + .quad _C_LABEL(Xintr_legacy7), _C_LABEL(Xrecurse_legacy7) + .quad _C_LABEL(Xresume_legacy7) + .quad _C_LABEL(Xintr_legacy8), _C_LABEL(Xrecurse_legacy8) + .quad _C_LABEL(Xresume_legacy8) + .quad _C_LABEL(Xintr_legacy9), _C_LABEL(Xrecurse_legacy9) + .quad _C_LABEL(Xresume_legacy9) + .quad _C_LABEL(Xintr_legacy10), _C_LABEL(Xrecurse_legacy10) + .quad _C_LABEL(Xresume_legacy10) + .quad _C_LABEL(Xintr_legacy11), _C_LABEL(Xrecurse_legacy11) + .quad _C_LABEL(Xresume_legacy11) + .quad _C_LABEL(Xintr_legacy12), _C_LABEL(Xrecurse_legacy12) + .quad _C_LABEL(Xresume_legacy12) + .quad _C_LABEL(Xintr_legacy13), _C_LABEL(Xrecurse_legacy13) + .quad _C_LABEL(Xresume_legacy13) + .quad _C_LABEL(Xintr_legacy14), _C_LABEL(Xrecurse_legacy14) + .quad _C_LABEL(Xresume_legacy14) + .quad _C_LABEL(Xintr_legacy15), _C_LABEL(Xrecurse_legacy15) + .quad _C_LABEL(Xresume_legacy15) + +#if NIOAPIC > 0 + .globl _C_LABEL(ioapic_edge_stubs) +_C_LABEL(ioapic_edge_stubs): + .quad _C_LABEL(Xintr_ioapic_edge0), _C_LABEL(Xrecurse_ioapic_edge0) + .quad _C_LABEL(Xresume_ioapic_edge0) + .quad _C_LABEL(Xintr_ioapic_edge1), _C_LABEL(Xrecurse_ioapic_edge1) + .quad _C_LABEL(Xresume_ioapic_edge1) + .quad _C_LABEL(Xintr_ioapic_edge2), _C_LABEL(Xrecurse_ioapic_edge2) + .quad _C_LABEL(Xresume_ioapic_edge2) + .quad _C_LABEL(Xintr_ioapic_edge3), _C_LABEL(Xrecurse_ioapic_edge3) + .quad _C_LABEL(Xresume_ioapic_edge3) + .quad _C_LABEL(Xintr_ioapic_edge4), _C_LABEL(Xrecurse_ioapic_edge4) + .quad _C_LABEL(Xresume_ioapic_edge4) + .quad _C_LABEL(Xintr_ioapic_edge5), _C_LABEL(Xrecurse_ioapic_edge5) + .quad _C_LABEL(Xresume_ioapic_edge5) + .quad _C_LABEL(Xintr_ioapic_edge6), _C_LABEL(Xrecurse_ioapic_edge6) + .quad _C_LABEL(Xresume_ioapic_edge6) + .quad _C_LABEL(Xintr_ioapic_edge7), _C_LABEL(Xrecurse_ioapic_edge7) + .quad _C_LABEL(Xresume_ioapic_edge7) + .quad _C_LABEL(Xintr_ioapic_edge8), _C_LABEL(Xrecurse_ioapic_edge8) + .quad _C_LABEL(Xresume_ioapic_edge8) + .quad _C_LABEL(Xintr_ioapic_edge9), _C_LABEL(Xrecurse_ioapic_edge9) + .quad _C_LABEL(Xresume_ioapic_edge9) + .quad _C_LABEL(Xintr_ioapic_edge10), _C_LABEL(Xrecurse_ioapic_edge10) + .quad _C_LABEL(Xresume_ioapic_edge10) + .quad _C_LABEL(Xintr_ioapic_edge11), _C_LABEL(Xrecurse_ioapic_edge11) + .quad _C_LABEL(Xresume_ioapic_edge11) + .quad _C_LABEL(Xintr_ioapic_edge12), _C_LABEL(Xrecurse_ioapic_edge12) + .quad _C_LABEL(Xresume_ioapic_edge12) + .quad _C_LABEL(Xintr_ioapic_edge13), _C_LABEL(Xrecurse_ioapic_edge13) + .quad _C_LABEL(Xresume_ioapic_edge13) + .quad _C_LABEL(Xintr_ioapic_edge14), _C_LABEL(Xrecurse_ioapic_edge14) + .quad _C_LABEL(Xresume_ioapic_edge14) + .quad _C_LABEL(Xintr_ioapic_edge15), _C_LABEL(Xrecurse_ioapic_edge15) + .quad _C_LABEL(Xresume_ioapic_edge15) + .quad _C_LABEL(Xintr_ioapic_edge16), _C_LABEL(Xrecurse_ioapic_edge16) + .quad _C_LABEL(Xresume_ioapic_edge16) + .quad _C_LABEL(Xintr_ioapic_edge17), _C_LABEL(Xrecurse_ioapic_edge17) + .quad _C_LABEL(Xresume_ioapic_edge17) + .quad _C_LABEL(Xintr_ioapic_edge18), _C_LABEL(Xrecurse_ioapic_edge18) + .quad _C_LABEL(Xresume_ioapic_edge18) + .quad _C_LABEL(Xintr_ioapic_edge19), _C_LABEL(Xrecurse_ioapic_edge19) + .quad _C_LABEL(Xresume_ioapic_edge19) + .quad _C_LABEL(Xintr_ioapic_edge20), _C_LABEL(Xrecurse_ioapic_edge20) + .quad _C_LABEL(Xresume_ioapic_edge20) + .quad _C_LABEL(Xintr_ioapic_edge21), _C_LABEL(Xrecurse_ioapic_edge21) + .quad _C_LABEL(Xresume_ioapic_edge21) + .quad _C_LABEL(Xintr_ioapic_edge22), _C_LABEL(Xrecurse_ioapic_edge22) + .quad _C_LABEL(Xresume_ioapic_edge22) + .quad _C_LABEL(Xintr_ioapic_edge23), _C_LABEL(Xrecurse_ioapic_edge23) + .quad _C_LABEL(Xresume_ioapic_edge23) + .quad _C_LABEL(Xintr_ioapic_edge24), _C_LABEL(Xrecurse_ioapic_edge24) + .quad _C_LABEL(Xresume_ioapic_edge24) + .quad _C_LABEL(Xintr_ioapic_edge25), _C_LABEL(Xrecurse_ioapic_edge25) + .quad _C_LABEL(Xresume_ioapic_edge25) + .quad _C_LABEL(Xintr_ioapic_edge26), _C_LABEL(Xrecurse_ioapic_edge26) + .quad _C_LABEL(Xresume_ioapic_edge26) + .quad _C_LABEL(Xintr_ioapic_edge27), _C_LABEL(Xrecurse_ioapic_edge27) + .quad _C_LABEL(Xresume_ioapic_edge27) + .quad _C_LABEL(Xintr_ioapic_edge28), _C_LABEL(Xrecurse_ioapic_edge28) + .quad _C_LABEL(Xresume_ioapic_edge28) + .quad _C_LABEL(Xintr_ioapic_edge29), _C_LABEL(Xrecurse_ioapic_edge29) + .quad _C_LABEL(Xresume_ioapic_edge29) + .quad _C_LABEL(Xintr_ioapic_edge30), _C_LABEL(Xrecurse_ioapic_edge30) + .quad _C_LABEL(Xresume_ioapic_edge30) + .quad _C_LABEL(Xintr_ioapic_edge31), _C_LABEL(Xrecurse_ioapic_edge31) + .quad _C_LABEL(Xresume_ioapic_edge31) + + .globl _C_LABEL(ioapic_level_stubs) +_C_LABEL(ioapic_level_stubs): + .quad _C_LABEL(Xintr_ioapic_level0), _C_LABEL(Xrecurse_ioapic_level0) + .quad _C_LABEL(Xresume_ioapic_level0) + .quad _C_LABEL(Xintr_ioapic_level1), _C_LABEL(Xrecurse_ioapic_level1) + .quad _C_LABEL(Xresume_ioapic_level1) + .quad _C_LABEL(Xintr_ioapic_level2), _C_LABEL(Xrecurse_ioapic_level2) + .quad _C_LABEL(Xresume_ioapic_level2) + .quad _C_LABEL(Xintr_ioapic_level3), _C_LABEL(Xrecurse_ioapic_level3) + .quad _C_LABEL(Xresume_ioapic_level3) + .quad _C_LABEL(Xintr_ioapic_level4), _C_LABEL(Xrecurse_ioapic_level4) + .quad _C_LABEL(Xresume_ioapic_level4) + .quad _C_LABEL(Xintr_ioapic_level5), _C_LABEL(Xrecurse_ioapic_level5) + .quad _C_LABEL(Xresume_ioapic_level5) + .quad _C_LABEL(Xintr_ioapic_level6), _C_LABEL(Xrecurse_ioapic_level6) + .quad _C_LABEL(Xresume_ioapic_level6) + .quad _C_LABEL(Xintr_ioapic_level7), _C_LABEL(Xrecurse_ioapic_level7) + .quad _C_LABEL(Xresume_ioapic_level7) + .quad _C_LABEL(Xintr_ioapic_level8), _C_LABEL(Xrecurse_ioapic_level8) + .quad _C_LABEL(Xresume_ioapic_level8) + .quad _C_LABEL(Xintr_ioapic_level9), _C_LABEL(Xrecurse_ioapic_level9) + .quad _C_LABEL(Xresume_ioapic_level9) + .quad _C_LABEL(Xintr_ioapic_level10), _C_LABEL(Xrecurse_ioapic_level10) + .quad _C_LABEL(Xresume_ioapic_level10) + .quad _C_LABEL(Xintr_ioapic_level11), _C_LABEL(Xrecurse_ioapic_level11) + .quad _C_LABEL(Xresume_ioapic_level11) + .quad _C_LABEL(Xintr_ioapic_level12), _C_LABEL(Xrecurse_ioapic_level12) + .quad _C_LABEL(Xresume_ioapic_level12) + .quad _C_LABEL(Xintr_ioapic_level13), _C_LABEL(Xrecurse_ioapic_level13) + .quad _C_LABEL(Xresume_ioapic_level13) + .quad _C_LABEL(Xintr_ioapic_level14), _C_LABEL(Xrecurse_ioapic_level14) + .quad _C_LABEL(Xresume_ioapic_level14) + .quad _C_LABEL(Xintr_ioapic_level15), _C_LABEL(Xrecurse_ioapic_level15) + .quad _C_LABEL(Xresume_ioapic_level15) + .quad _C_LABEL(Xintr_ioapic_level16), _C_LABEL(Xrecurse_ioapic_level16) + .quad _C_LABEL(Xresume_ioapic_level16) + .quad _C_LABEL(Xintr_ioapic_level17), _C_LABEL(Xrecurse_ioapic_level17) + .quad _C_LABEL(Xresume_ioapic_level17) + .quad _C_LABEL(Xintr_ioapic_level18), _C_LABEL(Xrecurse_ioapic_level18) + .quad _C_LABEL(Xresume_ioapic_level18) + .quad _C_LABEL(Xintr_ioapic_level19), _C_LABEL(Xrecurse_ioapic_level19) + .quad _C_LABEL(Xresume_ioapic_level19) + .quad _C_LABEL(Xintr_ioapic_level20), _C_LABEL(Xrecurse_ioapic_level20) + .quad _C_LABEL(Xresume_ioapic_level20) + .quad _C_LABEL(Xintr_ioapic_level21), _C_LABEL(Xrecurse_ioapic_level21) + .quad _C_LABEL(Xresume_ioapic_level21) + .quad _C_LABEL(Xintr_ioapic_level22), _C_LABEL(Xrecurse_ioapic_level22) + .quad _C_LABEL(Xresume_ioapic_level22) + .quad _C_LABEL(Xintr_ioapic_level23), _C_LABEL(Xrecurse_ioapic_level23) + .quad _C_LABEL(Xresume_ioapic_level23) + .quad _C_LABEL(Xintr_ioapic_level24), _C_LABEL(Xrecurse_ioapic_level24) + .quad _C_LABEL(Xresume_ioapic_level24) + .quad _C_LABEL(Xintr_ioapic_level25), _C_LABEL(Xrecurse_ioapic_level25) + .quad _C_LABEL(Xresume_ioapic_level25) + .quad _C_LABEL(Xintr_ioapic_level26), _C_LABEL(Xrecurse_ioapic_level26) + .quad _C_LABEL(Xresume_ioapic_level26) + .quad _C_LABEL(Xintr_ioapic_level27), _C_LABEL(Xrecurse_ioapic_level27) + .quad _C_LABEL(Xresume_ioapic_level27) + .quad _C_LABEL(Xintr_ioapic_level28), _C_LABEL(Xrecurse_ioapic_level28) + .quad _C_LABEL(Xresume_ioapic_level28) + .quad _C_LABEL(Xintr_ioapic_level29), _C_LABEL(Xrecurse_ioapic_level29) + .quad _C_LABEL(Xresume_ioapic_level29) + .quad _C_LABEL(Xintr_ioapic_level30), _C_LABEL(Xrecurse_ioapic_level30) + .quad _C_LABEL(Xresume_ioapic_level30) + .quad _C_LABEL(Xintr_ioapic_level31), _C_LABEL(Xrecurse_ioapic_level31) + .quad _C_LABEL(Xresume_ioapic_level31) +#endif + + .data +/* + * Symbols that vmstat -i wants, even though they're not used. + */ + .globl _C_LABEL(intrnames) +_C_LABEL(intrnames): + .globl _C_LABEL(eintrnames) +_C_LABEL(eintrnames): + + .globl _C_LABEL(intrcnt) +_C_LABEL(intrcnt): + .globl _C_LABEL(eintrcnt) +_C_LABEL(eintrcnt): + +/* + * Soft interrupt handlers + */ + .globl _C_LABEL(netisr) +_C_LABEL(netisr): + .word 0 + +IDTVEC(softserial) + movl $IPL_SOFTSERIAL, CPUVAR(ILEVEL) + incl CPUVAR(IDEPTH) +#ifdef MULTIPROCESSOR + call _C_LABEL(x86_softintlock) +#endif + movq CPUVAR(ISOURCES) + SIR_SERIAL * 8, %r12 + incq IS_EVCNT(%r12) + movl $X86_SOFTINTR_SOFTSERIAL,%edi + call _C_LABEL(softintr_dispatch) +#ifdef MULTIPROCESSOR + call _C_LABEL(x86_softintunlock) +#endif + decl CPUVAR(IDEPTH) + jmp *%r13 + +IDTVEC(softnet) + movl $IPL_SOFTNET, CPUVAR(ILEVEL) + incl CPUVAR(IDEPTH) +#ifdef MULTIPROCESSOR + call _C_LABEL(x86_softintlock) +#endif + movq CPUVAR(ISOURCES) + SIR_NET * 8, %r12 + incq IS_EVCNT(%r12) + + xorq %r12,%r12 + xchgl _C_LABEL(netisr),%r12d + + /* XXX Do the legacy netisrs here for now. */ +#define DONETISR(s, c) \ + .globl _C_LABEL(c) ;\ + testl $(1 << s),%r12d ;\ + jz 1f ;\ + call _C_LABEL(c) ;\ +1: +#include <net/netisr_dispatch.h> + + movl $X86_SOFTINTR_SOFTNET,%edi + call _C_LABEL(softintr_dispatch) +#ifdef MULTIPROCESSOR + call _C_LABEL(x86_softintunlock) +#endif + decl CPUVAR(IDEPTH) + jmp *%r13 + +IDTVEC(softclock) + movl $IPL_SOFTCLOCK, CPUVAR(ILEVEL) + incl CPUVAR(IDEPTH) +#ifdef MULTIPROCESSOR + call _C_LABEL(x86_softintlock) +#endif + movq CPUVAR(ISOURCES) + SIR_CLOCK * 8, %r12 + incq IS_EVCNT(%r12) + + movl $X86_SOFTINTR_SOFTCLOCK,%edi + call _C_LABEL(softintr_dispatch) +#ifdef MULTIPROCESSOR + call _C_LABEL(x86_softintunlock) +#endif + decl CPUVAR(IDEPTH) + jmp *%r13 diff --git a/sys/arch/amd64/amd64/vm_machdep.c b/sys/arch/amd64/amd64/vm_machdep.c new file mode 100644 index 00000000000..40d41ee2bf3 --- /dev/null +++ b/sys/arch/amd64/amd64/vm_machdep.c @@ -0,0 +1,379 @@ +/* $OpenBSD: vm_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: vm_machdep.c,v 1.1 2003/04/26 18:39:33 fvdl Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department, and 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. + * + * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + */ + +/* + * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/vnode.h> +#include <sys/buf.h> +#include <sys/user.h> +#include <sys/core.h> +#include <sys/exec.h> +#include <sys/ptrace.h> +#include <sys/signalvar.h> + +#include <uvm/uvm_extern.h> + +#include <machine/cpu.h> +#include <machine/gdt.h> +#include <machine/reg.h> +#include <machine/specialreg.h> +#include <machine/fpu.h> +#include <machine/mtrr.h> + +void setredzone(struct proc *); +void syscall_intern(struct proc *p); /* syscall.c */ + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the kernel stack and pcb, making the child + * ready to run, and marking it so that it can return differently + * than the parent. Returns 1 in the child process, 0 in the parent. + * We currently double-map the user area so that the stack is at the same + * address in each process; in the future we will probably relocate + * the frame pointers on the stack after copying. + */ +void +cpu_fork(struct proc *p1, struct proc *p2, void *stack, size_t stacksize, + void (*func)(void *), void *arg) +{ + struct pcb *pcb = &p2->p_addr->u_pcb; + struct trapframe *tf; + struct switchframe *sf; + + /* + * If fpuproc != p1, then the fpu h/w state is irrelevant and the + * state had better already be in the pcb. This is true for forks + * but not for dumps. + * + * If fpuproc == p1, then we have to save the fpu h/w state to + * p1's pcb so that we can copy it. + */ + if (p1->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p1, 1); + + p2->p_md.md_flags = p1->p_md.md_flags; + syscall_intern(p2); + + /* Copy pcb from proc p1 to p2. */ + if (p1 == curproc) { + /* Sync the PCB before we copy it. */ + savectx(curpcb); + } +#ifdef DIAGNOSTIC + else if (p1 != &proc0) + panic("cpu_fork: curproc"); +#endif + *pcb = p1->p_addr->u_pcb; + + /* + * Preset these so that gdt_compact() doesn't get confused if called + * during the allocations below. + * + * Note: pcb_ldt_sel is handled in the pmap_activate() call when + * we run the new process. + */ + p2->p_md.md_tss_sel = GSEL(GNULL_SEL, SEL_KPL); + + /* + * Activate the addres space. Note this will refresh pcb_ldt_sel. + */ + pmap_activate(p2); + + /* Fix up the TSS. */ + pcb->pcb_tss.tss_rsp0 = (u_int64_t)p2->p_addr + USPACE - 16; + pcb->pcb_tss.tss_ist[0] = (u_int64_t)p2->p_addr + PAGE_SIZE - 16; + p2->p_md.md_tss_sel = tss_alloc(pcb); + + /* + * Copy the trapframe. + */ + p2->p_md.md_regs = tf = (struct trapframe *)pcb->pcb_tss.tss_rsp0 - 1; + *tf = *p1->p_md.md_regs; + + setredzone(p2); + + /* + * If specified, give the child a different stack. + */ + if (stack != NULL) + tf->tf_rsp = (u_int64_t)stack + stacksize; + + sf = (struct switchframe *)tf - 1; + sf->sf_ppl = IPL_NONE; + sf->sf_r12 = (u_int64_t)func; + sf->sf_r13 = (u_int64_t)arg; + if (func == child_return) + sf->sf_rip = (u_int64_t)child_trampoline; + else + sf->sf_rip = (u_int64_t)proc_trampoline; + pcb->pcb_rsp = (u_int64_t)sf; + pcb->pcb_rbp = 0; +} + +void +cpu_swapin(struct proc *p) +{ + setredzone(p); +} + +void +cpu_swapout(struct proc *p) +{ + + /* + * Make sure we save the FP state before the user area vanishes. + */ + fpusave_proc(p, 1); +} + +/* + * cpu_exit is called as the last action during exit. + * + * We clean up a little and then call switch_exit() with the old proc as an + * argument. switch_exit() first switches to proc0's context, and finally + * jumps into switch() to wait for another process to wake up. + */ +void +cpu_exit(struct proc *p) +{ + + /* If we were using the FPU, forget about it. */ + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 0); + + if (p->p_md.md_flags & MDP_USEDMTRR) + mtrr_clean(p); + + /* + * No need to do user LDT cleanup here; it's handled in + * pmap_destroy(). + */ + + uvmexp.swtch++; + switch_exit(p, exit2); +} + +/* + * cpu_wait is called from reaper() to let machine-dependent + * code free machine-dependent resources that couldn't be freed + * in cpu_exit(). + */ +void +cpu_wait(struct proc *p) +{ + /* Nuke the TSS. */ + tss_free(p->p_md.md_tss_sel); +} + +/* + * Dump the machine specific segment at the start of a core dump. + */ +struct md_core { + struct reg intreg; + struct fpreg freg; +}; + +int +cpu_coredump(struct proc *p, struct vnode *vp, struct ucred *cred, + struct core *chdr) +{ + struct md_core md_core; + struct coreseg cseg; + int error; + + CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0); + chdr->c_hdrsize = ALIGN(sizeof(*chdr)); + chdr->c_seghdrsize = ALIGN(sizeof(cseg)); + chdr->c_cpusize = sizeof(md_core); + + /* Save integer registers. */ + error = process_read_regs(p, &md_core.intreg); + if (error) + return error; + + /* Save floating point registers. */ + error = process_read_fpregs(p, &md_core.freg); + if (error) + return error; + + CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU); + cseg.c_addr = 0; + cseg.c_size = chdr->c_cpusize; + + error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize, + (off_t)chdr->c_hdrsize, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, + NULL, p); + if (error) + return error; + + error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&md_core, sizeof(md_core), + (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE, + IO_NODELOCKED|IO_UNIT, cred, NULL, p); + if (error) + return error; + + chdr->c_nseg++; + return 0; +} + +/* + * Set a red zone in the kernel stack after the u. area. + */ +void +setredzone(struct proc *p) +{ +#if 0 + pmap_remove(pmap_kernel(), (vaddr_t)p->p_addr + PAGE_SIZE, + (vaddr_t)p->p_addr + 2 * PAGE_SIZE); + pmap_update(pmap_kernel()); +#endif +} + + +/* + * Move pages from one kernel virtual address to another. + * Both addresses are assumed to reside in the Sysmap. + */ +void +pagemove(caddr_t from, caddr_t to, size_t size) +{ + pt_entry_t *fpte, *tpte, ofpte, otpte; + int32_t cpumask = 0; + +#ifdef DIAGNOSTIC + if ((size & PAGE_MASK) != 0) + panic("pagemove"); +#endif + fpte = kvtopte((vaddr_t)from); + tpte = kvtopte((vaddr_t)to); +#ifdef LARGEPAGES + /* XXX For now... */ + if (*fpte & PG_PS) + panic("pagemove: fpte PG_PS"); + if (*tpte & PG_PS) + panic("pagemove: tpte PG_PS"); +#endif + while (size > 0) { + otpte = *tpte; + ofpte = *fpte; + *tpte++ = *fpte; + *fpte++ = 0; + if (otpte & PG_V) + pmap_tlb_shootdown(pmap_kernel(), + (vaddr_t)to, otpte, &cpumask); + if (ofpte & PG_V) + pmap_tlb_shootdown(pmap_kernel(), + (vaddr_t)from, ofpte, &cpumask); + from += PAGE_SIZE; + to += PAGE_SIZE; + size -= PAGE_SIZE; + } + pmap_tlb_shootnow(cpumask); +} + +/* + * Map a user I/O request into kernel virtual address space. + * Note: the pages are already locked by uvm_vslock(), so we + * do not need to pass an access_type to pmap_enter(). + */ +void +vmapbuf(struct buf *bp, vsize_t len) +{ + vaddr_t faddr, taddr, off; + paddr_t fpa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + faddr = trunc_page((vaddr_t)bp->b_saveaddr = bp->b_data); + off = (vaddr_t)bp->b_data - faddr; + len = round_page(off + len); + taddr= uvm_km_valloc_wait(phys_map, len); + bp->b_data = (caddr_t)(taddr + off); + /* + * The region is locked, so we expect that pmap_pte() will return + * non-NULL. + * XXX: unwise to expect this in a multithreaded environment. + * anything can happen to a pmap between the time we lock a + * region, release the pmap lock, and then relock it for + * the pmap_extract(). + * + * no need to flush TLB since we expect nothing to be mapped + * where we we just allocated (TLB will be flushed when our + * mapping is removed). + */ + while (len) { + (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map), + faddr, &fpa); + pmap_kenter_pa(taddr, fpa, VM_PROT_READ|VM_PROT_WRITE); + faddr += PAGE_SIZE; + taddr += PAGE_SIZE; + len -= PAGE_SIZE; + } +} + +/* + * Unmap a previously-mapped user I/O request. + */ +void +vunmapbuf(struct buf *bp, vsize_t len) +{ + vaddr_t addr, off; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + addr = trunc_page((vaddr_t)bp->b_data); + off = (vaddr_t)bp->b_data - addr; + len = round_page(off + len); + pmap_kremove(addr, len); + pmap_update(pmap_kernel()); + uvm_km_free_wakeup(phys_map, addr, len); + bp->b_data = bp->b_saveaddr; + bp->b_saveaddr = 0; +} diff --git a/sys/arch/amd64/amd64/wscons_machdep.c b/sys/arch/amd64/amd64/wscons_machdep.c new file mode 100644 index 00000000000..47d05e7e942 --- /dev/null +++ b/sys/arch/amd64/amd64/wscons_machdep.c @@ -0,0 +1,169 @@ +/* $OpenBSD: wscons_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/* + * Copyright (c) 2001 Aaron Campbell + * 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 Aaron Campbell. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 HIS RELATIVES 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 MIND, 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/extent.h> + +#include <machine/bus.h> + +#include <dev/cons.h> + +#include "vga.h" +#include "ega.h" +#include "pcdisplay.h" +#if (NVGA > 0) || (NEGA > 0) || (NPCDISPLAY > 0) +#include <dev/ic/mc6845reg.h> +#include <dev/ic/pcdisplayvar.h> +#if (NVGA > 0) +#include <dev/ic/vgareg.h> +#include <dev/ic/vgavar.h> +#endif +#if (NEGA > 0) +#include <dev/isa/egavar.h> +#endif +#if (NPCDISPLAY > 0) +#include <dev/isa/pcdisplayvar.h> +#endif +#endif + +#include "wsdisplay.h" +#if NWSDISPLAY > 0 +#include <dev/wscons/wsdisplayvar.h> +#endif + +#include "pckbc.h" +#if (NPCKBC > 0) +#include <dev/isa/isareg.h> +#include <dev/ic/i8042reg.h> +#include <dev/ic/pckbcvar.h> +#endif +#include "pckbd.h" /* for pckbc_machdep_cnattach */ +#include "ukbd.h" +#if (NPCKBD > 0) || (NUKBD > 0) +#include <dev/wscons/wskbdvar.h> +#endif +#if (NUKBD > 0) +#include <dev/usb/ukbdvar.h> +#endif + +void wscnprobe(struct consdev *); +void wscninit(struct consdev *); +void wscnputc(dev_t, char); +int wscngetc(dev_t); +void wscnpollc(dev_t, int); + +void +wscnprobe(cp) + struct consdev *cp; +{ + int maj; + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) { + if (cdevsw[maj].d_open == wsdisplayopen) + break; + } + + if (maj == nchrdev) { + /* we are not in cdevsw[], give up */ + panic("wsdisplay is not in cdevsw[]"); + } + + cp->cn_dev = makedev(maj, 0); + cp->cn_pri = CN_INTERNAL; +} + +void +wscninit(cp) + struct consdev *cp; +{ + static int initted; + + if (initted) + return; + + initted = 1; + +#if (NVGA > 0) || (NEGA > 0) || (NPCDISPLAY > 0) +#if (NVGA > 0) + if (!vga_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM, -1, 1)) + goto dokbd; +#endif +#if (NEGA > 0) + if (!ega_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM)) + goto dokbd; +#endif +#if (NPCDISPLAY > 0) + if (!pcdisplay_cnattach(X86_BUS_SPACE_IO, X86_BUS_SPACE_MEM)) + goto dokbd; +#endif + if (0) goto dokbd; /* XXX stupid gcc */ +dokbd: +#if (NPCKBC > 0) + if (!pckbc_cnattach(X86_BUS_SPACE_IO, IO_KBD, KBCMDP, PCKBC_KBD_SLOT)) + return; +#endif +#if (NUKBD > 0) + if (!ukbd_cnattach()) + return; +#endif +#endif /* VGA | EGA | PCDISPLAY */ + return; +} + +void +wscnputc(dev, i) + dev_t dev; + char i; +{ + wsdisplay_cnputc(dev, (int)i); +} + +int +wscngetc(dev) + dev_t dev; +{ + return (wskbd_cngetc(dev)); +} + +void +wscnpollc(dev, on) + dev_t dev; + int on; +{ + wskbd_cnpollc(dev, on); +} diff --git a/sys/arch/amd64/compile/.cvsignore b/sys/arch/amd64/compile/.cvsignore new file mode 100644 index 00000000000..db5b0e04a3a --- /dev/null +++ b/sys/arch/amd64/compile/.cvsignore @@ -0,0 +1 @@ +GENERIC diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC new file mode 100644 index 00000000000..0cd955cdf85 --- /dev/null +++ b/sys/arch/amd64/conf/GENERIC @@ -0,0 +1,73 @@ +# $OpenBSD: GENERIC,v 1.1 2004/01/28 01:39:39 mickey Exp $ + +machine amd64 + +include "../../../conf/GENERIC" + +maxusers 32 + +config bsd swap generic +option DEBUG +option SYSCALL_DEBUG + +mainbus0 at root +cpu* at mainbus? + +isa0 at mainbus0 +pci* at mainbus0 bus ? + +option PCIVERBOSE +pchb* at pci? dev ? function ? +ppb* at pci? dev ? function ? +pci* at ppb? bus ? +pci* at pchb? bus ? + +pckbc0 at isa? +pckbd* at pckbc? + +com0 at isa? port 0x3f8 irq 4 # standard PC serial ports +com1 at isa? port 0x2f8 irq 3 + +#vga0 at isa? +vga* at pci? dev ? function ? +wsdisplay* at vga? console ? +wskbd* at pckbd? console ? + +skc* at pci? dev ? function ? +sk* at skc? +fxp* at pci? dev ? function ? +eephy* at mii? phy ? +inphy* at mii? phy ? +iophy* at mii? phy ? +nsphy* at mii? phy ? +ukphy* at mii? phy ? + +ahc* at pci? dev ? function ? # Adaptec 2940 SCSI controllers +scsibus* at ahc? + +pciide* at pci? dev ? function ? +wd* at pciide? channel ? drive ? flags 0x0000 + +# PCI USB Controllers +uhci* at pci? # Universal Host Controller (Intel) +ohci* at pci? # Open Host Controller + +# USB bus support +usb* at uhci? +usb* at ohci? + +uhub* at usb? # USB Hubs +uhub* at uhub? port ? configuration ? # USB Hubs +ums* at uhidev? reportid ? +wsmouse* at ums? mux 0 +uhidev* at uhub? port ? configuration ? interface ? +ukbd* at uhidev? reportid ? +wskbd* at ukbd? console ? mux 1 +uhid* at uhidev? reportid ? + +sd* at scsibus? target ? lun ? # SCSI disk drives +cd* at scsibus? target ? lun ? # SCSI CD-ROM drives + +# mouse & keyboard multiplexor pseudo-devices +pseudo-device wsmux 2 +pseudo-device crypto 1 diff --git a/sys/arch/amd64/conf/Makefile.amd64 b/sys/arch/amd64/conf/Makefile.amd64 new file mode 100644 index 00000000000..4909063e7dc --- /dev/null +++ b/sys/arch/amd64/conf/Makefile.amd64 @@ -0,0 +1,214 @@ +# $OpenBSD: Makefile.amd64,v 1.1 2004/01/28 01:39:39 mickey Exp $ + +# Makefile for OpenBSD +# +# This makefile is constructed from a machine description: +# config machineid +# Most changes should be made in the machine description +# /sys/arch/amd64/conf/``machineid'' +# after which you should do +# config machineid +# Machine generic makefile changes should be made in +# /sys/arch/amd64/conf/Makefile.amd64 +# after which config should be rerun for all machines of that type. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE +# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING +# +# -DTRACE compile in kernel tracing hooks +# -DQUOTA compile in file system quotas + +# DEBUG is set to -g if debugging. +# PROF is set to -pg if profiling. + +.include <bsd.own.mk> + +MKDEP?= mkdep +SIZE?= size +STRIP?= strip + +# source tree is located via $S relative to the compilation directory +.ifndef S +S!= cd ../../../..; pwd +.endif +AMD64= $S/arch/amd64 + +INCLUDES= -nostdinc -I. -I$S/arch -I$S +CPPFLAGS= ${INCLUDES} ${IDENT} -D_KERNEL -U__NetBSD__ -D__OpenBSD__ \ + -Damd64 -Dx86_64 +CDIAGFLAGS= -Werror -Wall -Wstrict-prototypes -Wmissing-prototypes \ + -Wno-uninitialized -Wno-format -Wno-main -Wno-sign-compare + +CMACHFLAGS+= -mcmodel=kernel -mno-red-zone -fno-strict-aliasing \ + -mno-sse2 -mno-sse -mno-3dnow -mno-mmx -msoft-float \ + -fno-builtin-printf -fno-builtin-log +# -fno-stack-protector + +COPTS?= -O2 +CFLAGS= ${DEBUG} ${CDIAGFLAGS} ${CMACHFLAGS} ${COPTS} ${PIPE} +AFLAGS= -x assembler-with-cpp -traditional-cpp -D_LOCORE +LINKFLAGS= -Ttext 0xffffffff80100000 -e start -X +STRIPFLAGS= -g -x + +HOSTCC= ${CC} +HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//} +HOSTED_CFLAGS= ${CFLAGS} + +### find out what to use for libkern +.include "$S/lib/libkern/Makefile.inc" +.ifndef PROF +LIBKERN= ${KERNLIB} +.else +LIBKERN= ${KERNLIB_PROF} +.endif + +### find out what to use for libcompat +.include "$S/compat/common/Makefile.inc" +.ifndef PROF +LIBCOMPAT= ${COMPATLIB} +.else +LIBCOMPAT= ${COMPATLIB_PROF} +.endif + +# compile rules: rules are named ${TYPE}_${SUFFIX}${CONFIG_DEP} +# where TYPE is NORMAL, DRIVER, or PROFILE; SUFFIX is the file suffix, +# capitalized (e.g. C for a .c file), and CONFIG_DEP is _C if the file +# is marked as config-dependent. + +NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +NORMAL_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +DRIVER_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +DRIVER_C_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} ${PARAM} -c $< + +NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} -c $< +NORMAL_S_C= ${CC} ${AFLAGS} ${CPPFLAGS} ${PARAM} -c $< + +HOSTED_C= ${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $< + +%OBJS + +%CFILES + +%SFILES + +# load lines for config "xxx" will be emitted as: +# xxx: ${SYSTEM_DEP} swapxxx.o +# ${SYSTEM_LD_HEAD} +# ${SYSTEM_LD} swapxxx.o +# ${SYSTEM_LD_TAIL} +SYSTEM_OBJ= locore.o vector.o copy.o microtime.o spl.o \ + param.o ioconf.o ${OBJS} ${LIBKERN} ${LIBCOMPAT} +SYSTEM_DEP= Makefile ${SYSTEM_OBJ} +SYSTEM_LD_HEAD= rm -f $@ +SYSTEM_LD= @echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_OBJ}' vers.o; \ + ${LD} ${LINKFLAGS} -o $@ ${SYSTEM_OBJ} vers.o +SYSTEM_LD_TAIL= @${SIZE} $@; chmod 755 $@ + +DEBUG?= +.if ${DEBUG} == "-g" +LINKFLAGS+= -X +SYSTEM_LD_TAIL+=; \ + echo cp $@ $@.gdb; rm -f $@.gdb; cp $@ $@.gdb; \ + echo ${STRIP} ${STRIPFLAGS} $@; ${STRIP} ${STRIPFLAGS} $@ +.else +LINKFLAGS+= -x +.endif + +%LOAD + +assym.h: $S/kern/genassym.sh ${AMD64}/amd64/genassym.cf Makefile + sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} \ + ${PARAM} < ${AMD64}/amd64/genassym.cf > assym.h.tmp && \ + mv -f assym.h.tmp assym.h + +param.c: $S/conf/param.c + rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${NORMAL_C_C} + +ioconf.o: ioconf.c + ${NORMAL_C} + +newvers: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP} + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c + + +clean:: + rm -f eddep *bsd bsd.gdb tags *.[io] [a-z]*.s \ + [Ee]rrs linterrs makelinks assym.h + +lint: + @lint -hbxncez -Dvolatile= ${CPPFLAGS} ${PARAM} -UKGDB \ + ${CFILES} ${AMD64}/amd64/swapgeneric.c ioconf.c param.c | \ + grep -v 'static function .* unused' + +tags: + @echo "see $S/kern/Makefile for tags" + +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 makelinks + +AFILES= ${AMD64}/amd64/locore.S ${AMD64}/amd64/vector.S ${AMD64}/amd64/copy.S \ + ${AMD64}/amd64/microtime.S ${AMD64}/amd64/spl.S +SRCS= param.c ioconf.c ${AFILES} ${CFILES} ${SFILES} +depend:: .depend +.depend: ${SRCS} assym.h param.c ${APMINC} + ${MKDEP} ${AFLAGS} ${CPPFLAGS} ${AFILES} + ${MKDEP} -a ${CFLAGS} ${CPPFLAGS} param.c ioconf.c ${CFILES} +# ${MKDEP} -a ${AFLAGS} ${CPPFLAGS} ${SFILES} + + +# depend on root or device configuration +autoconf.o conf.o: Makefile + +# depend on network or filesystem configuration +uipc_domain.o uipc_proto.o vfs_conf.o: Makefile +if.o if_tun.o if_loop.o if_ethersubr.o: Makefile +if_arp.o if_ether.o: Makefile +ip_input.o ip_output.o in_pcb.o in_proto.o: Makefile +tcp_subr.o tcp_timer.o tcp_output.o: Makefile + +# depend on maxusers +machdep.o: Makefile + +# depend on CPU configuration +locore.o machdep.o: Makefile + + +locore.o: ${AMD64}/amd64/locore.S assym.h + ${NORMAL_S} + +vector.o: ${AMD64}/amd64/vector.S assym.h + ${NORMAL_S} + +copy.o: ${AMD64}/amd64/copy.S assym.h + ${NORMAL_S} + +microtime.o: ${AMD64}/amd64/microtime.S assym.h + ${NORMAL_S} + +spl.o: ${AMD64}/amd64/spl.S assym.h + ${NORMAL_S} + +# The install target can be redefined by putting a +# install-kernel-${MACHINE_NAME} target into /etc/mk.conf +MACHINE_NAME!= uname -n +install: install-kernel-${MACHINE_NAME} +.if !target(install-kernel-${MACHINE_NAME}}) +install-kernel-${MACHINE_NAME}: + rm -f /obsd + ln /bsd /obsd + cp bsd /nbsd + mv /nbsd /bsd +.endif + +%RULES diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 new file mode 100644 index 00000000000..608a9f4ac38 --- /dev/null +++ b/sys/arch/amd64/conf/files.amd64 @@ -0,0 +1,145 @@ +# $OpenBSD: files.amd64,v 1.1 2004/01/28 01:39:39 mickey Exp $ + +maxpartitions 16 +maxusers 2 16 128 + +file arch/amd64/amd64/autoconf.c +file arch/amd64/amd64/conf.c +file arch/amd64/amd64/disksubr.c disk +file arch/amd64/amd64/gdt.c +file arch/amd64/amd64/machdep.c +file arch/amd64/amd64/identcpu.c +file arch/amd64/amd64/mem.c +file arch/amd64/amd64/pmap.c +file arch/amd64/amd64/process_machdep.c +file arch/amd64/amd64/sys_machdep.c +file arch/amd64/amd64/syscall.c +file arch/amd64/amd64/trap.c +file arch/amd64/amd64/vm_machdep.c +file arch/amd64/amd64/fpu.c +file arch/amd64/amd64/Locore.c +file arch/amd64/amd64/softintr.c +file arch/amd64/amd64/i8259.c +file arch/amd64/amd64/cacheinfo.c + +file arch/amd64/amd64/intr.c +file arch/amd64/amd64/bus_space.c +file arch/amd64/amd64/bus_dma.c + +file arch/amd64/amd64/consinit.c +file dev/cons.c +file dev/cninit.c + +file arch/amd64/amd64/db_disasm.c ddb +file arch/amd64/amd64/db_interface.c ddb +file arch/amd64/amd64/db_memrw.c ddb +file arch/amd64/amd64/db_trace.c ddb + +file netinet/in_cksum.c inet + +# Basic clock - required +file arch/amd64/isa/clock.c +file dev/clock_subr.c + + +include "dev/mii/files.mii" + +include "scsi/files.scsi" + +include "dev/i2o/files.i2o" + +include "dev/atapiscsi/files.atapiscsi" +include "dev/ata/files.ata" + +define mainbus { } +device mainbus: isabus, pcibus, mainbus +attach mainbus at root +file arch/amd64/amd64/mainbus.c mainbus + +define cpu { [apid = -1] } +device cpu +attach cpu at mainbus +file arch/amd64/amd64/cpu.c cpu + + +define lapic +file arch/amd64/amd64/lapic.c lapic needs-flag + +device ioapic: lapic +attach ioapic at mainbus +file arch/amd64/amd64/ioapic.c ioapic needs-flag + +# +# PCI drivers +# + +include "dev/pci/files.pci" +file arch/amd64/pci/pci_machdep.c pci +file arch/amd64/pci/pciide_machdep.c pciide + +# PCI Host bridge chipsets +device pchb: pcibus +attach pchb at pci +file arch/amd64/pci/pchb.c pchb + +# PCI-ISA bridges +device pcib: isabus +attach pcib at pci +file arch/amd64/pci/pcib.c pcib + +device aapic +attach aapic at pci +file arch/amd64/pci/aapic.c aapic + +# +# ISA drivers +# + +include "dev/isa/files.isa" +include "dev/isa/files.isapnp" +file arch/amd64/isa/isa_machdep.c isa + +# attribute used to represent the "keyboard controller" +# XXX should be a real device +define pckbcport { [irq = -1], [port = -1] } + +include "dev/wscons/files.wscons" +include "dev/pckbc/files.pckbc" + +file arch/amd64/amd64/wscons_machdep.c wsdisplay + +device sysbeep +attach sysbeep at pcppi + +# Floppy disk controller +device fdc { drive = - 1 } +attach fdc at isa +file dev/isa/fdc.c fdc needs-flag + +device fd: disk, isa_dma +attach fd at fdc +file dev/isa/fd.c fd needs-flag + +# +# USB +# +include "dev/usb/files.usb" + +# +# FireWire +# +include "dev/ieee1394/files.ieee1394" + +# +# device major numbers +# + +major {ccd = 16} +major {vnd = 14} +major {sd = 4} +major {st = 5} +major {cd = 6} +major {rd = 17} +major {wd = 0} +major {wt = 3} +major {fd = 2} diff --git a/sys/arch/amd64/include/ansi.h b/sys/arch/amd64/include/ansi.h new file mode 100644 index 00000000000..eba619188a4 --- /dev/null +++ b/sys/arch/amd64/include/ansi.h @@ -0,0 +1,87 @@ +/* $NetBSD: ansi.h,v 1.1 2003/04/26 18:39:36 fvdl Exp $ */ + +/*- + * Copyright (c) 1990, 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. + * + * @(#)ansi.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _ANSI_H_ +#define _ANSI_H_ + +/* + * Types which are fundamental to the implementation and may appear in + * more than one standard header are defined here. Standard headers + * then use: + * #ifdef _BSD_SIZE_T_ + * typedef _BSD_SIZE_T_ size_t; + * #undef _BSD_SIZE_T_ + * #endif + */ +#define _BSD_CLOCK_T_ unsigned int /* clock() */ +#define _BSD_PTRDIFF_T_ long /* ptr1 - ptr2 */ +#define _BSD_SIZE_T_ unsigned long /* sizeof() */ +#define _BSD_SSIZE_T_ long /* byte count or error */ +#define _BSD_TIME_T_ int /* time() */ +#ifdef __GNUC__ +#define _BSD_VA_LIST_ __builtin_va_list /* GCC built-in type */ +#else +#define _BSD_VA_LIST_ char * /* XXXfvdl should be ok? */ +#endif +#define _BSD_CLOCKID_T_ int /* clockid_t */ +#define _BSD_TIMER_T_ int /* timer_t */ + +/* + * Runes (wchar_t) is declared to be an ``int'' instead of the more natural + * ``unsigned long'' or ``long''. Two things are happening here. It is not + * unsigned so that EOF (-1) can be naturally assigned to it and used. Also, + * it looks like 10646 will be a 31 bit standard. This means that if your + * ints cannot hold 32 bits, you will be in trouble. The reason an int was + * chosen over a long is that the is*() and to*() routines take ints (says + * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you + * lose a bit of ANSI conformance, but your programs will still work. + * + * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t + * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains + * defined for ctype.h. + */ +#define _BSD_WCHAR_T_ int /* wchar_t */ +#define _BSD_WINT_T_ int /* wint_t */ +#define _BSD_RUNE_T_ int /* rune_t */ + +/* + * We describe off_t here so its declaration can be visible to + * stdio without pulling in all of <sys/type.h>, thus appeasing ANSI. + */ +#define _BSD_OFF_T_ long long /* file offset */ + +#endif /* _ANSI_H_ */ diff --git a/sys/arch/amd64/include/apicvar.h b/sys/arch/amd64/include/apicvar.h new file mode 100644 index 00000000000..e40b9552c18 --- /dev/null +++ b/sys/arch/amd64/include/apicvar.h @@ -0,0 +1,58 @@ +/* $OpenBSD: apicvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: apicvar.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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. + */ + +#ifndef _X86_APICVAR_H_ +#define _X86_APICVAR_H_ + +struct apic_attach_args { + const char *aaa_name; + int apic_id; + int apic_version; + int flags; +#define IOAPIC_PICMODE 0x01 +#define IOAPIC_VWIRE 0x02 + paddr_t apic_address; + int apic_vecbase; +}; + +void apic_format_redir(char *, char *, int, u_int32_t, u_int32_t); + +#endif /* !_X86_APICVAR_H_ */ diff --git a/sys/arch/amd64/include/apmvar.h b/sys/arch/amd64/include/apmvar.h new file mode 100644 index 00000000000..7be38bb9db4 --- /dev/null +++ b/sys/arch/amd64/include/apmvar.h @@ -0,0 +1,300 @@ +/* XXX - DSR */ +/* $OpenBSD: apmvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/* + * Copyright (c) 1995 John T. Kohl + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `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 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 _I386_APMVAR_H_ +#define _I386_APMVAR_H_ + +#include <sys/ioccom.h> + +/* Advanced Power Management (v1.0 and v1.1 specification) + * functions/defines/etc. + */ + +#define APM_VERSION 0x0102 + +/* + * APM info word from boot loader + */ +#define APM_16BIT_SUPPORTED 0x00010000 +#define APM_32BIT_SUPPORTED 0x00020000 +#define APM_IDLE_SLOWS 0x00040000 +#define APM_BIOS_PM_DISABLED 0x00080000 +#define APM_BIOS_PM_DISENGAGED 0x00100000 +#define APM_MAJOR(f) (((f) >> 8) & 0xff) +#define APM_MINOR(f) ((f) & 0xff) +#define APM_VERMASK 0x0000ffff +#define APM_NOCLI 0x00010000 +#define APM_BEBATT 0x00020000 + +/* APM error codes */ +#define APM_ERR_CODE(regs) (((regs)->ax & 0xff00) >> 8) +#define APM_ERR_PM_DISABLED 0x01 +#define APM_ERR_REALALREADY 0x02 +#define APM_ERR_NOTCONN 0x03 +#define APM_ERR_16ALREADY 0x05 +#define APM_ERR_16NOTSUPP 0x06 +#define APM_ERR_32ALREADY 0x07 +#define APM_ERR_32NOTSUPP 0x08 +#define APM_ERR_UNRECOG_DEV 0x09 +#define APM_ERR_ERANGE 0x0A +#define APM_ERR_NOTENGAGED 0x0B +#define APM_ERR_EOPNOSUPP 0x0C +#define APM_ERR_RTIMER_DISABLED 0x0D +#define APM_ERR_UNABLE 0x60 +#define APM_ERR_NOEVENTS 0x80 +#define APM_ERR_NOT_PRESENT 0x86 + +#define APM_DEV_APM_BIOS 0x0000 +#define APM_DEV_ALLDEVS 0x0001 +/* device classes are high byte; device IDs go in low byte */ +#define APM_DEV_DISPLAY(x) (0x0100|((x)&0xff)) +#define APM_DEV_DISK(x) (0x0200|((x)&0xff)) +#define APM_DEV_PARALLEL(x) (0x0300|((x)&0xff)) +#define APM_DEV_SERIAL(x) (0x0400|((x)&0xff)) +#define APM_DEV_NETWORK(x) (0x0500|((x)&0xff)) +#define APM_DEV_PCMCIA(x) (0x0600|((x)&0xff)) +#define APM_DEV_BATTERIES(x) (0x8000|((x)&0xff)) +#define APM_DEV_ALLUNITS 0xff +/* 0x8100-0xDFFF - reserved */ +/* 0xE000-0xEFFF - OEM-defined */ +/* 0xF000-0xFFFF - reserved */ + +#define APM_INSTCHECK 0x5300 /* int15 only */ +#define APM_16BIT_SUPPORT 0x01 +#define APM_32BIT_SUPPORT 0x02 +#define APM_CPUIDLE_SLOW 0x04 +#define APM_DISABLED 0x08 +#define APM_DISENGAGED 0x10 + +#define APM_REAL_CONNECT 0x5301 /* int15 only */ +#define APM_PROT16_CONNECT 0x5302 /* int15 only */ +#define APM_PROT32_CONNECT 0x5303 /* int15 only */ +#define APM_DISCONNECT 0x5304 /* %bx = APM_DEV_APM_BIOS */ + +#define APM_CPU_IDLE 0x5305 +#define APM_CPU_BUSY 0x5306 + +#define APM_SET_PWR_STATE 0x5307 +#define APM_SYS_READY 0x0000 /* %cx */ +#define APM_SYS_STANDBY 0x0001 +#define APM_SYS_SUSPEND 0x0002 +#define APM_SYS_OFF 0x0003 +#define APM_LASTREQ_INPROG 0x0004 +#define APM_LASTREQ_REJECTED 0x0005 +/* 0x0006 - 0x001f Reserved system states */ +/* 0x0020 - 0x003f OEM-defined system states */ +/* 0x0040 - 0x007f OEM-defined device states */ +/* 0x0080 - 0xffff Reserved device states */ + +/* system standby is device ID (%bx) 0x0001, APM_SYS_STANDBY */ +/* system suspend is device ID (%bx) 0x0001, APM_SYS_SUSPEND */ + +#define APM_PWR_MGT_ENABLE 0x5308 +#define APM_MGT_ALL 0xffff /* %bx */ +#define APM_MGT_DISABLE 0x0 /* %cx */ +#define APM_MGT_ENABLE 0x1 + +#define APM_SYSTEM_DEFAULTS 0x5309 +#define APM_DEFAULTS_ALL 0xffff /* %bx */ + +#define APM_POWER_STATUS 0x530a +#define APM_AC_OFF 0x00 +#define APM_AC_ON 0x01 +#define APM_AC_BACKUP 0x02 +#define APM_AC_UNKNOWN 0xff +#define APM_BATT_HIGH 0x00 +#define APM_BATT_LOW 0x01 +#define APM_BATT_CRITICAL 0x02 +#define APM_BATT_CHARGING 0x03 +#define APM_BATT_UNKNOWN 0xff +#define APM_BATT_FLAG_HIGH 0x01 +#define APM_BATT_FLAG_LOW 0x02 +#define APM_BATT_FLAG_CRITICAL 0x04 +#define APM_BATT_FLAG_CHARGING 0x08 +#define APM_BATT_FLAG_NOBATTERY 0x10 +#define APM_BATT_FLAG_NOSYSBATT 0x80 +#define APM_BATT_LIFE_UNKNOWN 0xff +#define BATT_STATE(regp) ((regp)->bx & 0xff) +#define BATT_FLAGS(regp) (((regp)->cx & 0xff00) >> 8) +#define AC_STATE(regp) (((regp)->bx & 0xff00) >> 8) +#define BATT_LIFE(regp) ((regp)->cx & 0xff) /* in % */ +/* Return time in minutes. According to the APM 1.2 spec: + DX = Remaining battery life -- time units + Bit 15 = 0 Time units are seconds + = 1 Time units are minutes + Bits 14-0 = Number of seconds or minutes */ +#define BATT_REMAINING(regp) (((regp)->dx & 0x8000) ? \ + ((regp)->dx & 0x7fff) : \ + ((regp)->dx & 0x7fff)/60) +#define BATT_REM_VALID(regp) (((regp)->dx & 0xffff) != 0xffff) +#define BATT_COUNT(regp) ((regp)->si) + +#define APM_GET_PM_EVENT 0x530b +#define APM_NOEVENT 0x0000 +#define APM_STANDBY_REQ 0x0001 /* %bx on return */ +#define APM_SUSPEND_REQ 0x0002 +#define APM_NORMAL_RESUME 0x0003 +#define APM_CRIT_RESUME 0x0004 /* suspend/resume happened + without us */ +#define APM_BATTERY_LOW 0x0005 +#define APM_POWER_CHANGE 0x0006 +#define APM_UPDATE_TIME 0x0007 +#define APM_CRIT_SUSPEND_REQ 0x0008 +#define APM_USER_STANDBY_REQ 0x0009 +#define APM_USER_SUSPEND_REQ 0x000A +#define APM_SYS_STANDBY_RESUME 0x000B +#define APM_CAPABILITY_CHANGE 0x000C /* apm v1.2 */ +/* 0x000d - 0x00ff Reserved system events */ +/* 0x0100 - 0x01ff Reserved device events */ +/* 0x0200 - 0x02ff OEM-defined APM events */ +/* 0x0300 - 0xffff Reserved */ +#define APM_EVENT_MASK 0xffff + +#define APM_EVENT_COMPOSE(t,i) ((((i) & 0x7fff) << 16)|((t) & APM_EVENT_MASK)) +#define APM_EVENT_TYPE(e) ((e) & APM_EVENT_MASK) +#define APM_EVENT_INDEX(e) ((e) >> 16) + +#define APM_GET_POWER_STATE 0x530c +#define APM_DEVICE_MGMT_ENABLE 0x530d + +#define APM_DRIVER_VERSION 0x530e +/* %bx should be DEV value (APM_DEV_APM_BIOS) + %ch = driver major vno + %cl = driver minor vno + return: %ah = conn major; %al = conn minor + */ +#define APM_CONN_MINOR(regp) ((regp)->ax & 0xff) +#define APM_CONN_MAJOR(regp) (((regp)->ax & 0xff00) >> 8) + +#define APM_PWR_MGT_ENGAGE 0x530F +#define APM_MGT_DISENGAGE 0x0 /* %cx */ +#define APM_MGT_ENGAGE 0x1 + +/* %bx - APM_DEV_APM_BIOS + * %bl - number of batteries + * %cx - capabilities + */ +#define APM_GET_CAPABILITIES 0x5310 +#define APM_NBATTERIES(regp) ((regp)->bx) +#define APM_GLOBAL_STANDBY 0x0001 +#define APM_GLOBAL_SUSPEND 0x0002 +#define APM_RTIMER_STANDBY 0x0004 /* resume time wakes up */ +#define APM_RTIMER_SUSPEND 0x0008 +#define APM_IRRING_STANDBY 0x0010 /* internal ring wakes up */ +#define APM_IRRING_SUSPEND 0x0020 +#define APM_PCCARD_STANDBY 0x0040 /* pccard wakes up */ +#define APM_PCCARD_SUSPEND 0x0080 + +/* %bx - APM_DEV_APM_BIOS + * %cl - function + * for %cl=2 (set resume timer) + * %ch - seconds in BCD + * %dh - hours in BCD + * %dl - minutes in BCD + * %si - month in BCD (high), day in BCD (low) + * %di - year in BCD + */ +#define APM_RESUME_TIMER 0x5311 +#define APM_RT_DISABLE 0x0 +#define APM_RT_GET 0x1 +#define APM_RT_SET 0x2 + +/* %bx - APM_DEV_APM_BIOS + * %cx - function + */ +#define APM_RESUME_ON_RING 0x5312 +#define APM_ROR_DISABLE 0x0 +#define APM_ROR_ENABLE 0x1 +#define APM_ROR_STATUS 0x2 + +/* %bx - APM_EDV_APM_BIOS + * %cx - function + */ +#define APM_INACTIVITY_TIMER 0x5313 +#define APM_IT_DISABLE 0x0 +#define APM_IT_ENABLE 0x1 +#define APM_IT_STATUS 0x2 + +/* %bh - function */ +#define APM_OEM 0x5380 +#define APM_OEM_INSTCHECK 0x7f /* %bx - OEM ID */ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#define APM_BATTERY_ABSENT 4 + +struct apm_power_info { + u_char battery_state; + u_char ac_state; + u_char battery_life; + u_char spare1; + u_int minutes_left; /* estimate */ + u_int spare2[6]; +}; + +struct apm_ctl { + u_int dev; + u_int mode; +}; + +#define APM_IOC_REJECT _IOW('A', 0, struct apm_event_info) /* reject request # */ +#define APM_IOC_STANDBY _IO('A', 1) /* put system into standby */ +#define APM_IOC_SUSPEND _IO('A', 2) /* put system into suspend */ +#define APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */ +#define APM_IOC_DEV_CTL _IOW('A', 5, struct apm_ctl) /* put device into mode */ +#define APM_IOC_PRN_CTL _IOW('A', 6, int ) /* driver power status msg */ +#define APM_PRINT_ON 0 /* driver power status displayed */ +#define APM_PRINT_OFF 1 /* driver power status not displayed */ +#define APM_PRINT_PCT 2 /* driver power status only displayed + if the percentage changes */ + +#ifdef _KERNEL +extern void apm_cpu_busy(void); +extern void apm_cpu_idle(void); +extern void apminit(void); +int apm_set_powstate(u_int devid, u_int powstate); +int apm_kqfilter(dev_t dev, struct knote *kn); +#endif /* _KERNEL */ + +#endif /* _I386_APMVAR_H_ */ diff --git a/sys/arch/amd64/include/asm.h b/sys/arch/amd64/include/asm.h new file mode 100644 index 00000000000..4dc7f0facac --- /dev/null +++ b/sys/arch/amd64/include/asm.h @@ -0,0 +1,122 @@ +/* $OpenBSD: asm.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: asm.h,v 1.2 2003/05/02 18:05:47 yamt Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)asm.h 5.5 (Berkeley) 5/7/91 + */ + +#ifndef _AMD64_ASM_H_ +#define _AMD64_ASM_H_ + +#ifdef PIC +#define PIC_PLT(x) x@PLT +#define PIC_GOT(x) x@GOTPCREL(%rip) +#else +#define PIC_PLT(x) x +#define PIC_GOT(x) x +#endif + +# define _C_LABEL(x) x +#define _ASM_LABEL(x) x + +#define CVAROFF(x,y) (_C_LABEL(x)+y)(%rip) + +#ifdef __STDC__ +# define __CONCAT(x,y) x ## y +# define __STRING(x) #x +#else +# define __CONCAT(x,y) x/**/y +# define __STRING(x) "x" +#endif + +/* let kernels and others override entrypoint alignment */ +#ifndef _ALIGN_TEXT +#define _ALIGN_TEXT .align 16, 0x90 +#endif + +#define _ENTRY(x) \ + .text; _ALIGN_TEXT; .globl x; .type x,@function; x: + +#ifdef _KERNEL +/* XXX Can't use __CONCAT() here, as it would be evaluated incorrectly. */ +#ifdef __STDC__ +#define IDTVEC(name) \ + .text; ALIGN_TEXT; .globl X ## name; .type X ## name,@function; X ## name: +#else +#define IDTVEC(name) \ + .text; ALIGN_TEXT; .globl X/**/name; .type X/**/name,@function; X/**/name: +#endif /* __STDC__ */ +#endif /* _KERNEL */ + +#ifdef __STDC__ +#define CPUVAR(off) %gs:CPU_INFO_ ## off +#else +#define CPUVAR(off) %gs:CPU_INFO_/**/off +#endif + + +#ifdef GPROF +# define _PROF_PROLOGUE \ + pushq %rbp; leaq (%rsp),%rbp; call PIC_PLT(__mcount); popq %rbp +#else +# define _PROF_PROLOGUE +#endif + +#define ENTRY(y) _ENTRY(_C_LABEL(y)); _PROF_PROLOGUE +#define NENTRY(y) _ENTRY(_C_LABEL(y)) +#define ASENTRY(y) _ENTRY(_ASM_LABEL(y)); _PROF_PROLOGUE + +#define ASMSTR .asciz + +#define RCSID(x) .text; .asciz x + +#define WEAK_ALIAS(alias,sym) \ + .weak alias; \ + alias = sym + +/* XXXfvdl do not use stabs here */ +#ifdef __STDC__ +#define WARN_REFERENCES(sym,msg) \ + .stabs msg ## ,30,0,0,0 ; \ + .stabs __STRING(_C_LABEL(sym)) ## ,1,0,0,0 +#else +#define WARN_REFERENCES(sym,msg) \ + .stabs msg,30,0,0,0 ; \ + .stabs __STRING(sym),1,0,0,0 +#endif /* __STDC__ */ + +#endif /* !_AMD64_ASM_H_ */ diff --git a/sys/arch/amd64/include/atomic.h b/sys/arch/amd64/include/atomic.h new file mode 100644 index 00000000000..027415b18c2 --- /dev/null +++ b/sys/arch/amd64/include/atomic.h @@ -0,0 +1,96 @@ +/* $OpenBSD: atomic.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: atomic.h,v 1.1 2003/04/26 18:39:37 fvdl Exp $ */ + +/* + * Copyright 2002 (c) Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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 _ATOMIC_H +#define _ATOMIC_H + +#ifndef _LOCORE + +static __inline u_int64_t +x86_atomic_testset_u64(volatile u_int64_t *ptr, u_int64_t val) { + __asm__ volatile ("xchgq %0,(%2)" :"=r" (val):"0" (val),"r" (ptr)); + return val; +} + +static __inline u_int32_t +x86_atomic_testset_u32(volatile u_int32_t *ptr, u_int32_t val) { + __asm__ volatile ("xchgl %0,(%2)" :"=r" (val):"0" (val),"r" (ptr)); + return val; +} + + + +static __inline int32_t +x86_atomic_testset_i32(volatile int32_t *ptr, int32_t val) { + __asm__ volatile ("xchgl %0,(%2)" :"=r" (val):"0" (val),"r" (ptr)); + return val; +} + + + +static __inline void +x86_atomic_setbits_u32(volatile u_int32_t *ptr, u_int32_t bits) { + __asm __volatile("lock ; orl %1,%0" : "=m" (*ptr) : "ir" (bits)); +} + +static __inline void +x86_atomic_clearbits_u32(volatile u_int32_t *ptr, u_int32_t bits) { + __asm __volatile("lock ; andl %1,%0" : "=m" (*ptr) : "ir" (~bits)); +} + + + +static __inline void +x86_atomic_setbits_u64(volatile u_int64_t *ptr, u_int64_t bits) { + __asm __volatile("lock ; orq %1,%0" : "=m" (*ptr) : "ir" (~bits)); +} + +static __inline void +x86_atomic_clearbits_u64(volatile u_int64_t *ptr, u_int64_t bits) { + __asm __volatile("lock ; andq %1,%0" : "=m" (*ptr) : "ir" (~bits)); +} + +#define x86_atomic_testset_ul x86_atomic_testset_u32 +#define x86_atomic_testset_i x86_atomic_testset_i32 +#define x86_atomic_setbits_l x86_atomic_setbits_u32 +#define x86_atomic_setbits_ul x86_atomic_setbits_u32 +#define x86_atomic_clearbits_l x86_atomic_clearbits_u32 +#define x86_atomic_clearbits_ul x86_atomic_clearbits_u32 + +#endif +#endif diff --git a/sys/arch/amd64/include/biosvar.h b/sys/arch/amd64/include/biosvar.h new file mode 100644 index 00000000000..55922d4e002 --- /dev/null +++ b/sys/arch/amd64/include/biosvar.h @@ -0,0 +1,259 @@ +/* XXX - DSR */ +/* $OpenBSD: biosvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/* + * Copyright (c) 1997-1999 Michael Shalayeff + * 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 Michael Shalayeff. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 HIS RELATIVES 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 MIND, 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 _I386_BIOSVAR_H_ +#define _I386_BIOSVAR_H_ +#pragma pack(1) + + /* some boxes put apm data seg in the 2nd page */ +#define BOOTARG_OFF (NBPG*2) +#define BOOTARG_LEN (NBPG*1) +#define BOOTBIOS_ADDR (0x7c00) + + /* BIOS configure flags */ +#define BIOSF_BIOS32 0x0001 +#define BIOSF_PCIBIOS 0x0002 +#define BIOSF_PROMSCAN 0x0004 + +/* BIOS media ID */ +#define BIOSM_F320K 0xff /* floppy ds/sd 8 spt */ +#define BIOSM_F160K 0xfe /* floppy ss/sd 8 spt */ +#define BIOSM_F360K 0xfd /* floppy ds/sd 9 spt */ +#define BIOSM_F180K 0xfc /* floppy ss/sd 9 spt */ +#define BIOSM_ROMD 0xfa /* ROM disk */ +#define BIOSM_F120M 0xf9 /* floppy ds/hd 15 spt 5.25" */ +#define BIOSM_F720K 0xf9 /* floppy ds/dd 9 spt 3.50" */ +#define BIOSM_HD 0xf8 /* hard drive */ +#define BIOSM_F144K 0xf0 /* floppy ds/hd 18 spt 3.50" */ +#define BIOSM_OTHER 0xf0 /* any other */ + +/* + * BIOS memory maps + */ +#define BIOS_MAP_END 0x00 /* End of array XXX - special */ +#define BIOS_MAP_FREE 0x01 /* Usable memory */ +#define BIOS_MAP_RES 0x02 /* Reserved memory */ +#define BIOS_MAP_ACPI 0x03 /* ACPI Reclaim memory */ +#define BIOS_MAP_NVS 0x04 /* ACPI NVS memory */ + +/* + * Optional ROM header + */ +typedef +struct bios_romheader { + u_int16_t signature; /* 0xaa55 */ + u_int8_t len; /* length in pages (512 bytes) */ + u_int32_t entry; /* initialization entry point */ + u_int8_t reserved[19]; + u_int16_t pnpheader; /* offset to PnP expansion header */ +} *bios_romheader_t; + +/* + * BIOS32 + */ +typedef +struct bios32_header { + u_int32_t signature; /* 00: signature "_32_" */ + u_int32_t entry; /* 04: entry point */ + u_int8_t rev; /* 08: revision */ + u_int8_t length; /* 09: header length */ + u_int8_t cksum; /* 0a: modulo 256 checksum */ + u_int8_t reserved[5]; +} *bios32_header_t; + +typedef +struct bios32_entry_info { + paddr_t bei_base; + psize_t bei_size; + paddr_t bei_entry; +} *bios32_entry_info_t; + +typedef +struct bios32_entry { + u_int32_t offset; + u_int16_t segment; +} *bios32_entry_t; + +#define BIOS32_START 0xe0000 +#define BIOS32_SIZE 0x20000 +#define BIOS32_END (BIOS32_START + BIOS32_SIZE - 0x10) + +#define BIOS32_MAKESIG(a, b, c, d) \ + ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24)) +#define BIOS32_SIGNATURE BIOS32_MAKESIG('_', '3', '2', '_') +#define PCIBIOS_SIGNATURE BIOS32_MAKESIG('$', 'P', 'C', 'I') + +/* + * CTL_BIOS definitions. + */ +#define BIOS_DEV 1 /* int: BIOS boot device */ +#define BIOS_DISKINFO 2 /* struct: BIOS boot device info */ +#define BIOS_CKSUMLEN 3 /* int: disk cksum block count */ +#define BIOS_MAXID 4 /* number of valid machdep ids */ + +#define CTL_BIOS_NAMES { \ + { 0, 0 }, \ + { "biosdev", CTLTYPE_INT }, \ + { "diskinfo", CTLTYPE_STRUCT }, \ + { "cksumlen", CTLTYPE_INT }, \ +} + +#define BOOTARG_MEMMAP 0 +typedef struct _bios_memmap { + u_int64_t addr; /* Beginning of block */ + u_int64_t size; /* Size of block */ + u_int32_t type; /* Type of block */ +} bios_memmap_t; + +/* Info about disk from the bios, plus the mapping from + * BIOS numbers to BSD major (driver?) number. + * + * Also, do not bother with BIOSN*() macros, just parcel + * the info out, and use it like this. This makes for less + * of a dependance on BIOSN*() macros having to be the same + * across /boot, /bsd, and userland. + */ +#define BOOTARG_DISKINFO 1 +typedef struct _bios_diskinfo { + /* BIOS section */ + int bios_number; /* BIOS number of drive (or -1) */ + u_int bios_cylinders; /* BIOS cylinders */ + u_int bios_heads; /* BIOS heads */ + u_int bios_sectors; /* BIOS sectors */ + int bios_edd; /* EDD support */ + + /* BSD section */ + dev_t bsd_dev; /* BSD device */ + + /* Checksum section */ + u_int32_t checksum; /* Checksum for drive */ + + /* Misc. flags */ + u_int32_t flags; +#define BDI_INVALID 0x00000001 /* I/O error during checksumming */ +#define BDI_GOODLABEL 0x00000002 /* Had SCSI or ST506/ESDI disklabel */ +#define BDI_BADLABEL 0x00000004 /* Had another disklabel */ +#define BDI_PICKED 0x80000000 /* kernel-only: cksum matched */ + +} bios_diskinfo_t; + +#define BOOTARG_APMINFO 2 +typedef struct _bios_apminfo { + /* APM_CONNECT returned values */ + u_int apm_detail; + u_int apm_code32_base; + u_int apm_code16_base; + u_int apm_code_len; + u_int apm_data_base; + u_int apm_data_len; + u_int apm_entry; + u_int apm_code16_len; +} bios_apminfo_t; + +#define BOOTARG_CKSUMLEN 3 /* u_int32_t */ + +#define BOOTARG_PCIINFO 4 +typedef struct _bios_pciinfo { + /* PCI BIOS v2.0+ - Installation check values */ + u_int32_t pci_chars; /* Characteristics (%eax) */ + u_int32_t pci_rev; /* BCD Revision (%ebx) */ + u_int32_t pci_entry32; /* PM entry point for PCI BIOS */ + u_int32_t pci_lastbus; /* Number of last PCI bus */ +} bios_pciinfo_t; + +#define BOOTARG_CONSDEV 5 +typedef struct _bios_consdev { + dev_t consdev; + int conspeed; +} bios_consdev_t; + +#if defined(_KERNEL) || defined (_STANDALONE) + +#ifdef _LOCORE +#define DOINT(n) int $0x20+(n) +#else +#define DOINT(n) "int $0x20+(" #n ")" + +extern struct BIOS_regs { + u_int32_t biosr_ax; + u_int32_t biosr_cx; + u_int32_t biosr_dx; + u_int32_t biosr_bx; + u_int32_t biosr_bp; + u_int32_t biosr_si; + u_int32_t biosr_di; + u_int32_t biosr_ds; + u_int32_t biosr_es; +} BIOS_regs; + +#ifdef _KERNEL +#include <machine/bus.h> + +struct bios_attach_args { + char *bios_dev; + u_int bios_func; + bus_space_tag_t bios_iot; + bus_space_tag_t bios_memt; + union { + void *_p; + bios_apminfo_t *_bios_apmp; + } _; +}; + +#define bios_apmp _._bios_apmp + +struct consdev; +struct proc; + +int bios_sysctl(int *, u_int, void *, size_t *, void *, size_t, struct proc *); + +void bioscnprobe(struct consdev *); +void bioscninit(struct consdev *); +void bioscnputc(dev_t, int); +int bioscngetc(dev_t); +void bioscnpollc(dev_t, int); +void bios_getopt(void); + +/* bios32.c */ +int bios32_service(u_int32_t, bios32_entry_t, bios32_entry_info_t); + +extern u_int bootapiver; +extern bios_memmap_t *bios_memmap; + +#endif /* _KERNEL */ +#endif /* _LOCORE */ +#endif /* _KERNEL || _STANDALONE */ + +#pragma pack() +#endif /* _I386_BIOSVAR_H_ */ diff --git a/sys/arch/amd64/include/bootinfo.h b/sys/arch/amd64/include/bootinfo.h new file mode 100644 index 00000000000..8751e66a3be --- /dev/null +++ b/sys/arch/amd64/include/bootinfo.h @@ -0,0 +1,159 @@ +/* $OpenBSD: bootinfo.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: bootinfo.h,v 1.2 2003/04/16 19:16:42 dsl Exp $ */ + +/* + * Copyright (c) 1997 + * Matthias Drochner. 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 for the NetBSD Project + * by Matthias Drochner. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 _LOCORE + +struct btinfo_common { + int len; + int type; +}; + +#define BTINFO_BOOTPATH 0 +#define BTINFO_BOOTDISK 3 +#define BTINFO_NETIF 4 +#define BTINFO_CONSOLE 6 +#define BTINFO_BIOSGEOM 7 +#define BTINFO_SYMTAB 8 +#define BTINFO_MEMMAP 9 + +struct btinfo_bootpath { + struct btinfo_common common; + char bootpath[80]; +}; + +struct btinfo_bootdisk { + struct btinfo_common common; + int labelsector; /* label valid if != -1 */ + struct { + u_int16_t type, checksum; + char packname[16]; + } label; + int biosdev; + int partition; +}; + +struct btinfo_netif { + struct btinfo_common common; + char ifname[16]; + int bus; +#define BI_BUS_ISA 0 +#define BI_BUS_PCI 1 + union { + unsigned int iobase; /* ISA */ + unsigned int tag; /* PCI, BIOS format */ + } addr; +}; + +struct btinfo_console { + struct btinfo_common common; + char devname[16]; + int addr; + int speed; +}; + +struct btinfo_symtab { + struct btinfo_common common; + int nsym; + int ssym; + int esym; +}; + +struct bi_memmap_entry { + u_int64_t addr; /* beginning of block */ /* 8 */ + u_int64_t size; /* size of block */ /* 8 */ + u_int32_t type; /* type of block */ /* 4 */ +} __attribute__((packed)); /* == 20 */ + +#define BIM_Memory 1 /* available RAM usable by OS */ +#define BIM_Reserved 2 /* in use or reserved by the system */ +#define BIM_ACPI 3 /* ACPI Reclaim memory */ +#define BIM_NVS 4 /* ACPI NVS memory */ + +struct btinfo_memmap { + struct btinfo_common common; + int num; + struct bi_memmap_entry entry[1]; /* var len */ +}; + +#include <machine/disklabel.h> + +/* + * Structure describing disk info as seen by the BIOS. + */ +struct bi_biosgeom_entry { + int sec, head, cyl; /* geometry */ + u_int64_t totsec; /* LBA sectors from ext int13 */ + int flags, dev; /* flags, BIOS device # */ +#define BI_GEOM_INVALID 0x000001 +#define BI_GEOM_EXTINT13 0x000002 +#ifdef BIOSDISK_EXT13INFO_V3 +#define BI_GEOM_BADCKSUM 0x000004 /* v3.x checksum invalid */ +#define BI_GEOM_BUS_MASK 0x00ff00 /* connecting bus type */ +#define BI_GEOM_BUS_ISA 0x000100 +#define BI_GEOM_BUS_PCI 0x000200 +#define BI_GEOM_BUS_OTHER 0x00ff00 +#define BI_GEOM_IFACE_MASK 0xff0000 /* interface type */ +#define BI_GEOM_IFACE_ATA 0x010000 +#define BI_GEOM_IFACE_ATAPI 0x020000 +#define BI_GEOM_IFACE_SCSI 0x030000 +#define BI_GEOM_IFACE_USB 0x040000 +#define BI_GEOM_IFACE_1394 0x050000 /* Firewire */ +#define BI_GEOM_IFACE_FIBRE 0x060000 /* Fibre channel */ +#define BI_GEOM_IFACE_OTHER 0xff0000 + unsigned int cksum; /* MBR checksum */ + u_int interface_path; /* ISA iobase PCI bus/dev/fun */ + u_int64_t device_path; + int res0; /* future expansion; 0 now */ +#else + unsigned int cksum; /* MBR checksum */ + int res0, res1, res2, res3; /* future expansion; 0 now */ +#endif + struct dos_partition dosparts[NDOSPART]; /* MBR itself */ +} __attribute__((packed)); + +struct btinfo_biosgeom { + struct btinfo_common common; + int num; + struct bi_biosgeom_entry disk[1]; /* var len */ +}; + +#ifdef _KERNEL +void *lookup_bootinfo __P((int)); +#endif +#endif /* _LOCORE */ + +#ifdef _KERNEL +#define BOOTINFO_MAXSIZE 4096 +#endif diff --git a/sys/arch/amd64/include/bus.h b/sys/arch/amd64/include/bus.h new file mode 100644 index 00000000000..4a1c326b8fc --- /dev/null +++ b/sys/arch/amd64/include/bus.h @@ -0,0 +1,1158 @@ +/* $OpenBSD: bus.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $ */ + +/*- + * Copyright (c) 1996, 1997 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. + * + * 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) 1996 Charles M. Hannum. All rights reserved. + * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. + * Copyright (c) 1996 Christopher G. Demetriou. 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 Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 _X86_BUS_H_ +#define _X86_BUS_H_ + +#include <machine/pio.h> + +/* + * Values for the x86 bus space tag, not to be used directly by MI code. + */ +#define X86_BUS_SPACE_IO 0 /* space is i/o space */ +#define X86_BUS_SPACE_MEM 1 /* space is mem space */ + +/* + * Bus address and size types + */ +typedef u_long bus_addr_t; +typedef u_long bus_size_t; + +/* + * Access methods for bus resources and address space. + */ +typedef int bus_space_tag_t; +typedef u_long bus_space_handle_t; + +#define bus_space_map(t, a, s, f, hp) x86_memio_map((t),(a),(s),(f),(hp)) +#define bus_space_unmap(t, h, s) x86_memio_unmap((t),(h),(s)) +#define bus_space_subregion(t, h, o, s, nhp) \ + x86_memio_subregion((t), (h), (o), (s), (nhp)) + +int x86_memio_map(bus_space_tag_t t, bus_addr_t addr, + bus_size_t size, int flags, bus_space_handle_t *bshp); +/* like map, but without extent map checking/allocation */ +int _x86_memio_map(bus_space_tag_t t, bus_addr_t addr, + bus_size_t size, int flags, bus_space_handle_t *bshp); + +/* + * int bus_space_unmap(bus_space_tag_t t, + * bus_space_handle_t bsh, bus_size_t size); + * + * Unmap a region of bus space. + */ + +void x86_memio_unmap(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); +void _x86_memio_unmap(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size, bus_addr_t *); + +/* like bus_space_map(), but without extent map checking/allocation */ +int _bus_space_map(bus_space_tag_t t, bus_addr_t addr, + bus_size_t size, int cacheable, bus_space_handle_t *bshp); + +int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, + bus_addr_t rend, bus_size_t size, bus_size_t align, + bus_size_t boundary, int cacheable, bus_addr_t *addrp, + bus_space_handle_t *bshp); +void bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + +/* + * int bus_space_subregion(bus_space_tag_t t, + * bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, + * bus_space_handle_t *nbshp); + * + * Get a new handle for a subregion of an already-mapped area of bus space. + */ + +int x86_memio_subregion(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp); + +/* + * u_intN_t bus_space_read_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset); + * + * Read a 1, 2, 4, or 8 byte quantity from bus space + * described by tag/handle/offset. + */ + +#define bus_space_read_1(t, h, o) \ + ((t) == X86_BUS_SPACE_IO ? (inb((h) + (o))) : \ + (*(volatile u_int8_t *)((h) + (o)))) + +#define bus_space_read_2(t, h, o) \ + ((t) == X86_BUS_SPACE_IO ? (inw((h) + (o))) : \ + (*(volatile u_int16_t *)((h) + (o)))) + +#define bus_space_read_4(t, h, o) \ + ((t) == X86_BUS_SPACE_IO ? (inl((h) + (o))) : \ + (*(volatile u_int32_t *)((h) + (o)))) + +#if 0 /* Cause a link error for bus_space_read_8 */ +#define bus_space_read_8(t, h, o) !!! bus_space_read_8 unimplemented !!! +#endif + +/* + * void bus_space_read_multi_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_intN_t *addr, size_t count); + * + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle/offset and copy into buffer provided. + */ + +#define bus_space_read_multi_1(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + insb((h) + (o), (ptr), (cnt)); \ + } else { \ + void *dummy1; \ + int dummy2; \ + void *dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: movb (%2),%%al ; \ + stosb ; \ + loop 1b" : \ + "=D" (dummy1), "=c" (dummy2), "=r" (dummy3), "=&a" (__x) : \ + "0" ((ptr)), "1" ((cnt)), "2" ((h) + (o)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_read_multi_2(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + insw((h) + (o), (ptr), (cnt)); \ + } else { \ + void *dummy1; \ + int dummy2; \ + void *dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: movw (%2),%%ax ; \ + stosw ; \ + loop 1b" : \ + "=D" (dummy1), "=c" (dummy2), "=r" (dummy3), "=&a" (__x) : \ + "0" ((ptr)), "1" ((cnt)), "2" ((h) + (o)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_read_multi_4(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + insl((h) + (o), (ptr), (cnt)); \ + } else { \ + void *dummy1; \ + int dummy2; \ + void *dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: movl (%2),%%eax ; \ + stosl ; \ + loop 1b" : \ + "=D" (dummy1), "=c" (dummy2), "=r" (dummy3), "=&a" (__x) : \ + "0" ((ptr)), "1" ((cnt)), "2" ((h) + (o)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#if 0 /* Cause a link error for bus_space_read_multi_8 */ +#define bus_space_read_multi_8 !!! bus_space_read_multi_8 unimplemented !!! +#endif + +/* + * void bus_space_read_raw_multi_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_int8_t *addr, size_t count); + * + * Read `count' bytes in 2, 4 or 8 byte wide quantities from bus space + * described by tag/handle/offset and copy into buffer provided. The buffer + * must have proper alignment for the N byte wide entities. Furthermore + * possible byte-swapping should be done by these functions. + */ + +#define bus_space_read_raw_multi_2(t, h, o, a, c) \ + bus_space_read_multi_2((t), (h), (o), (u_int16_t *)(a), (c) >> 1) +#define bus_space_read_raw_multi_4(t, h, o, a, c) \ + bus_space_read_multi_4((t), (h), (o), (u_int32_t *)(a), (c) >> 2) + +#if 0 /* Cause a link error for bus_space_read_raw_multi_8 */ +#define bus_space_read_raw_multi_8 \ + !!! bus_space_read_raw_multi_8 unimplemented !!! +#endif + +/* + * void bus_space_read_region_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_intN_t *addr, size_t count); + * + * Read `count' 1, 2, 4, or 8 byte quantities from bus space + * described by tag/handle and starting at `offset' and copy into + * buffer provided. + */ + +#define bus_space_read_region_1(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: inb %w1,%%al ; \ + stosb ; \ + incl %1 ; \ + loop 1b" : \ + "=&a" (__x), "=d" (dummy1), "=D" (dummy2), \ + "=c" (dummy3) : \ + "1" ((h) + (o)), "2" ((ptr)), "3" ((cnt)) : \ + "memory"); \ + } else { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + __asm __volatile(" \ + cld ; \ + repne ; \ + movsb" : \ + "=S" (dummy1), "=D" (dummy2), "=c" (dummy3) : \ + "0" ((h) + (o)), "1" ((ptr)), "2" ((cnt)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_read_region_2(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: inw %w1,%%ax ; \ + stosw ; \ + addl $2,%1 ; \ + loop 1b" : \ + "=&a" (__x), "=d" (dummy1), "=D" (dummy2), \ + "=c" (dummy3) : \ + "1" ((h) + (o)), "2" ((ptr)), "3" ((cnt)) : \ + "memory"); \ + } else { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + __asm __volatile(" \ + cld ; \ + repne ; \ + movsw" : \ + "=S" (dummy1), "=D" (dummy2), "=c" (dummy3) : \ + "0" ((h) + (o)), "1" ((ptr)), "2" ((cnt)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_read_region_4(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: inl %w1,%%eax ; \ + stosl ; \ + addl $4,%1 ; \ + loop 1b" : \ + "=&a" (__x), "=d" (dummy1), "=D" (dummy2), \ + "=c" (dummy3) : \ + "1" ((h) + (o)), "2" ((ptr)), "3" ((cnt)) : \ + "memory"); \ + } else { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + __asm __volatile(" \ + cld ; \ + repne ; \ + movsl" : \ + "=S" (dummy1), "=D" (dummy2), "=c" (dummy3) : \ + "0" ((h) + (o)), "1" ((ptr)), "2" ((cnt)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_read_region_stream_1 bus_space_read_region_1 +#if 0 /* Cause a link error for bus_space_read_region_8 */ +#define bus_space_read_region_8 !!! bus_space_read_region_8 unimplemented !!! +#endif + +/* + * void bus_space_read_raw_region_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_int8_t *addr, size_t count); + * + * Read `count' bytes in 2, 4 or 8 byte wide quantities from bus space + * described by tag/handle and starting at `offset' and copy into + * buffer provided. The buffer must have proper alignment for the N byte + * wide entities. Furthermore possible byte-swapping should be done by + * these functions. + */ + +#define bus_space_read_raw_region_2(t, h, o, a, c) \ + bus_space_read_region_2((t), (h), (o), (u_int16_t *)(a), (c) >> 1) +#define bus_space_read_raw_region_4(t, h, o, a, c) \ + bus_space_read_region_4((t), (h), (o), (u_int32_t *)(a), (c) >> 2) + +#if 0 /* Cause a link error for bus_space_read_raw_region_8 */ +#define bus_space_read_raw_region_8 \ + !!! bus_space_read_raw_region_8 unimplemented !!! +#endif + +/* + * void bus_space_write_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_intN_t value); + * + * Write the 1, 2, 4, or 8 byte value `value' to bus space + * described by tag/handle/offset. + */ + +#define bus_space_write_1(t, h, o, v) do { \ + if ((t) == X86_BUS_SPACE_IO) \ + outb((h) + (o), (v)); \ + else \ + ((void)(*(volatile u_int8_t *)((h) + (o)) = (v))); \ +} while (0) + +#define bus_space_write_2(t, h, o, v) do { \ + if ((t) == X86_BUS_SPACE_IO) \ + outw((h) + (o), (v)); \ + else \ + ((void)(*(volatile u_int16_t *)((h) + (o)) = (v))); \ +} while (0) + +#define bus_space_write_4(t, h, o, v) do { \ + if ((t) == X86_BUS_SPACE_IO) \ + outl((h) + (o), (v)); \ + else \ + ((void)(*(volatile u_int32_t *)((h) + (o)) = (v))); \ +} while (0) + +#if 0 /* Cause a link error for bus_space_write_8 */ +#define bus_space_write_8 !!! bus_space_write_8 not implemented !!! +#endif + +/* + * void bus_space_write_multi_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * const u_intN_t *addr, size_t count); + * + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer + * provided to bus space described by tag/handle/offset. + */ + +#define bus_space_write_multi_1(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + outsb((h) + (o), (ptr), (cnt)); \ + } else { \ + void *dummy1; \ + int dummy2; \ + void *dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: lodsb ; \ + movb %%al,(%2) ; \ + loop 1b" : \ + "=S" (dummy1), "=c" (dummy2), "=r" (dummy3), "=&a" (__x) : \ + "0" ((ptr)), "1" ((cnt)), "2" ((h) + (o))); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_write_multi_2(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + outsw((h) + (o), (ptr), (cnt)); \ + } else { \ + void *dummy1; \ + int dummy2; \ + void *dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: lodsw ; \ + movw %%ax,(%2) ; \ + loop 1b" : \ + "=S" (dummy1), "=c" (dummy2), "=r" (dummy3), "=&a" (__x) : \ + "0" ((ptr)), "1" ((cnt)), "2" ((h) + (o))); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_write_multi_4(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + outsl((h) + (o), (ptr), (cnt)); \ + } else { \ + void *dummy1; \ + int dummy2; \ + void *dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: lodsl ; \ + movl %%eax,(%2) ; \ + loop 1b" : \ + "=S" (dummy1), "=c" (dummy2), "=r" (dummy3), "=&a" (__x) : \ + "0" ((ptr)), "1" ((cnt)), "2" ((h) + (o))); \ + } \ +} while (/* CONSTCOND */ 0) + +#if 0 /* Cause a link error for bus_space_write_multi_8 */ +#define bus_space_write_multi_8(t, h, o, a, c) \ + !!! bus_space_write_multi_8 unimplemented !!! +#endif + +/* + * void bus_space_write_raw_multi_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * const u_int8_t *addr, size_t count); + * + * Write `count' bytes in 2, 4 or 8 byte wide quantities from the buffer + * provided to bus space described by tag/handle/offset. The buffer + * must have proper alignment for the N byte wide entities. Furthermore + * possible byte-swapping should be done by these functions. + */ + +#define bus_space_write_raw_multi_2(t, h, o, a, c) \ + bus_space_write_multi_2((t), (h), (o), (const u_int16_t *)(a), (c) >> 1) +#define bus_space_write_raw_multi_4(t, h, o, a, c) \ + bus_space_write_multi_4((t), (h), (o), (const u_int32_t *)(a), (c) >> 2) + +#if 0 /* Cause a link error for bus_space_write_raw_multi_8 */ +#define bus_space_write_raw_multi_8 \ + !!! bus_space_write_raw_multi_8 unimplemented !!! +#endif + +/* + * void bus_space_write_region_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * const u_intN_t *addr, size_t count); + * + * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided + * to bus space described by tag/handle starting at `offset'. + */ + +#define bus_space_write_region_1(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: lodsb ; \ + outb %%al,%w1 ; \ + incl %1 ; \ + loop 1b" : \ + "=&a" (__x), "=d" (dummy1), "=S" (dummy2), \ + "=c" (dummy3) : \ + "1" ((h) + (o)), "2" ((ptr)), "3" ((cnt)) : \ + "memory"); \ + } else { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + __asm __volatile(" \ + cld ; \ + repne ; \ + movsb" : \ + "=D" (dummy1), "=S" (dummy2), "=c" (dummy3) : \ + "0" ((h) + (o)), "1" ((ptr)), "2" ((cnt)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_write_region_2(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: lodsw ; \ + outw %%ax,%w1 ; \ + addl $2,%1 ; \ + loop 1b" : \ + "=&a" (__x), "=d" (dummy1), "=S" (dummy2), \ + "=c" (dummy3) : \ + "1" ((h) + (o)), "2" ((ptr)), "3" ((cnt)) : \ + "memory"); \ + } else { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + __asm __volatile(" \ + cld ; \ + repne ; \ + movsw" : \ + "=D" (dummy1), "=S" (dummy2), "=c" (dummy3) : \ + "0" ((h) + (o)), "1" ((ptr)), "2" ((cnt)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#define bus_space_write_region_4(t, h, o, ptr, cnt) \ +do { \ + if ((t) == X86_BUS_SPACE_IO) { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + int __x; \ + __asm __volatile(" \ + cld ; \ + 1: lodsl ; \ + outl %%eax,%w1 ; \ + addl $4,%1 ; \ + loop 1b" : \ + "=&a" (__x), "=d" (dummy1), "=S" (dummy2), \ + "=c" (dummy3) : \ + "1" ((h) + (o)), "2" ((ptr)), "3" ((cnt)) : \ + "memory"); \ + } else { \ + int dummy1; \ + void *dummy2; \ + int dummy3; \ + __asm __volatile(" \ + cld ; \ + repne ; \ + movsl" : \ + "=D" (dummy1), "=S" (dummy2), "=c" (dummy3) : \ + "0" ((h) + (o)), "1" ((ptr)), "2" ((cnt)) : \ + "memory"); \ + } \ +} while (/* CONSTCOND */ 0) + +#if 0 /* Cause a link error for bus_space_write_region_8 */ +#define bus_space_write_region_8 \ + !!! bus_space_write_region_8 unimplemented !!! +#endif + +/* + * void bus_space_write_raw_region_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * const u_int8_t *addr, size_t count); + * + * Write `count' bytes in 2, 4 or 8 byte wide quantities to bus space + * described by tag/handle and starting at `offset' from the + * buffer provided. The buffer must have proper alignment for the N byte + * wide entities. Furthermore possible byte-swapping should be done by + * these functions. + */ + +#define bus_space_write_raw_region_2(t, h, o, a, c) \ + bus_space_write_region_2((t), (h), (o), (const u_int16_t *)(a), (c) >> 1) +#define bus_space_write_raw_region_4(t, h, o, a, c) \ + bus_space_write_region_4((t), (h), (o), (const u_int32_t *)(a), (c) >> 2) + +#if 0 /* Cause a link error for bus_space_write_raw_region_8 */ +#define bus_space_write_raw_region_8 \ + !!! bus_space_write_raw_region_8 unimplemented !!! +#endif + +/* + * void bus_space_set_multi_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_intN_t val, size_t count); + * + * Write the 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle/offset `count' times. + */ + +static __inline void x86_memio_set_multi_1(bus_space_tag_t, + bus_space_handle_t, bus_size_t, u_int8_t, size_t); +static __inline void x86_memio_set_multi_2(bus_space_tag_t, + bus_space_handle_t, bus_size_t, u_int16_t, size_t); +static __inline void x86_memio_set_multi_4(bus_space_tag_t, + bus_space_handle_t, bus_size_t, u_int32_t, size_t); + +#define bus_space_set_multi_1(t, h, o, v, c) \ + x86_memio_set_multi_1((t), (h), (o), (v), (c)) + +#define bus_space_set_multi_2(t, h, o, v, c) \ + x86_memio_set_multi_2((t), (h), (o), (v), (c)) + +#define bus_space_set_multi_4(t, h, o, v, c) \ + x86_memio_set_multi_4((t), (h), (o), (v), (c)) + +static __inline void +x86_memio_set_multi_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int8_t v, size_t c) +{ + bus_addr_t addr = h + o; + + if (t == X86_BUS_SPACE_IO) + while (c--) + outb(addr, v); + else + while (c--) + *(volatile u_int8_t *)(addr) = v; +} + +static __inline void +x86_memio_set_multi_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int16_t v, size_t c) +{ + bus_addr_t addr = h + o; + + if (t == X86_BUS_SPACE_IO) + while (c--) + outw(addr, v); + else + while (c--) + *(volatile u_int16_t *)(addr) = v; +} + +static __inline void +x86_memio_set_multi_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int32_t v, size_t c) +{ + bus_addr_t addr = h + o; + + if (t == X86_BUS_SPACE_IO) + while (c--) + outl(addr, v); + else + while (c--) + *(volatile u_int32_t *)(addr) = v; +} + +#if 0 /* Cause a link error for bus_space_set_multi_8 */ +#define bus_space_set_multi_8 \ + !!! bus_space_set_multi_8 unimplemented !!! +#endif + +/* + * void bus_space_set_region_N(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * u_intN_t val, size_t count); + * + * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described + * by tag/handle starting at `offset'. + */ + +static __inline void x86_memio_set_region_1(bus_space_tag_t, + bus_space_handle_t, bus_size_t, u_int8_t, size_t); +static __inline void x86_memio_set_region_2(bus_space_tag_t, + bus_space_handle_t, bus_size_t, u_int16_t, size_t); +static __inline void x86_memio_set_region_4(bus_space_tag_t, + bus_space_handle_t, bus_size_t, u_int32_t, size_t); + +#define bus_space_set_region_1(t, h, o, v, c) \ + x86_memio_set_region_1((t), (h), (o), (v), (c)) + +#define bus_space_set_region_2(t, h, o, v, c) \ + x86_memio_set_region_2((t), (h), (o), (v), (c)) + +#define bus_space_set_region_4(t, h, o, v, c) \ + x86_memio_set_region_4((t), (h), (o), (v), (c)) + +static __inline void +x86_memio_set_region_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int8_t v, size_t c) +{ + bus_addr_t addr = h + o; + + if (t == X86_BUS_SPACE_IO) + for (; c != 0; c--, addr++) + outb(addr, v); + else + for (; c != 0; c--, addr++) + *(volatile u_int8_t *)(addr) = v; +} + +static __inline void +x86_memio_set_region_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int16_t v, size_t c) +{ + bus_addr_t addr = h + o; + + if (t == X86_BUS_SPACE_IO) + for (; c != 0; c--, addr += 2) + outw(addr, v); + else + for (; c != 0; c--, addr += 2) + *(volatile u_int16_t *)(addr) = v; +} + +static __inline void +x86_memio_set_region_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + u_int32_t v, size_t c) +{ + bus_addr_t addr = h + o; + + if (t == X86_BUS_SPACE_IO) + for (; c != 0; c--, addr += 4) + outl(addr, v); + else + for (; c != 0; c--, addr += 4) + *(volatile u_int32_t *)(addr) = v; +} + +#if 0 /* Cause a link error for bus_space_set_region_8 */ +#define bus_space_set_region_8 \ + !!! bus_space_set_region_8 unimplemented !!! +#endif + +/* + * void bus_space_copy_N(bus_space_tag_t tag, + * bus_space_handle_t bsh1, bus_size_t off1, + * bus_space_handle_t bsh2, bus_size_t off2, + * size_t count); + * + * Copy `count' 1, 2, 4, or 8 byte values from bus space starting + * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. + */ + +#define bus_space_copy_1 bus_space_copy_region_1 +#define bus_space_copy_2 bus_space_copy_region_2 +#define bus_space_copy_4 bus_space_copy_region_4 +#define bus_space_copy_8 bus_space_copy_region_8 + +static __inline void x86_memio_copy_region_1(bus_space_tag_t, + bus_space_handle_t, bus_size_t, bus_space_handle_t, + bus_size_t, size_t); +static __inline void x86_memio_copy_region_2(bus_space_tag_t, + bus_space_handle_t, bus_size_t, bus_space_handle_t, + bus_size_t, size_t); +static __inline void x86_memio_copy_region_4(bus_space_tag_t, + bus_space_handle_t, bus_size_t, bus_space_handle_t, + bus_size_t, size_t); + +#define bus_space_copy_region_1(t, h1, o1, h2, o2, c) \ + x86_memio_copy_region_1((t), (h1), (o1), (h2), (o2), (c)) + +#define bus_space_copy_region_2(t, h1, o1, h2, o2, c) \ + x86_memio_copy_region_2((t), (h1), (o1), (h2), (o2), (c)) + +#define bus_space_copy_region_4(t, h1, o1, h2, o2, c) \ + x86_memio_copy_region_4((t), (h1), (o1), (h2), (o2), (c)) + +static __inline void +x86_memio_copy_region_1(bus_space_tag_t t, + bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, size_t c) +{ + bus_addr_t addr1 = h1 + o1; + bus_addr_t addr2 = h2 + o2; + + if (t == X86_BUS_SPACE_IO) { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; c != 0; c--, addr1++, addr2++) + outb(addr2, inb(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += (c - 1), addr2 += (c - 1); + c != 0; c--, addr1--, addr2--) + outb(addr2, inb(addr1)); + } + } else { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; c != 0; c--, addr1++, addr2++) + *(volatile u_int8_t *)(addr2) = + *(volatile u_int8_t *)(addr1); + } else { + /* dest after src: copy backwards */ + for (addr1 += (c - 1), addr2 += (c - 1); + c != 0; c--, addr1--, addr2--) + *(volatile u_int8_t *)(addr2) = + *(volatile u_int8_t *)(addr1); + } + } +} + +static __inline void +x86_memio_copy_region_2(bus_space_tag_t t, + bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, size_t c) +{ + bus_addr_t addr1 = h1 + o1; + bus_addr_t addr2 = h2 + o2; + + if (t == X86_BUS_SPACE_IO) { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; c != 0; c--, addr1 += 2, addr2 += 2) + outw(addr2, inw(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += 2 * (c - 1), addr2 += 2 * (c - 1); + c != 0; c--, addr1 -= 2, addr2 -= 2) + outw(addr2, inw(addr1)); + } + } else { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; c != 0; c--, addr1 += 2, addr2 += 2) + *(volatile u_int16_t *)(addr2) = + *(volatile u_int16_t *)(addr1); + } else { + /* dest after src: copy backwards */ + for (addr1 += 2 * (c - 1), addr2 += 2 * (c - 1); + c != 0; c--, addr1 -= 2, addr2 -= 2) + *(volatile u_int16_t *)(addr2) = + *(volatile u_int16_t *)(addr1); + } + } +} + +static __inline void +x86_memio_copy_region_4(bus_space_tag_t t, + bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, size_t c) +{ + bus_addr_t addr1 = h1 + o1; + bus_addr_t addr2 = h2 + o2; + + if (t == X86_BUS_SPACE_IO) { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; c != 0; c--, addr1 += 4, addr2 += 4) + outl(addr2, inl(addr1)); + } else { + /* dest after src: copy backwards */ + for (addr1 += 4 * (c - 1), addr2 += 4 * (c - 1); + c != 0; c--, addr1 -= 4, addr2 -= 4) + outl(addr2, inl(addr1)); + } + } else { + if (addr1 >= addr2) { + /* src after dest: copy forward */ + for (; c != 0; c--, addr1 += 4, addr2 += 4) + *(volatile u_int32_t *)(addr2) = + *(volatile u_int32_t *)(addr1); + } else { + /* dest after src: copy backwards */ + for (addr1 += 4 * (c - 1), addr2 += 4 * (c - 1); + c != 0; c--, addr1 -= 4, addr2 -= 4) + *(volatile u_int32_t *)(addr2) = + *(volatile u_int32_t *)(addr1); + } + } +} + +#if 0 /* Cause a link error for bus_space_copy_8 */ +#define bus_space_copy_8 \ + !!! bus_space_copy_8 unimplemented !!! +#endif + +/* + * Bus read/write barrier methods. + * + * void bus_space_barrier(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * bus_size_t len, int flags); + * + * Note: the x86 does not currently require barriers, but we must + * provide the flags to MI code. + */ +#define bus_space_barrier(t, h, o, l, f) \ + ((void)((void)(t), (void)(h), (void)(o), (void)(l), (void)(f))) +#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ +#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ +/* Compatibility defines */ +#define BUS_BARRIER_READ BUS_SPACE_BARRIER_READ +#define BUS_BARRIER_WRITE BUS_SPACE_BARRIER_WRITE + +/* + * Flags used in various bus DMA methods. + */ +#define BUS_DMA_WAITOK 0x000 /* safe to sleep (pseudo-flag) */ +#define BUS_DMA_NOWAIT 0x001 /* not safe to sleep */ +#define BUS_DMA_ALLOCNOW 0x002 /* perform resource allocation now */ +#define BUS_DMA_COHERENT 0x004 /* hint: map memory DMA coherent */ +#define BUS_DMA_BUS1 0x010 /* placeholders for bus functions... */ +#define BUS_DMA_BUS2 0x020 +#define BUS_DMA_BUS3 0x040 +#define BUS_DMA_BUS4 0x080 +#define BUS_DMA_STREAMING 0x100 /* hint: sequential, unidirectional */ +#define BUS_DMA_READ 0x200 /* mapping is device -> memory only */ +#define BUS_DMA_WRITE 0x400 /* mapping is memory -> device only */ + +/* Forwards needed by prototypes below. */ +struct mbuf; +struct proc; +struct uio; + +/* + * Operations performed by bus_dmamap_sync(). + */ +#define BUS_DMASYNC_PREREAD 0x01 +#define BUS_DMASYNC_POSTREAD 0x02 +#define BUS_DMASYNC_PREWRITE 0x04 +#define BUS_DMASYNC_POSTWRITE 0x08 + +typedef struct x86_bus_dma_tag *bus_dma_tag_t; +typedef struct x86_bus_dmamap *bus_dmamap_t; + +/* + * bus_dma_segment_t + * + * Describes a single contiguous DMA transaction. Values + * are suitable for programming into DMA registers. + */ +struct x86_bus_dma_segment { + bus_addr_t ds_addr; /* DMA address */ + bus_size_t ds_len; /* length of transfer */ +}; +typedef struct x86_bus_dma_segment bus_dma_segment_t; + +/* + * bus_dma_tag_t + * + * A machine-dependent opaque type describing the implementation of + * DMA for a given bus. + */ + +struct x86_bus_dma_tag { + void *_cookie; /* cookie used in the guts */ + + /* + * DMA mapping methods. + */ + int (*_dmamap_create)(bus_dma_tag_t, bus_size_t, int, + bus_size_t, bus_size_t, int, bus_dmamap_t *); + void (*_dmamap_destroy)(bus_dma_tag_t, bus_dmamap_t); + int (*_dmamap_load)(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int); + int (*_dmamap_load_mbuf)(bus_dma_tag_t, bus_dmamap_t, + struct mbuf *, int); + int (*_dmamap_load_uio)(bus_dma_tag_t, bus_dmamap_t, + struct uio *, int); + int (*_dmamap_load_raw)(bus_dma_tag_t, bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); + void (*_dmamap_unload)(bus_dma_tag_t, bus_dmamap_t); + void (*_dmamap_sync)(bus_dma_tag_t, bus_dmamap_t, + bus_addr_t, bus_size_t, int); + + /* + * DMA memory utility functions. + */ + int (*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t, + bus_size_t, bus_dma_segment_t *, int, int *, int); + void (*_dmamem_free)(bus_dma_tag_t, + bus_dma_segment_t *, int); + int (*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *, + int, size_t, caddr_t *, int); + void (*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t); + paddr_t (*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *, + int, off_t, int, int); +}; + +#define bus_dmamap_create(t, s, n, m, b, f, p) \ + (*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p)) +#define bus_dmamap_destroy(t, p) \ + (*(t)->_dmamap_destroy)((t), (p)) +#define bus_dmamap_load(t, m, b, s, p, f) \ + (*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f)) +#define bus_dmamap_load_mbuf(t, m, b, f) \ + (*(t)->_dmamap_load_mbuf)((t), (m), (b), (f)) +#define bus_dmamap_load_uio(t, m, u, f) \ + (*(t)->_dmamap_load_uio)((t), (m), (u), (f)) +#define bus_dmamap_load_raw(t, m, sg, n, s, f) \ + (*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f)) +#define bus_dmamap_unload(t, p) \ + (*(t)->_dmamap_unload)((t), (p)) +#define bus_dmamap_sync(t, p, o, l, ops) \ + (void)((t)->_dmamap_sync ? \ + (*(t)->_dmamap_sync)((t), (p), (o), (l), (ops)) : (void)0) + +#define bus_dmamem_alloc(t, s, a, b, sg, n, r, f) \ + (*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f)) +#define bus_dmamem_free(t, sg, n) \ + (*(t)->_dmamem_free)((t), (sg), (n)) +#define bus_dmamem_map(t, sg, n, s, k, f) \ + (*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f)) +#define bus_dmamem_unmap(t, k, s) \ + (*(t)->_dmamem_unmap)((t), (k), (s)) +#define bus_dmamem_mmap(t, sg, n, o, p, f) \ + (*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f)) + +/* + * bus_dmamap_t + * + * Describes a DMA mapping. + */ +struct x86_bus_dmamap { + /* + * PRIVATE MEMBERS: not for use my machine-independent code. + */ + bus_size_t _dm_size; /* largest DMA transfer mappable */ + int _dm_segcnt; /* number of segs this map can map */ + bus_size_t _dm_maxsegsz; /* largest possible segment */ + bus_size_t _dm_boundary; /* don't cross this */ + int _dm_flags; /* misc. flags */ + + void *_dm_cookie; /* cookie for bus-specific functions */ + + /* + * PUBLIC MEMBERS: these are used by machine-independent code. + */ + bus_size_t dm_mapsize; /* size of the mapping */ + int dm_nsegs; /* # valid segments in mapping */ + bus_dma_segment_t dm_segs[1]; /* segments; variable length */ +}; + +#ifdef _X86_BUS_DMA_PRIVATE +int _bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, + bus_size_t, int, bus_dmamap_t *); +void _bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); +int _bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int); +int _bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, + struct mbuf *, int); +int _bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, + struct uio *, int); +int _bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); +void _bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); +void _bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, + bus_size_t, int); + +int _bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, + bus_size_t alignment, bus_size_t boundary, + bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags); +void _bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, + int nsegs); +int _bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, + int nsegs, size_t size, caddr_t *kvap, int flags); +void _bus_dmamem_unmap(bus_dma_tag_t tag, caddr_t kva, + size_t size); +paddr_t _bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs, + int nsegs, off_t off, int prot, int flags); + +int _bus_dmamem_alloc_range(bus_dma_tag_t tag, bus_size_t size, + bus_size_t alignment, bus_size_t boundary, + bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags, + paddr_t low, paddr_t high); + +/* + * int bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, + * bus_addr_t rend, bus_size_t size, bus_size_t align, + * bus_size_t boundary, int flags, bus_addr_t *addrp, + * bus_space_handle_t *bshp); + * + * Allocate a region of bus space. + */ + +int x86_memio_alloc(bus_space_tag_t t, bus_addr_t rstart, + bus_addr_t rend, bus_size_t size, bus_size_t align, + bus_size_t boundary, int flags, bus_addr_t *addrp, + bus_space_handle_t *bshp); + +/* + * int bus_space_free(bus_space_tag_t t, + * bus_space_handle_t bsh, bus_size_t size); + * + * Free a region of bus space. + */ + +void x86_memio_free(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size); + +/* + * paddr_t bus_space_mmap(bus_space_tag_t t, bus_addr_t base, + * off_t offset, int prot, int flags); + * + * Mmap an area of bus space. + */ + +paddr_t x86_memio_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int); + + +#endif /* _X86_BUS_DMA_PRIVATE */ + +#endif /* _X86_BUS_H_ */ diff --git a/sys/arch/amd64/include/cacheinfo.h b/sys/arch/amd64/include/cacheinfo.h new file mode 100644 index 00000000000..ea0d7837029 --- /dev/null +++ b/sys/arch/amd64/include/cacheinfo.h @@ -0,0 +1,111 @@ +/* $OpenBSD: cacheinfo.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: cacheinfo.h,v 1.1 2003/04/25 21:54:30 fvdl Exp $ */ + +#ifndef _X86_CACHEINFO_H +#define _X86_CACHEINFO_H + +struct x86_cache_info { + uint8_t cai_index; + uint8_t cai_desc; + uint8_t cai_associativity; + u_int cai_totalsize; /* #entries for TLB, bytes for cache */ + u_int cai_linesize; /* or page size for TLB */ + const char *cai_string; +}; + +#define CAI_ITLB 0 /* Instruction TLB (4K pages) */ +#define CAI_ITLB2 1 /* Instruction TLB (2/4M pages) */ +#define CAI_DTLB 2 /* Data TLB (4K pages) */ +#define CAI_DTLB2 3 /* Data TLB (2/4M pages) */ +#define CAI_ICACHE 4 /* Instruction cache */ +#define CAI_DCACHE 5 /* Data cache */ +#define CAI_L2CACHE 6 /* Level 2 cache */ + +#define CAI_COUNT 7 + +struct cpu_info; + +const struct x86_cache_info *cache_info_lookup(const struct x86_cache_info *, + u_int8_t); +void amd_cpu_cacheinfo(struct cpu_info *); +void x86_print_cacheinfo(struct cpu_info *); + +/* + * AMD Cache Info: + * + * Athlon, Duron: + * + * Function 8000.0005 L1 TLB/Cache Information + * EAX -- L1 TLB 2/4MB pages + * EBX -- L1 TLB 4K pages + * ECX -- L1 D-cache + * EDX -- L1 I-cache + * + * Function 8000.0006 L2 TLB/Cache Information + * EAX -- L2 TLB 2/4MB pages + * EBX -- L2 TLB 4K pages + * ECX -- L2 Unified cache + * EDX -- reserved + * + * K5, K6: + * + * Function 8000.0005 L1 TLB/Cache Information + * EAX -- reserved + * EBX -- TLB 4K pages + * ECX -- L1 D-cache + * EDX -- L1 I-cache + * + * K6-III: + * + * Function 8000.0006 L2 Cache Information + * EAX -- reserved + * EBX -- reserved + * ECX -- L2 Unified cache + * EDX -- reserved + */ + +/* L1 TLB 2/4MB pages */ +#define AMD_L1_EAX_DTLB_ASSOC(x) (((x) >> 24) & 0xff) +#define AMD_L1_EAX_DTLB_ENTRIES(x) (((x) >> 16) & 0xff) +#define AMD_L1_EAX_ITLB_ASSOC(x) (((x) >> 8) & 0xff) +#define AMD_L1_EAX_ITLB_ENTRIES(x) ( (x) & 0xff) + +/* L1 TLB 4K pages */ +#define AMD_L1_EBX_DTLB_ASSOC(x) (((x) >> 24) & 0xff) +#define AMD_L1_EBX_DTLB_ENTRIES(x) (((x) >> 16) & 0xff) +#define AMD_L1_EBX_ITLB_ASSOC(x) (((x) >> 8) & 0xff) +#define AMD_L1_EBX_ITLB_ENTRIES(x) ( (x) & 0xff) + +/* L1 Data Cache */ +#define AMD_L1_ECX_DC_SIZE(x) ((((x) >> 24) & 0xff) * 1024) +#define AMD_L1_ECX_DC_ASSOC(x) (((x) >> 16) & 0xff) +#define AMD_L1_ECX_DC_LPT(x) (((x) >> 8) & 0xff) +#define AMD_L1_ECX_DC_LS(x) ( (x) & 0xff) + +/* L1 Instruction Cache */ +#define AMD_L1_EDX_IC_SIZE(x) ((((x) >> 24) & 0xff) * 1024) +#define AMD_L1_EDX_IC_ASSOC(x) (((x) >> 16) & 0xff) +#define AMD_L1_EDX_IC_LPT(x) (((x) >> 8) & 0xff) +#define AMD_L1_EDX_IC_LS(x) ( (x) & 0xff) + +/* Note for L2 TLB -- if the upper 16 bits are 0, it is a unified TLB */ + +/* L2 TLB 2/4MB pages */ +#define AMD_L2_EAX_DTLB_ASSOC(x) (((x) >> 28) & 0xf) +#define AMD_L2_EAX_DTLB_ENTRIES(x) (((x) >> 16) & 0xfff) +#define AMD_L2_EAX_IUTLB_ASSOC(x) (((x) >> 12) & 0xf) +#define AMD_L2_EAX_IUTLB_ENTRIES(x) ( (x) & 0xfff) + +/* L2 TLB 4K pages */ +#define AMD_L2_EBX_DTLB_ASSOC(x) (((x) >> 28) & 0xf) +#define AMD_L2_EBX_DTLB_ENTRIES(x) (((x) >> 16) & 0xfff) +#define AMD_L2_EBX_IUTLB_ASSOC(x) (((x) >> 12) & 0xf) +#define AMD_L2_EBX_IUTLB_ENTRIES(x) ( (x) & 0xfff) + +/* L2 Cache */ +#define AMD_L2_ECX_C_SIZE(x) ((((x) >> 16) & 0xffff) * 1024) +#define AMD_L2_ECX_C_ASSOC(x) (((x) >> 12) & 0xf) +#define AMD_L2_ECX_C_LPT(x) (((x) >> 8) & 0xf) +#define AMD_L2_ECX_C_LS(x) ( (x) & 0xff) + +#endif /* _X86_CACHEINFO_H */ diff --git a/sys/arch/amd64/include/cdefs.h b/sys/arch/amd64/include/cdefs.h new file mode 100644 index 00000000000..26606d3e377 --- /dev/null +++ b/sys/arch/amd64/include/cdefs.h @@ -0,0 +1,23 @@ +/* $OpenBSD: cdefs.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: cdefs.h,v 1.2 1995/03/23 20:10:26 jtc Exp $ */ + +/* + * Written by J.T. Conklin <jtc@wimsey.com> 01/17/95. + * Public domain. + */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#if defined(__GNUC__) && defined(__STDC__) +#define __weak_alias(alias,sym) \ + __asm__(".weak " __STRING(alias) " ; " __STRING(alias) " = " __STRING(sym)) +#define __warn_references(sym,msg) \ + __asm__(".section .gnu.warning." __STRING(sym) " ; .ascii \"" msg "\" ; .text") +#else +#define __indr_reference(sym,alias) +#define __warn_references(sym,msg) +#define __weak_alias(alias,sym) +#endif + +#endif /* !_MACHINE_CDEFS_H_ */ diff --git a/sys/arch/amd64/include/conf.h b/sys/arch/amd64/include/conf.h new file mode 100644 index 00000000000..0eeee30a029 --- /dev/null +++ b/sys/arch/amd64/include/conf.h @@ -0,0 +1,45 @@ +/* $OpenBSD: conf.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */ + +/* + * Copyright (c) 1996 Christos Zoulas. 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 Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +#include <sys/conf.h> + +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); + +bdev_decl(fd); +cdev_decl(fd); + +cdev_decl(spkr); + +#define biosselect seltrue +cdev_decl(bios); diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h new file mode 100644 index 00000000000..44e4a446ccb --- /dev/null +++ b/sys/arch/amd64/include/cpu.h @@ -0,0 +1,376 @@ +/* $OpenBSD: cpu.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)cpu.h 5.4 (Berkeley) 5/9/91 + */ + +#ifndef _AMD64_CPU_H_ +#define _AMD64_CPU_H_ + +/* + * Definitions unique to x86-64 cpu support. + */ +#include <machine/frame.h> +#include <machine/segments.h> +#include <machine/tss.h> +#include <machine/intrdefs.h> +#include <machine/cacheinfo.h> + +#include <sys/device.h> +#include <sys/lock.h> + +struct cpu_info { + struct device *ci_dev; + struct cpu_info *ci_self; +#if 0 + struct schedstate_percpu ci_schedstate; /* scheduler state */ +#endif + struct cpu_info *ci_next; + + struct proc *ci_curproc; + struct simplelock ci_slock; + u_int ci_cpuid; + u_int ci_apicid; + u_long ci_spin_locks; + u_long ci_simple_locks; + + u_int64_t ci_scratch; + + struct proc *ci_fpcurproc; + int ci_fpsaving; + + volatile u_int32_t ci_tlb_ipi_mask; + + struct pcb *ci_curpcb; + struct pcb *ci_idle_pcb; + int ci_idle_tss_sel; + + struct intrsource *ci_isources[MAX_INTR_SOURCES]; + u_int32_t ci_ipending; + int ci_ilevel; + int ci_idepth; + u_int32_t ci_imask[NIPL]; + u_int32_t ci_iunmask[NIPL]; + + paddr_t ci_idle_pcb_paddr; + u_int ci_flags; + u_int32_t ci_ipis; + + u_int32_t ci_feature_flags; + u_int32_t ci_signature; + u_int64_t ci_tsc_freq; + + struct cpu_functions *ci_func; + void (*cpu_setup)(struct cpu_info *); + void (*ci_info)(struct cpu_info *); + + int ci_want_resched; + int ci_astpending; + struct trapframe *ci_ddb_regs; + + struct x86_cache_info ci_cinfo[CAI_COUNT]; + + struct timeval ci_cc_time; + int64_t ci_cc_cc; + int64_t ci_cc_ms_delta; + int64_t ci_cc_denom; + + char *ci_gdt; + + struct x86_64_tss ci_doubleflt_tss; + struct x86_64_tss ci_ddbipi_tss; + + char *ci_doubleflt_stack; + char *ci_ddbipi_stack; + + struct evcnt ci_ipi_events[X86_NIPI]; +}; + +#define CPUF_BSP 0x0001 /* CPU is the original BSP */ +#define CPUF_AP 0x0002 /* CPU is an AP */ +#define CPUF_SP 0x0004 /* CPU is only processor */ +#define CPUF_PRIMARY 0x0008 /* CPU is active primary processor */ + +#define CPUF_PRESENT 0x1000 /* CPU is present */ +#define CPUF_RUNNING 0x2000 /* CPU is running */ +#define CPUF_PAUSE 0x4000 /* CPU is paused in DDB */ +#define CPUF_GO 0x8000 /* CPU should start running */ + +#define PROC_PC(p) ((p)->p_md.md_regs->tf_rip) + +extern struct cpu_info cpu_info_primary; +extern struct cpu_info *cpu_info_list; + +#define CPU_INFO_ITERATOR int +#define CPU_INFO_FOREACH(cii, ci) cii = 0, ci = cpu_info_list; \ + ci != NULL; ci = ci->ci_next + +#if defined(MULTIPROCESSOR) + +#define X86_MAXPROCS 32 /* bitmask; can be bumped to 64 */ + +#define CPU_STARTUP(_ci) ((_ci)->ci_func->start(_ci)) +#define CPU_STOP(_ci) ((_ci)->ci_func->stop(_ci)) +#define CPU_START_CLEANUP(_ci) ((_ci)->ci_func->cleanup(_ci)) + +#define curcpu() ({struct cpu_info *__ci; \ + asm volatile("movq %%gs:8,%0" : "=r" (__ci)); \ + __ci;}) +#define cpu_number() (curcpu()->ci_cpuid) + +#define CPU_IS_PRIMARY(ci) ((ci)->ci_flags & CPUF_PRIMARY) + +extern struct cpu_info *cpu_info[X86_MAXPROCS]; + +void cpu_boot_secondary_processors(void); +void cpu_init_idle_pcbs(void); + + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +extern void need_resched(struct cpu_info *); + +#else /* !MULTIPROCESSOR */ + +#define X86_MAXPROCS 1 + +#ifdef _KERNEL +extern struct cpu_info cpu_info_primary; + +#define curcpu() (&cpu_info_primary) + +#endif + +/* + * definitions of cpu-dependent requirements + * referenced in generic code + */ +#define cpu_number() 0 +#define CPU_IS_PRIMARY(ci) 1 + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ + +#ifdef MULTIPROCESSOR +#define need_resched(ci) \ +do { \ + struct cpu_info *__ci = (ci); \ + __ci->ci_want_resched = 1; \ + if (__ci->ci_curproc != NULL) \ + aston(__ci->ci_curproc); \ +} while (/*CONSTCOND*/0) +#else +#define need_resched() \ +do { \ + struct cpu_info *__ci = curcpu(); \ + __ci->ci_want_resched = 1; \ + if (__ci->ci_curproc != NULL) \ + aston(__ci->ci_curproc); \ +} while (/*CONSTCOND*/0) +#endif + +#endif + +#define aston(p) ((p)->p_md.md_astpending = 1) + +extern u_int32_t cpus_attached; + +#define curpcb curcpu()->ci_curpcb +#define curproc curcpu()->ci_curproc + +/* + * Arguments to hardclock, softclock and statclock + * encapsulate the previous machine state in an opaque + * clockframe; for now, use generic intrframe. + */ +#define clockframe intrframe + +#define CLKF_USERMODE(frame) USERMODE((frame)->if_cs, (frame)->if_rflags) +#define CLKF_BASEPRI(frame) (0) +#define CLKF_PC(frame) ((frame)->if_rip) +#define CLKF_INTR(frame) (curcpu()->ci_idepth > 1) + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the i386, request an ast to send us + * through trap(), marking the proc as needing a profiling tick. + */ +#define need_proftick(p) ((p)->p_flag |= P_OWEUPC, aston(p)) + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ +#define signotify(p) aston(p) + +/* + * We need a machine-independent name for this. + */ +extern void (*delay_func)(int); +struct timeval; +extern void (*microtime_func)(struct timeval *); + +#define DELAY(x) (*delay_func)(x) +#define delay(x) (*delay_func)(x) +#define microtime(tv) (*microtime_func)(tv) + + +/* + * pull in #defines for kinds of processors + */ + +#ifdef _KERNEL +extern int biosbasemem; +extern int biosextmem; +extern int cpu; +extern int cpu_feature; +extern int cpu_id; +extern char cpu_vendor[]; +extern int cpuid_level; + +/* kern_microtime.c */ + +extern struct timeval cc_microset_time; +void cc_microtime(struct timeval *); +void cc_microset(struct cpu_info *); + +/* identcpu.c */ + +void identifycpu(struct cpu_info *); +void cpu_probe_features(struct cpu_info *); + +/* machdep.c */ +void delay(int); +void dumpconf(void); +int cpu_maxproc(void); +void cpu_reset(void); +void x86_64_proc0_tss_ldt_init(void); +void x86_64_bufinit(void); +void x86_64_init_pcb_tss_ldt(struct cpu_info *); +void cpu_proc_fork(struct proc *, struct proc *); + +struct region_descriptor; +void lgdt(struct region_descriptor *); +void fillw(short, void *, size_t); + +struct pcb; +void savectx(struct pcb *); +void switch_exit(struct proc *, void (*)(struct proc *)); +void proc_trampoline(void); +void child_trampoline(void); + +/* clock.c */ +void initrtclock(void); +void startrtclock(void); +void i8254_delay(int); +void i8254_microtime(struct timeval *); +void i8254_initclocks(void); + +void cpu_init_msrs(struct cpu_info *); + + +/* trap.c */ +void child_return(void *); + +/* consinit.c */ +void kgdb_port_init(void); + +/* bus_machdep.c */ +void x86_bus_space_init(void); +void x86_bus_space_mallocok(void); + +#endif /* _KERNEL */ + +#include <machine/psl.h> + +/* + * CTL_MACHDEP definitions. + */ +#define CPU_CONSDEV 1 /* dev_t: console terminal device */ +#define CPU_BIOSBASEMEM 2 /* int: bios-reported base mem (K) */ +#define CPU_BIOSEXTMEM 3 /* int: bios-reported ext. mem (K) */ +#define CPU_NKPDE 4 /* int: number of kernel PDEs */ +#define CPU_BOOTED_KERNEL 5 /* string: booted kernel name */ +#define CPU_DISKINFO 6 /* disk geometry information */ +#define CPU_FPU_PRESENT 7 /* FPU is present */ +#define CPU_MAXID 8 /* number of valid machdep ids */ + +#define CTL_MACHDEP_NAMES { \ + { 0, 0 }, \ + { "console_device", CTLTYPE_STRUCT }, \ + { "biosbasemem", CTLTYPE_INT }, \ + { "biosextmem", CTLTYPE_INT }, \ + { "nkpde", CTLTYPE_INT }, \ + { "booted_kernel", CTLTYPE_STRING }, \ + { "diskinfo", CTLTYPE_STRUCT }, \ + { "fpu_present", CTLTYPE_INT }, \ +} + + +/* + * Structure for CPU_DISKINFO sysctl call. + * XXX this should be somewhere else. + */ +#define MAX_BIOSDISKS 16 + +struct disklist { + int dl_nbiosdisks; /* number of bios disks */ + struct biosdisk_info { + int bi_dev; /* BIOS device # (0x80 ..) */ + int bi_cyl; /* cylinders on disk */ + int bi_head; /* heads per track */ + int bi_sec; /* sectors per track */ + u_int64_t bi_lbasecs; /* total sec. (iff ext13) */ +#define BIFLAG_INVALID 0x01 +#define BIFLAG_EXTINT13 0x02 + int bi_flags; + } dl_biosdisks[MAX_BIOSDISKS]; + + int dl_nnativedisks; /* number of native disks */ + struct nativedisk_info { + char ni_devname[16]; /* native device name */ + int ni_nmatches; /* # of matches w/ BIOS */ + int ni_biosmatches[MAX_BIOSDISKS]; /* indices in dl_biosdisks */ + } dl_nativedisks[1]; /* actually longer */ +}; + +#endif /* !_AMD64_CPU_H_ */ diff --git a/sys/arch/amd64/include/cpufunc.h b/sys/arch/amd64/include/cpufunc.h new file mode 100644 index 00000000000..085a658a23e --- /dev/null +++ b/sys/arch/amd64/include/cpufunc.h @@ -0,0 +1,280 @@ +/* $OpenBSD: cpufunc.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: cpufunc.h,v 1.3 2003/05/08 10:27:43 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +#ifndef _AMD64_CPUFUNC_H_ +#define _AMD64_CPUFUNC_H_ + +/* + * Functions to provide access to i386-specific instructions. + */ + +#include <sys/cdefs.h> +#include <sys/types.h> + +#include <machine/specialreg.h> + +static __inline void +x86_pause(void) +{ + /* nothing */ +} + +#ifdef _KERNEL + +extern int cpu_feature; + +static __inline void +invlpg(u_int64_t addr) +{ + __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory"); +} + +static __inline void +lidt(void *p) +{ + __asm __volatile("lidt (%0)" : : "r" (p)); +} + +static __inline void +lldt(u_short sel) +{ + __asm __volatile("lldt %0" : : "r" (sel)); +} + +static __inline void +ltr(u_short sel) +{ + __asm __volatile("ltr %0" : : "r" (sel)); +} + +static __inline void +lcr8(u_int val) +{ + u_int64_t val64 = val; + __asm __volatile("movq %0,%%cr8" : : "r" (val64)); +} + +/* + * Upper 32 bits are reserved anyway, so just keep this 32bits. + */ +static __inline void +lcr0(u_int val) +{ + u_int64_t val64 = val; + __asm __volatile("movq %0,%%cr0" : : "r" (val64)); +} + +static __inline u_int +rcr0(void) +{ + u_int64_t val64; + u_int val; + __asm __volatile("movq %%cr0,%0" : "=r" (val64)); + val = val64; + return val; +} + +static __inline u_int64_t +rcr2(void) +{ + u_int64_t val; + __asm __volatile("movq %%cr2,%0" : "=r" (val)); + return val; +} + +static __inline void +lcr3(u_int64_t val) +{ + __asm __volatile("movq %0,%%cr3" : : "r" (val)); +} + +static __inline u_int64_t +rcr3(void) +{ + u_int64_t val; + __asm __volatile("movq %%cr3,%0" : "=r" (val)); + return val; +} + +/* + * Same as for cr0. Don't touch upper 32 bits. + */ +static __inline void +lcr4(u_int val) +{ + u_int64_t val64 = val; + + __asm __volatile("movq %0,%%cr4" : : "r" (val64)); +} + +static __inline u_int +rcr4(void) +{ + u_int val; + u_int64_t val64; + __asm __volatile("movq %%cr4,%0" : "=r" (val64)); + val = val64; + return val; +} + +static __inline void +tlbflush(void) +{ + u_int64_t val; + __asm __volatile("movq %%cr3,%0" : "=r" (val)); + __asm __volatile("movq %0,%%cr3" : : "r" (val)); +} + +static __inline void +tlbflushg(void) +{ + /* + * Big hammer: flush all TLB entries, including ones from PTE's + * with the G bit set. This should only be necessary if TLB + * shootdown falls far behind. + * + * Intel Architecture Software Developer's Manual, Volume 3, + * System Programming, section 9.10, "Invalidating the + * Translation Lookaside Buffers (TLBS)": + * "The following operations invalidate all TLB entries, irrespective + * of the setting of the G flag: + * ... + * "(P6 family processors only): Writing to control register CR4 to + * modify the PSE, PGE, or PAE flag." + * + * (the alternatives not quoted above are not an option here.) + * + * If PGE is not in use, we reload CR3 for the benefit of + * pre-P6-family processors. + */ + + if (cpu_feature & CPUID_PGE) { + u_int cr4 = rcr4(); + lcr4(cr4 & ~CR4_PGE); + lcr4(cr4); + } else + tlbflush(); +} + +#ifdef notyet +void setidt(int idx, /*XXX*/caddr_t func, int typ, int dpl); +#endif + + +/* XXXX ought to be in psl.h with spl() functions */ + +static __inline void +disable_intr(void) +{ + __asm __volatile("cli"); +} + +static __inline void +enable_intr(void) +{ + __asm __volatile("sti"); +} + +static __inline u_long +read_rflags(void) +{ + u_long ef; + + __asm __volatile("pushfq; popq %0" : "=r" (ef)); + return (ef); +} + +static __inline void +write_rflags(u_long ef) +{ + __asm __volatile("pushq %0; popfq" : : "r" (ef)); +} + +static __inline u_int64_t +rdmsr(u_int msr) +{ + uint32_t hi, lo; + __asm __volatile("rdmsr" : "=d" (hi), "=a" (lo) : "c" (msr)); + return (((uint64_t)hi << 32) | (uint64_t) lo); +} + +static __inline void +wrmsr(u_int msr, u_int64_t newval) +{ + __asm __volatile("wrmsr" : + : "a" (newval & 0xffffffff), "d" (newval >> 32), "c" (msr)); +} + +static __inline void +wbinvd(void) +{ + __asm __volatile("wbinvd"); +} + +static __inline u_int64_t +rdtsc(void) +{ + uint32_t hi, lo; + + __asm __volatile("rdtsc" : "=d" (hi), "=a" (lo)); + return (((uint64_t)hi << 32) | (uint64_t) lo); +} + +static __inline u_int64_t +rdpmc(u_int pmc) +{ + uint32_t hi, lo; + + __asm __volatile("rdpmc" : "=d" (hi), "=a" (lo) : "c" (pmc)); + return (((uint64_t)hi << 32) | (uint64_t) lo); +} + +/* Break into DDB/KGDB. */ +static __inline void +breakpoint(void) +{ + __asm __volatile("int $3"); +} + +#define read_psl() read_rflags() +#define write_psl(x) write_rflags(x) + +#endif /* _KERNEL */ + +#endif /* !_AMD64_CPUFUNC_H_ */ diff --git a/sys/arch/amd64/include/cpuvar.h b/sys/arch/amd64/include/cpuvar.h new file mode 100644 index 00000000000..b821592e1b8 --- /dev/null +++ b/sys/arch/amd64/include/cpuvar.h @@ -0,0 +1,109 @@ +/* $OpenBSD: cpuvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: cpuvar.h,v 1.1 2003/03/01 18:29:28 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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) 1999 Stefan Grefen + * + * 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 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 AND 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. + */ + +struct cpu_functions { + int (*start)(struct cpu_info *); + int (*stop)(struct cpu_info *); + void (*cleanup)(struct cpu_info *); +}; + +extern struct cpu_functions mp_cpu_funcs; + +#define CPU_ROLE_SP 0 +#define CPU_ROLE_BP 1 +#define CPU_ROLE_AP 2 + +struct cpu_attach_args { + const char *caa_name; + int cpu_number; + int cpu_role; + struct cpu_functions *cpu_func; +}; + +#define MP_PICMODE 0x00000001 /* System booted in picmode */ + +#ifdef _KERNEL + +#ifdef MULTIPROCESSOR +extern u_int32_t cpus_running; +#endif + +int x86_ipi(int,int,int); +void x86_self_ipi(int); +int x86_ipi_init(int); + +void identifycpu(struct cpu_info *); +void cpu_init(struct cpu_info *); +void cpu_init_first(void); + +#endif diff --git a/sys/arch/amd64/include/db_machdep.h b/sys/arch/amd64/include/db_machdep.h new file mode 100644 index 00000000000..c2569ee9379 --- /dev/null +++ b/sys/arch/amd64/include/db_machdep.h @@ -0,0 +1,141 @@ +/* $OpenBSD: db_machdep.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: db_machdep.h,v 1.2 2003/04/29 17:06:04 scw Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * 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 Mellon + * the rights to redistribute these changes. + */ + +#ifndef _I386_DB_MACHDEP_H_ +#define _I386_DB_MACHDEP_H_ + +/* + * Machine-dependent defines for new kernel debugger. + */ + +#include <sys/param.h> +#include <uvm/uvm_extern.h> +#include <machine/trap.h> + +typedef vaddr_t db_addr_t; /* address - unsigned */ +typedef long db_expr_t; /* expression - signed */ + +typedef struct trapframe db_regs_t; +#ifndef MULTIPROCESSOR +extern db_regs_t ddb_regs; /* register state */ +#define DDB_REGS (&ddb_regs) +#else +extern db_regs_t *ddb_regp; +#define DDB_REGS (ddb_regp) +#define ddb_regs (*ddb_regp) +#endif + +#if defined(lint) +#define PC_REGS(regs) ((regs)->tf_rip) +#else +#define PC_REGS(regs) ((db_addr_t)(regs)->tf_rip) +#endif + +#define BKPT_ADDR(addr) (addr) /* breakpoint address */ +#define BKPT_INST 0xcc /* breakpoint instruction */ +#define BKPT_SIZE (1) /* size of breakpoint inst */ +#define BKPT_SET(inst) (BKPT_INST) + +#define FIXUP_PC_AFTER_BREAK(regs) ((regs)->tf_rip -= BKPT_SIZE) + +#define db_clear_single_step(regs) ((regs)->tf_rflags &= ~PSL_T) +#define db_set_single_step(regs) ((regs)->tf_rflags |= PSL_T) + +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT) +#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_TRCTRAP && (code) & 15) + +#define I_CALL 0xe8 +#define I_CALLI 0xff +#define I_RET 0xc3 +#define I_IRET 0xcf + +#define inst_trap_return(ins) (((ins)&0xff) == I_IRET) +#define inst_return(ins) (((ins)&0xff) == I_RET) +#define inst_call(ins) (((ins)&0xff) == I_CALL || \ + (((ins)&0xff) == I_CALLI && \ + ((ins)&0x3800) == 0x1000)) +#define inst_load(ins) 0 +#define inst_store(ins) 0 + +/* access capability and access macros */ + +#define DB_ACCESS_LEVEL 2 /* access any space */ +#define DB_CHECK_ACCESS(addr,size,task) \ + db_check_access(addr,size,task) +#define DB_PHYS_EQ(task1,addr1,task2,addr2) \ + db_phys_eq(task1,addr1,task2,addr2) +#define DB_VALID_KERN_ADDR(addr) \ + ((addr) >= VM_MIN_KERNEL_ADDRESS && \ + (addr) < VM_MAX_KERNEL_ADDRESS) +#define DB_VALID_ADDRESS(addr,user) \ + ((!(user) && DB_VALID_KERN_ADDR(addr)) || \ + ((user) && (addr) < VM_MAX_ADDRESS)) + +#if 0 +boolean_t db_check_access(vaddr_t, int, task_t); +boolean_t db_phys_eq(task_t, vaddr_t, task_t, vaddr_t); +#endif + +/* macros for printing OS server dependent task name */ + +#define DB_TASK_NAME(task) db_task_name(task) +#define DB_TASK_NAME_TITLE "COMMAND " +#define DB_TASK_NAME_LEN 23 +#define DB_NULL_TASK_NAME "? " + +/* + * Constants for KGDB. + */ +typedef long kgdb_reg_t; +#define KGDB_NUMREGS 16 +#define KGDB_BUFLEN 512 + +#if 0 +void db_task_name(/* task_t */); +#endif + +/* macro for checking if a thread has used floating-point */ + +#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0) + +int kdb_trap(int, int, db_regs_t *); + +/* + * We define some of our own commands + */ +#define DB_MACHINE_COMMANDS + +#define DB_ELF_SYMBOLS +#define DB_ELFSIZE 64 + +extern void db_machine_init(void); + +extern void cpu_debug_dump(void); + +#endif /* _I386_DB_MACHDEP_H_ */ diff --git a/sys/arch/amd64/include/disklabel.h b/sys/arch/amd64/include/disklabel.h new file mode 100644 index 00000000000..8b2ef5f335c --- /dev/null +++ b/sys/arch/amd64/include/disklabel.h @@ -0,0 +1,118 @@ +/* $OpenBSD: disklabel.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: disklabel.h,v 1.3 1996/03/09 20:52:54 ghudson Exp $ */ + +/* + * Copyright (c) 1994 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 _MACHINE_DISKLABEL_H_ +#define _MACHINE_DISKLABEL_H_ + +#define LABELSECTOR 1 /* sector containing label */ +#define LABELOFFSET 0 /* offset of label in sector */ +#define MAXPARTITIONS 16 /* number of partitions */ +#define RAW_PART 2 /* raw partition: ie. rsd0c */ + +/* DOS partition table -- located in boot block */ +#define DOSBBSECTOR 0 /* DOS boot block relative sector # */ +#define DOSPARTOFF 446 +#define DOSDISKOFF 444 +#define NDOSPART 4 +#define DOSACTIVE 0x80 /* active partition */ + +struct dos_partition { + u_int8_t dp_flag; /* bootstrap flags */ + u_int8_t dp_shd; /* starting head */ + u_int8_t dp_ssect; /* starting sector */ + u_int8_t dp_scyl; /* starting cylinder */ + u_int8_t dp_typ; /* partition type (see below) */ + u_int8_t dp_ehd; /* end head */ + u_int8_t dp_esect; /* end sector */ + u_int8_t dp_ecyl; /* end cylinder */ + u_int32_t dp_start; /* absolute starting sector number */ + u_int32_t dp_size; /* partition size in sectors */ +}; + +/* Known DOS partition types. */ +#define DOSPTYP_UNUSED 0x00 /* Unused partition */ +#define DOSPTYP_FAT12 0x01 /* 12-bit FAT */ +#define DOSPTYP_FAT16S 0x04 /* 16-bit FAT, less than 32M */ +#define DOSPTYP_EXTEND 0x05 /* Extended; contains sub-partitions */ +#define DOSPTYP_FAT16B 0x06 /* 16-bit FAT, more than 32M */ +#define DOSPTYP_FAT32 0x0b /* 32-bit FAT */ +#define DOSPTYP_FAT32L 0x0c /* 32-bit FAT, LBA-mapped */ +#define DOSPTYP_FAT16L 0x0e /* 16-bit FAT, LBA-mapped */ +#define DOSPTYP_EXTENDL 0x0f /* Extended, LBA-mapped; contains sub-partitions */ +#define DOSPTYP_ONTRACK 0x54 +#define DOSPTYP_LINUX 0x83 /* That other thing */ +#define DOSPTYP_FREEBSD 0xa5 /* FreeBSD partition type */ +#define DOSPTYP_OPENBSD 0xa6 /* OpenBSD partition type */ +#define DOSPTYP_NETBSD 0xa9 /* NetBSD partition type */ + +struct dos_mbr { + u_int8_t dmbr_boot[DOSPARTOFF]; + struct dos_partition dmbr_parts[NDOSPART]; + u_int16_t dmbr_sign; +} __attribute__((__packed__)); + +#define DOSMBR_SIGNATURE (0xaa55) +#define DOSMBR_SIGNATURE_OFF (0x1fe) + +#include <sys/dkbad.h> +struct cpu_disklabel { + struct dos_partition dosparts[NDOSPART]; + struct dkbad bad; +}; + +#define DKBAD(x) ((x)->bad) + +/* Isolate the relevant bits to get sector and cylinder. */ +#define DPSECT(s) ((s) & 0x3f) +#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2)) + +static __inline u_int32_t get_le(void *); + +static __inline u_int32_t +#ifdef __cplusplus +get_le(void *p) +#else +get_le(p) + void *p; +#endif +{ + u_int8_t *_p = (u_int8_t *)p; + u_int32_t x; + x = _p[0]; + x |= _p[1] << 8; + x |= _p[2] << 16; + x |= _p[3] << 24; + return x; +} + +#endif /* _MACHINE_DISKLABEL_H_ */ diff --git a/sys/arch/amd64/include/endian.h b/sys/arch/amd64/include/endian.h new file mode 100644 index 00000000000..a8ee99504de --- /dev/null +++ b/sys/arch/amd64/include/endian.h @@ -0,0 +1,67 @@ +/* $OpenBSD: endian.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/*- + * Copyright (c) 1997 Niklas Hallqvist. 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 Niklas Hallqvist. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 _I386_ENDIAN_H_ +#define _I386_ENDIAN_H_ + +#ifdef __GNUC__ + +#define __swap32md(x) ({ \ + u_int32_t __swap32md_x = (x); \ + \ + __asm ("bswap %1" : "+r" (__swap32md_x)); \ + __swap32md_x; \ +}) + +/* XXX - I'm sure there is a better way on this cpu. */ +#define __swap64md(x) ({ \ + u_int64_t __swap64md_x = (x); \ + \ + (u_int64_t)__swap32md(__swap64md_x >> 32) | \ + (u_int64_t)__swap32md(__swap64md_x & 0xffffffff) << 32; \ +}) + +#define __swap16md(x) ({ \ + u_int16_t __swap16md_x = (x); \ + \ + __asm ("rorw $8, %w1" : "+r" (__swap16md_x)); \ + __swap16md_x; \ +}) + +/* Tell sys/endian.h we have MD variants of the swap macros. */ +#define MD_SWAP + +#endif /* __GNUC__ */ + +#define BYTE_ORDER LITTLE_ENDIAN +#include <sys/endian.h> + +#endif /* _I386_ENDIAN_H_ */ diff --git a/sys/arch/amd64/include/exec.h b/sys/arch/amd64/include/exec.h new file mode 100644 index 00000000000..45290aafa7d --- /dev/null +++ b/sys/arch/amd64/include/exec.h @@ -0,0 +1,22 @@ +/* $OpenBSD: exec.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* + * Written by Artur Grabowski <art@openbsd.org> Public Domain + */ + +#ifndef _AMD64_EXEC_H_ +#define _AMD64_EXEC_H_ + +#define __LDPGSZ 4096 + +#define NATIVE_EXEC_ELF + +#define ARCH_ELFSIZE 64 + +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_X86_64 + +#define _NLIST_DO_ELF +#define _KERN_DO_ELF64 + +#endif diff --git a/sys/arch/amd64/include/float.h b/sys/arch/amd64/include/float.h new file mode 100644 index 00000000000..7c315a0e10d --- /dev/null +++ b/sys/arch/amd64/include/float.h @@ -0,0 +1,77 @@ +/* $OpenBSD: float.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: float.h,v 1.8 1995/06/20 20:45:37 jtc Exp $ */ + +/* + * Copyright (c) 1989 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. 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. + * + * @(#)float.h 7.1 (Berkeley) 5/8/90 + */ + +#ifndef _I386_FLOAT_H_ +#define _I386_FLOAT_H_ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int __flt_rounds(void); +__END_DECLS + +#define FLT_RADIX 2 /* b */ +#define FLT_ROUNDS __flt_rounds() + +#define FLT_MANT_DIG 24 /* p */ +#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */ +#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */ +#define FLT_MIN_EXP (-125) /* emin */ +#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */ +#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */ +#define FLT_MAX_EXP 128 /* emax */ +#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */ +#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */ + +#define DBL_MANT_DIG 53 +#define DBL_EPSILON 2.2204460492503131E-16 +#define DBL_DIG 15 +#define DBL_MIN_EXP (-1021) +#define DBL_MIN 2.2250738585072014E-308 +#define DBL_MIN_10_EXP (-307) +#define DBL_MAX_EXP 1024 +#define DBL_MAX 1.7976931348623157E+308 +#define DBL_MAX_10_EXP 308 + +#define LDBL_MANT_DIG DBL_MANT_DIG +#define LDBL_EPSILON DBL_EPSILON +#define LDBL_DIG DBL_DIG +#define LDBL_MIN_EXP DBL_MIN_EXP +#define LDBL_MIN DBL_MIN +#define LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define LDBL_MAX_EXP DBL_MAX_EXP +#define LDBL_MAX DBL_MAX +#define LDBL_MAX_10_EXP DBL_MAX_10_EXP + +#endif /* _I386_FLOAT_H_ */ diff --git a/sys/arch/amd64/include/fpu.h b/sys/arch/amd64/include/fpu.h new file mode 100644 index 00000000000..a7952df5d54 --- /dev/null +++ b/sys/arch/amd64/include/fpu.h @@ -0,0 +1,84 @@ +/* $OpenBSD: fpu.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: fpu.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ + +#ifndef _AMD64_FPU_H_ +#define _AMD64_FPU_H_ + +#include <sys/types.h> + +/* + * NetBSD/amd64 only uses the extended save/restore format used + * by fxsave/fsrestore, to always deal with the SSE registers, + * which are part of the ABI to pass floating point values. + * Must be stored in memory on a 16-byte boundary. + */ + +struct fxsave64 { + u_int16_t fx_fcw; + u_int16_t fx_fsw; + u_int8_t fx_ftw; + u_int8_t fx_unused1; + u_int16_t fx_fop; + u_int64_t fx_rip; + u_int64_t fx_rdp; + u_int32_t fx_mxcsr; + u_int32_t fx_mxcsr_mask; + u_int64_t fx_st[8][2]; /* 8 normal FP regs */ + u_int64_t fx_xmm[16][2]; /* 16 SSE2 registers */ + u_int8_t fx_unused3[96]; +} __attribute__((packed)); + +struct savefpu { + struct fxsave64 fp_fxsave; /* see above */ + u_int16_t fp_ex_sw; /* saved status from last exception */ + u_int16_t fp_ex_tw; /* saved tag from last exception */ +}; + +/* + * The i387 defaults to Intel extended precision mode and round to nearest, + * with all exceptions masked. + */ +#define __INITIAL_NPXCW__ 0x037f +#define __INITIAL_MXCSR__ 0x1f80 +#define __INITIAL_MXCSR_MASK__ 0xffbf + +/* NetBSD uses IEEE double precision. */ +#define __NetBSD_NPXCW__ 0x127f +/* Linux just uses the default control word. */ +#define __Linux_NPXCW__ 0x037f + +/* + * The standard control word from finit is 0x37F, giving: + * round to nearest + * 64-bit precision + * all exceptions masked. + * + * Now we want: + * affine mode (if we decide to support 287's) + * round to nearest + * 53-bit precision + * all exceptions masked. + * + * 64-bit precision often gives bad results with high level languages + * because it makes the results of calculations depend on whether + * intermediate values are stored in memory or in FPU registers. + */ + +#ifdef _KERNEL +/* + * XXX + */ +struct trapframe; +struct cpu_info; + +void fpuinit(struct cpu_info *); +void fpudrop(void); +void fpusave(struct proc *); +void fpudiscard(struct proc *); +void fputrap(struct trapframe *); +void fpusave_proc(struct proc *, int); +void fpusave_cpu(struct cpu_info *, int); + +#endif + +#endif /* _AMD64_FPU_H_ */ diff --git a/sys/arch/amd64/include/frame.h b/sys/arch/amd64/include/frame.h new file mode 100644 index 00000000000..d0fb538ceeb --- /dev/null +++ b/sys/arch/amd64/include/frame.h @@ -0,0 +1,175 @@ +/* $OpenBSD: frame.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: frame.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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) 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. + * + * @(#)frame.h 5.2 (Berkeley) 1/18/91 + */ + +/* + * Adapted for NetBSD/amd64 by fvdl@wasabisystems.com + */ + +#ifndef _AMD64_FRAME_H_ +#define _AMD64_FRAME_H_ + +#include <sys/signal.h> +#include <machine/fpu.h> + +/* + * System stack frames. + */ + +/* + * Exception/Trap Stack Frame + */ +struct trapframe { + int64_t tf_rdi; + int64_t tf_rsi; + int64_t tf_rdx; + int64_t tf_rcx; + int64_t tf_r8; + int64_t tf_r9; + int64_t tf_r10; + int64_t tf_r11; + int64_t tf_r12; + int64_t tf_r13; + int64_t tf_r14; + int64_t tf_r15; + int64_t tf_rbp; + int64_t tf_rbx; + int64_t tf_rax; + int64_t tf_gs; + int64_t tf_fs; + int64_t tf_es; + int64_t tf_ds; + int64_t tf_trapno; + /* below portion defined in hardware */ + int64_t tf_err; + int64_t tf_rip; + int64_t tf_cs; + int64_t tf_rflags; + /* These are pushed unconditionally on the x86-64 */ + int64_t tf_rsp; + int64_t tf_ss; +}; + +/* + * Interrupt stack frame + */ +struct intrframe { + int64_t if_ppl; + int64_t if_rdi; + int64_t if_rsi; + int64_t if_rdx; + int64_t if_rcx; + int64_t if_r8; + int64_t if_r9; + int64_t if_r10; + int64_t if_r11; + int64_t if_r12; + int64_t if_r13; + int64_t if_r14; + int64_t if_r15; + int64_t if_rbp; + int64_t if_rbx; + int64_t if_rax; + int64_t tf_gs; + int64_t tf_fs; + int64_t tf_es; + int64_t tf_ds; + u_int64_t __if_trapno; /* for compat with trap frame - trapno */ + u_int64_t __if_err; /* for compat with trap frame - err */ + /* below portion defined in hardware */ + int64_t if_rip; + int64_t if_cs; + int64_t if_rflags; + /* These are pushed unconditionally on the x86-64 */ + int64_t if_rsp; + int64_t if_ss; +}; + +/* + * Stack frame inside cpu_switch() + */ +struct switchframe { + int64_t sf_ppl; + int64_t sf_r15; + int64_t sf_r14; + int64_t sf_r13; + int64_t sf_r12; + int64_t sf_rbp; + int64_t sf_rbx; + int64_t sf_rip; +}; + +#endif /* _AMD64_FRAME_H_ */ diff --git a/sys/arch/amd64/include/frameasm.h b/sys/arch/amd64/include/frameasm.h new file mode 100644 index 00000000000..c23b0e65a4d --- /dev/null +++ b/sys/arch/amd64/include/frameasm.h @@ -0,0 +1,94 @@ +/* $OpenBSD: frameasm.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: frameasm.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ + +#ifndef _AMD64_MACHINE_FRAMEASM_H +#define _AMD64_MACHINE_FRAMEASM_H + +/* + * Macros to define pushing/popping frames for interrupts, traps + * and system calls. Currently all the same; will diverge later. + */ + +/* + * These are used on interrupt or trap entry or exit. + */ +#define INTR_SAVE_GPRS \ + subq $120,%rsp ; \ + movq %r15,TF_R15(%rsp) ; \ + movq %r14,TF_R14(%rsp) ; \ + movq %r13,TF_R13(%rsp) ; \ + movq %r12,TF_R12(%rsp) ; \ + movq %r11,TF_R11(%rsp) ; \ + movq %r10,TF_R10(%rsp) ; \ + movq %r9,TF_R9(%rsp) ; \ + movq %r8,TF_R8(%rsp) ; \ + movq %rdi,TF_RDI(%rsp) ; \ + movq %rsi,TF_RSI(%rsp) ; \ + movq %rbp,TF_RBP(%rsp) ; \ + movq %rbx,TF_RBX(%rsp) ; \ + movq %rdx,TF_RDX(%rsp) ; \ + movq %rcx,TF_RCX(%rsp) ; \ + movq %rax,TF_RAX(%rsp) + +#define INTR_RESTORE_GPRS \ + movq TF_R15(%rsp),%r15 ; \ + movq TF_R14(%rsp),%r14 ; \ + movq TF_R13(%rsp),%r13 ; \ + movq TF_R12(%rsp),%r12 ; \ + movq TF_R11(%rsp),%r11 ; \ + movq TF_R10(%rsp),%r10 ; \ + movq TF_R9(%rsp),%r9 ; \ + movq TF_R8(%rsp),%r8 ; \ + movq TF_RDI(%rsp),%rdi ; \ + movq TF_RSI(%rsp),%rsi ; \ + movq TF_RBP(%rsp),%rbp ; \ + movq TF_RBX(%rsp),%rbx ; \ + movq TF_RDX(%rsp),%rdx ; \ + movq TF_RCX(%rsp),%rcx ; \ + movq TF_RAX(%rsp),%rax ; \ + addq $120,%rsp + +#define INTRENTRY \ + subq $32,%rsp ; \ + testq $SEL_UPL,56(%rsp) ; \ + je 98f ; \ + swapgs ; \ + movw %gs,0(%rsp) ; \ + movw %fs,8(%rsp) ; \ + movw %es,16(%rsp) ; \ + movw %ds,24(%rsp) ; \ +98: INTR_SAVE_GPRS + +#define INTRFASTEXIT \ + INTR_RESTORE_GPRS ; \ + testq $SEL_UPL,56(%rsp) ; \ + je 99f ; \ + cli ; \ + swapgs ; \ + movw 0(%rsp),%gs ; \ + movw 8(%rsp),%fs ; \ + movw 16(%rsp),%es ; \ + movw 24(%rsp),%ds ; \ +99: addq $48,%rsp ; \ + iretq + +#define INTR_RECURSE_HWFRAME \ + movq %rsp,%r10 ; \ + movl %ss,%r11d ; \ + pushq %r11 ; \ + pushq %r10 ; \ + pushfq ; \ + movl %cs,%r11d ; \ + pushq %r11 ; \ + pushq %r13 ; + + +#define CHECK_ASTPENDING(reg) movq CPUVAR(CURPROC),reg ; \ + cmpq $0, reg ; \ + je 99f ; \ + cmpl $0, P_MD_ASTPENDING(reg) ; \ + 99: + +#define CLEAR_ASTPENDING(reg) movl $0, P_MD_ASTPENDING(reg) + +#endif /* _AMD64_MACHINE_FRAMEASM_H */ diff --git a/sys/arch/amd64/include/gdt.h b/sys/arch/amd64/include/gdt.h new file mode 100644 index 00000000000..a26608a78e8 --- /dev/null +++ b/sys/arch/amd64/include/gdt.h @@ -0,0 +1,62 @@ +/* $OpenBSD: gdt.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: gdt.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by John T. Kohl and Charles M. Hannum. + * + * 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. + */ + +#ifndef _LOCORE +struct proc; +struct pmap; + +void gdt_init(void); +void gdt_init_cpu(struct cpu_info *); +void gdt_reload_cpu(struct cpu_info *); +void gdt_alloc_cpu(struct cpu_info *); + +int tss_alloc(struct pcb *); +void tss_free(int); + +void ldt_alloc(struct pmap *, char *, size_t); +void ldt_free(struct pmap *); + +void set_mem_gdt(struct mem_segment_descriptor *, void *, size_t, + int, int, int, int, int); +void set_sys_gdt(struct sys_segment_descriptor *, void *, size_t, int, int, + int); +#endif + +#define MINGDTSIZ 2048 +#define MAXGDTSIZ 65536 diff --git a/sys/arch/amd64/include/i82093reg.h b/sys/arch/amd64/include/i82093reg.h new file mode 100644 index 00000000000..91dc73bb1df --- /dev/null +++ b/sys/arch/amd64/include/i82093reg.h @@ -0,0 +1,121 @@ +/* $OpenBSD: i82093reg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: i82093reg.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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. + */ + +/* + * Typically, the first apic lives here. + */ +#define IOAPIC_BASE_DEFAULT 0xfec00000 + +/* + * Memory-space registers. + */ + +/* + * The externally visible registers are all 32 bits wide; + * store the register number of interest in IOAPIC_REG, and store/fetch + * the real value in IOAPIC_DATA. + */ + + + +#define IOAPIC_REG 0x0000 +#define IOAPIC_DATA 0x0010 + +/* + * Internal I/O APIC registers. + */ + +#define IOAPIC_ID 0x00 + +#define IOAPIC_ID_SHIFT 24 +#define IOAPIC_ID_MASK 0x0f000000 + +/* Version, and maximum interrupt pin number. */ + +#define IOAPIC_VER 0x01 + +#define IOAPIC_VER_SHIFT 0 +#define IOAPIC_VER_MASK 0x000000ff + +#define IOAPIC_MAX_SHIFT 16 +#define IOAPIC_MAX_MASK 0x00ff0000 + +/* + * Arbitration ID. Same format as IOAPIC_ID register. + */ +#define IOAPIC_ARB 0x02 + +/* + * Redirection table registers. + */ + +#define IOAPIC_REDHI(pin) (0x11 + ((pin)<<1)) +#define IOAPIC_REDLO(pin) (0x10 + ((pin)<<1)) + +#define IOAPIC_REDHI_DEST_SHIFT 24 /* destination. */ +#define IOAPIC_REDHI_DEST_MASK 0xff000000 + +#define IOAPIC_REDLO_MASK 0x00010000 /* 0=enabled; 1=masked */ + +#define IOAPIC_REDLO_LEVEL 0x00008000 /* 0=edge, 1=level */ +#define IOAPIC_REDLO_RIRR 0x00004000 /* remote IRR; read only */ +#define IOAPIC_REDLO_ACTLO 0x00002000 /* 0=act. hi; 1=act. lo */ +#define IOAPIC_REDLO_DELSTS 0x00001000 /* 0=idle; 1=send pending */ +#define IOAPIC_REDLO_DSTMOD 0x00000800 /* 0=physical; 1=logical */ + +#define IOAPIC_REDLO_DEL_MASK 0x00000700 /* del. mode mask */ +#define IOAPIC_REDLO_DEL_SHIFT 8 + +#define IOAPIC_REDLO_DEL_FIXED 0 +#define IOAPIC_REDLO_DEL_LOPRI 1 +#define IOAPIC_REDLO_DEL_SMI 2 +#define IOAPIC_REDLO_DEL_NMI 4 +#define IOAPIC_REDLO_DEL_INIT 5 +#define IOAPIC_REDLO_DEL_EXTINT 7 + +#define IOAPIC_REDLO_VECTOR_MASK 0x000000ff /* delivery vector */ + +#define IMCR_ADDR 0x22 +#define IMCR_DATA 0x23 + +#define IMCR_REGISTER 0x70 +#define IMCR_PIC 0x00 +#define IMCR_APIC 0x01 diff --git a/sys/arch/amd64/include/i82093var.h b/sys/arch/amd64/include/i82093var.h new file mode 100644 index 00000000000..78f1358bb63 --- /dev/null +++ b/sys/arch/amd64/include/i82093var.h @@ -0,0 +1,104 @@ +/* $OpenBSD: i82093var.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: i82093var.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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. + */ + +#ifndef _X86_I82093VAR_H_ +#define _X86_I82093VAR_H_ + +#include <machine/apicvar.h> + +struct ioapic_pin +{ + struct ioapic_pin *ip_next; /* next pin on this vector */ + struct mp_intr_map *ip_map; + int ip_vector; /* IDT vector */ + int ip_type; + struct cpu_info *ip_cpu; /* target CPU */ +}; + +struct ioapic_softc { + struct pic sc_pic; + struct ioapic_softc *sc_next; + int sc_apicid; + int sc_apic_vers; + int sc_apic_vecbase; /* global int base if ACPI */ + int sc_apic_sz; /* apic size*/ + int sc_flags; + paddr_t sc_pa; /* PA of ioapic */ + volatile u_int32_t *sc_reg; /* KVA of ioapic addr */ + volatile u_int32_t *sc_data; /* KVA of ioapic data */ + struct ioapic_pin *sc_pins; /* sc_apic_sz entries */ +}; + +/* + * MP: intr_handle_t is bitfielded. + * ih&0xff -> legacy irq number. + * ih&0x10000000 -> if 0, old-style isa irq; if 1, routed via ioapic. + * (ih&0xff0000)>>16 -> ioapic id. + * (ih&0x00ff00)>>8 -> ioapic pin. + */ + +#define APIC_INT_VIA_APIC 0x10000000 +#define APIC_INT_APIC_MASK 0x00ff0000 +#define APIC_INT_APIC_SHIFT 16 +#define APIC_INT_PIN_MASK 0x0000ff00 +#define APIC_INT_PIN_SHIFT 8 + +#define APIC_IRQ_APIC(x) ((x & APIC_INT_APIC_MASK) >> APIC_INT_APIC_SHIFT) +#define APIC_IRQ_PIN(x) ((x & APIC_INT_PIN_MASK) >> APIC_INT_PIN_SHIFT) +#define APIC_IRQ_ISLEGACY(x) (!((x) & APIC_INT_VIA_APIC)) +#define APIC_IRQ_LEGACY_IRQ(x) ((x) & 0xff) + +void *apic_intr_establish(int, int, int, int (*)(void *), void *); +void apic_intr_disestablish(void *); + +void ioapic_print_redir(struct ioapic_softc *, char *, int); +void ioapic_format_redir(char *, char *, int, u_int32_t, u_int32_t); +struct ioapic_softc *ioapic_find(int); +struct ioapic_softc *ioapic_find_bybase(int); + +void ioapic_enable(void); +void lapic_vectorset(void); /* XXX */ + +extern int ioapic_bsp_id; +extern int nioapics; +extern struct ioapic_softc *ioapics; + +#endif /* !_X86_I82093VAR_H_ */ diff --git a/sys/arch/amd64/include/i82489reg.h b/sys/arch/amd64/include/i82489reg.h new file mode 100644 index 00000000000..fb1bb6217b4 --- /dev/null +++ b/sys/arch/amd64/include/i82489reg.h @@ -0,0 +1,150 @@ +/* $OpenBSD: i82489reg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: i82489reg.h,v 1.1 2003/02/26 21:26:10 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Frank van der Linden. + * + * 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. + */ + + +/* + * Registers and constants for the 82489DX and Pentium (and up) integrated + * "local" APIC. + */ + +#define LAPIC_ID 0x020 /* ID. RW */ +# define LAPIC_ID_MASK 0x0f000000 +# define LAPIC_ID_SHIFT 24 + +#define LAPIC_VERS 0x030 /* Version. R */ +# define LAPIC_VERSION_MASK 0x000000ff +# define LAPIC_VERSION_LVT_MASK 0x00ff0000 +# define LAPIC_VERSION_LVT_SHIFT 16 + +#define LAPIC_TPRI 0x080 /* Task Prio. RW */ +# define LAPIC_TPRI_MASK 0x000000ff +# define LAPIC_TPRI_INT_MASK 0x000000f0 +# define LAPIC_TPRI_SUB_MASK 0x0000000f + +#define LAPIC_APRI 0x090 /* Arbitration prio R */ +# define LAPIC_APRI_MASK 0x000000ff + +#define LAPIC_PPRI 0x0a0 /* Processor prio. R */ +#define LAPIC_EOI 0x0b0 /* End Int. W */ +#define LAPIC_RRR 0x0c0 /* Remote read R */ +#define LAPIC_LDR 0x0d0 /* Logical dest. RW */ +#define LAPIC_DFR 0x0e0 /* Dest. format RW */ + +#define LAPIC_SVR 0x0f0 /* Spurious intvec RW */ +# define LAPIC_SVR_VECTOR_MASK 0x000000ff +# define LAPIC_SVR_VEC_FIX 0x0000000f +# define LAPIC_SVR_VEC_PROG 0x000000f0 +# define LAPIC_SVR_ENABLE 0x00000100 +# define LAPIC_SVR_SWEN 0x00000100 +# define LAPIC_SVR_FOCUS 0x00000200 +# define LAPIC_SVR_FDIS 0x00000200 + +#define LAPIC_ISR 0x100 /* Int. status. R */ +#define LAPIC_TMR 0x180 +#define LAPIC_IRR 0x200 +#define LAPIC_ESR 0x280 /* Err status. R */ + +#define LAPIC_ICRLO 0x300 /* Int. cmd. RW */ +# define LAPIC_DLMODE_MASK 0x00000700 +# define LAPIC_DLMODE_FIXED 0x00000000 +# define LAPIC_DLMODE_LOW 0x00000100 +# define LAPIC_DLMODE_SMI 0x00000200 +# define LAPIC_DLMODE_RR 0x00000300 +# define LAPIC_DLMODE_NMI 0x00000400 +# define LAPIC_DLMODE_INIT 0x00000500 +# define LAPIC_DLMODE_STARTUP 0x00000600 + +# define LAPIC_DSTMODE_LOG 0x00000800 + +# define LAPIC_DLSTAT_BUSY 0x00001000 + +# define LAPIC_LVL_ASSERT 0x00004000 +# define LAPIC_LVL_DEASSERT 0x00000000 + +# define LAPIC_LVL_TRIG 0x00008000 + +# define LAPIC_RRSTAT_MASK 0x00030000 +# define LAPIC_RRSTAT_INPROG 0x00010000 +# define LAPIC_RRSTAT_VALID 0x00020000 + +# define LAPIC_DEST_MASK 0x000c0000 +# define LAPIC_DEST_SELF 0x00040000 +# define LAPIC_DEST_ALLINCL 0x00080000 +# define LAPIC_DEST_ALLEXCL 0x000c0000 + +# define LAPIC_RESV2_MASK 0xfff00000 + + +#define LAPIC_ICRHI 0x310 /* Int. cmd. RW */ +# define LAPIC_ID_MASK 0x0f000000 +# define LAPIC_ID_SHIFT 24 + +#define LAPIC_LVTT 0x320 /* Loc.vec.(timer) RW */ +# define LAPIC_LVTT_VEC_MASK 0x000000ff +# define LAPIC_LVTT_DS 0x00001000 +# define LAPIC_LVTT_M 0x00010000 +# define LAPIC_LVTT_TM 0x00020000 + +#define LAPIC_PCINT 0x340 +#define LAPIC_LVINT0 0x350 /* Loc.vec (LINT0) RW */ +# define LAPIC_LVT_PERIODIC 0x00020000 +# define LAPIC_LVT_MASKED 0x00010000 +# define LAPIC_LVT_LEVTRIG 0x00008000 +# define LAPIC_LVT_REMOTE_IRR 0x00004000 +# define LAPIC_INP_POL 0x00002000 +# define LAPIC_PEND_SEND 0x00001000 + +#define LAPIC_LVINT1 0x360 /* Loc.vec (LINT1) RW */ +#define LAPIC_LVERR 0x370 /* Loc.vec (ERROR) RW */ +#define LAPIC_ICR_TIMER 0x380 /* Initial count RW */ +#define LAPIC_CCR_TIMER 0x390 /* Current count RO */ + +#define LAPIC_DCR_TIMER 0x3e0 /* Divisor config register */ +# define LAPIC_DCRT_DIV1 0x0b +# define LAPIC_DCRT_DIV2 0x00 +# define LAPIC_DCRT_DIV4 0x01 +# define LAPIC_DCRT_DIV8 0x02 +# define LAPIC_DCRT_DIV16 0x03 +# define LAPIC_DCRT_DIV32 0x08 +# define LAPIC_DCRT_DIV64 0x09 +# define LAPIC_DCRT_DIV128 0x0a + +#define LAPIC_BASE 0xfee00000 + +#define LAPIC_IRQ_MASK(i) (1 << ((i) + 1)) diff --git a/sys/arch/amd64/include/i8259.h b/sys/arch/amd64/include/i8259.h new file mode 100644 index 00000000000..e89f77f4164 --- /dev/null +++ b/sys/arch/amd64/include/i8259.h @@ -0,0 +1,152 @@ +/* $OpenBSD: i8259.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: i8259.h,v 1.3 2003/05/04 22:01:56 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)icu.h 5.6 (Berkeley) 5/9/91 + */ + +#ifndef _X86_I8259_H_ +#define _X86_I8259_H_ + +#include <dev/isa/isareg.h> + +#ifndef _LOCORE + +/* + * Interrupt "level" mechanism variables, masks, and macros + */ +extern unsigned i8259_imen; /* interrupt mask enable */ +extern unsigned i8259_setmask(unsigned); + +#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IO_ICU2 + 1, imen >> 8)) + +extern void i8259_default_setup(void); +extern void i8259_reinit(void); + +#endif /* !_LOCORE */ + +/* + * Interrupt enable bits -- in order of priority + */ +#define IRQ_SLAVE 2 + +/* + * Interrupt Control offset into Interrupt descriptor table (IDT) + */ +#define ICU_OFFSET 32 /* 0-31 are processor exceptions */ +#define ICU_LEN 16 /* 32-47 are ISA interrupts */ + + +#define ICU_HARDWARE_MASK + +/* + * These macros are fairly self explanatory. If ICU_SPECIAL_MASK_MODE is + * defined, we try to take advantage of the ICU's `special mask mode' by only + * EOIing the interrupts on return. This avoids the requirement of masking and + * unmasking. We can't do this without special mask mode, because the ICU + * would also hold interrupts that it thinks are of lower priority. + * + * Many machines do not support special mask mode, so by default we don't try + * to use it. + */ + +#define IRQ_BIT(num) (1 << ((num) % 8)) +#define IRQ_BYTE(num) ((num) >> 3) + +#define i8259_late_ack(num) + +#ifdef ICU_SPECIAL_MASK_MODE + +#define i8259_asm_ack1(num) +#define i8259_asm_ack2(num) \ + movb $(0x60|IRQ_SLAVE),%al /* specific EOI for IRQ2 */ ;\ + outb %al,$IO_ICU1 +#define i8259_asm_mask(num) +#define i8259_asm_unmask(num) \ + movb $(0x60|(num%8)),%al /* specific EOI */ ;\ + outb %al,$ICUADDR + +#else /* ICU_SPECIAL_MASK_MODE */ + +#ifndef AUTO_EOI_1 +#define i8259_asm_ack1(num) \ + movb $(0x60|(num%8)),%al /* specific EOI */ ;\ + outb %al,$IO_ICU1 +#else +#define i8259_asm_ack1(num) +#endif + +#ifndef AUTO_EOI_2 +#define i8259_asm_ack2(num) \ + movb $(0x60|(num%8)),%al /* specific EOI */ ;\ + outb %al,$IO_ICU2 /* do the second ICU first */ ;\ + movb $(0x60|IRQ_SLAVE),%al /* specific EOI for IRQ2 */ ;\ + outb %al,$IO_ICU1 +#else +#define i8259_asm_ack2(num) +#endif + +#ifdef PIC_MASKDELAY +#define MASKDELAY pushl %eax ; inb $0x84,%al ; popl %eax +#else +#define MASKDELAY +#endif + +#ifdef ICU_HARDWARE_MASK + +#define i8259_asm_mask(num) \ + movb CVAROFF(i8259_imen, IRQ_BYTE(num)),%al ;\ + orb $IRQ_BIT(num),%al ;\ + movb %al,CVAROFF(i8259_imen, IRQ_BYTE(num)) ;\ + MASKDELAY ;\ + outb %al,$(ICUADDR+1) +#define i8259_asm_unmask(num) \ + movb CVAROFF(i8259_imen, IRQ_BYTE(num)),%al ;\ + andb $~IRQ_BIT(num),%al ;\ + movb %al,CVAROFF(i8259_imen, IRQ_BYTE(num)) ;\ + MASKDELAY ;\ + outb %al,$(ICUADDR+1) + +#else /* ICU_HARDWARE_MASK */ + +#define i8259_asm_mask(num) +#define i8259_asm_unmask(num) + +#endif /* ICU_HARDWARE_MASK */ +#endif /* ICU_SPECIAL_MASK_MODE */ + +#endif /* !_X86_I8259_H_ */ diff --git a/sys/arch/amd64/include/ieee.h b/sys/arch/amd64/include/ieee.h new file mode 100644 index 00000000000..5a34355d223 --- /dev/null +++ b/sys/arch/amd64/include/ieee.h @@ -0,0 +1,133 @@ +/* $OpenBSD: ieee.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: ieee.h,v 1.1 1996/09/30 16:34:25 ws Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. 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. + * + * @(#)ieee.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * ieee.h defines the machine-dependent layout of the machine's IEEE + * floating point. It does *not* define (yet?) any of the rounding + * mode bits, exceptions, and so forth. + */ + +/* + * Define the number of bits in each fraction and exponent. + * + * k k+1 + * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented + * + * (-exp_bias+1) + * as fractions that look like 0.fffff x 2 . This means that + * + * -126 + * the number 0.10000 x 2 , for instance, is the same as the normalized + * + * -127 -128 + * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero + * + * -129 + * in the fraction; to represent 2 , we need two, and so on. This + * + * (-exp_bias-fracbits+1) + * implies that the smallest denormalized number is 2 + * + * for whichever format we are talking about: for single precision, for + * + * -126 -149 + * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and + * + * -149 == -127 - 23 + 1. + */ +#define SNG_EXPBITS 8 +#define SNG_FRACBITS 23 + +#define DBL_EXPBITS 11 +#define DBL_FRACBITS 52 + +#define EXT_EXPBITS 15 +#define EXT_FRACBITS 112 + +struct ieee_single { + u_int sng_frac:23; + u_int sng_exp:8; + u_int sng_sign:1; +}; + +struct ieee_double { + u_int dbl_fracl; + u_int dbl_frach:20; + u_int dbl_exp:11; + u_int dbl_sign:1; +}; + +struct ieee_ext { + u_int ext_fracl; + u_int ext_fraclm; + u_int ext_frachm; + u_int ext_frach:16; + u_int ext_exp:15; + u_int ext_sign:1; +}; + +/* + * Floats whose exponent is in [1..INFNAN) (of whatever type) are + * `normal'. Floats whose exponent is INFNAN are either Inf or NaN. + * Floats whose exponent is zero are either zero (iff all fraction + * bits are zero) or subnormal values. + * + * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its + * high fraction; if the bit is set, it is a `quiet NaN'. + */ +#define SNG_EXP_INFNAN 255 +#define DBL_EXP_INFNAN 2047 +#define EXT_EXP_INFNAN 32767 + +#if 0 +#define SNG_QUIETNAN (1 << 22) +#define DBL_QUIETNAN (1 << 19) +#define EXT_QUIETNAN (1 << 15) +#endif + +/* + * Exponent biases. + */ +#define SNG_EXP_BIAS 127 +#define DBL_EXP_BIAS 1023 +#define EXT_EXP_BIAS 16383 diff --git a/sys/arch/amd64/include/ieeefp.h b/sys/arch/amd64/include/ieeefp.h new file mode 100644 index 00000000000..774ee8d6adc --- /dev/null +++ b/sys/arch/amd64/include/ieeefp.h @@ -0,0 +1,26 @@ +/* $OpenBSD: ieeefp.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/* + * Written by J.T. Conklin, Apr 6, 1995 + * Public domain. + */ + +#ifndef _I386_IEEEFP_H_ +#define _I386_IEEEFP_H_ + +typedef int fp_except; +#define FP_X_INV 0x01 /* invalid operation exception */ +#define FP_X_DNML 0x02 /* denormalization exception */ +#define FP_X_DZ 0x04 /* divide-by-zero exception */ +#define FP_X_OFL 0x08 /* overflow exception */ +#define FP_X_UFL 0x10 /* underflow exception */ +#define FP_X_IMP 0x20 /* imprecise (loss of precision) */ + +typedef enum { + FP_RN=0, /* round to nearest representable number */ + FP_RM=1, /* round toward negative infinity */ + FP_RP=2, /* round toward positive infinity */ + FP_RZ=3 /* round to zero (truncate) */ +} fp_rnd; + +#endif /* _I386_IEEEFP_H_ */ diff --git a/sys/arch/amd64/include/internal_types.h b/sys/arch/amd64/include/internal_types.h new file mode 100644 index 00000000000..8237a6b4cef --- /dev/null +++ b/sys/arch/amd64/include/internal_types.h @@ -0,0 +1,10 @@ +/* $OpenBSD: internal_types.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* Public domain */ +#ifndef _MACHINE_INTERNAL_TYPES_H_ +#define _MACHINE_INTERNAL_TYPES_H_ + +#ifdef __x86_64__ +#define __machine_is_64_bits +#endif + +#endif diff --git a/sys/arch/amd64/include/intr.h b/sys/arch/amd64/include/intr.h new file mode 100644 index 00000000000..1b3390d7b17 --- /dev/null +++ b/sys/arch/amd64/include/intr.h @@ -0,0 +1,356 @@ +/* $OpenBSD: intr.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: intr.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum, and by Jason R. Thorpe. + * + * 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. + */ + +#ifndef _X86_INTR_H_ +#define _X86_INTR_H_ + +#include <machine/intrdefs.h> + +#ifndef _LOCORE +#include <machine/cpu.h> +#include <machine/pic.h> + +/* + * Struct describing an interrupt source for a CPU. struct cpu_info + * has an array of MAX_INTR_SOURCES of these. The index in the array + * is equal to the stub number of the stubcode as present in vector.s + * + * The primary CPU's array of interrupt sources has its first 16 + * entries reserved for legacy ISA irq handlers. This means that + * they have a 1:1 mapping for arrayindex:irq_num. This is not + * true for interrupts that come in through IO APICs, to find + * their source, go through ci->ci_isources[index].is_pic + * + * It's possible to always maintain a 1:1 mapping, but that means + * limiting the total number of interrupt sources to MAX_INTR_SOURCES + * (32), instead of 32 per CPU. It also would mean that having multiple + * IO APICs which deliver interrupts from an equal pin number would + * overlap if they were to be sent to the same CPU. + */ + +struct intrstub { + void *ist_entry; + void *ist_recurse; + void *ist_resume; +}; + +struct intrsource { + int is_maxlevel; /* max. IPL for this source */ + int is_pin; /* IRQ for legacy; pin for IO APIC */ + struct intrhand *is_handlers; /* handler chain */ + struct pic *is_pic; /* originating PIC */ + void *is_recurse; /* entry for spllower */ + void *is_resume; /* entry for doreti */ + struct evcnt is_evcnt; /* interrupt counter */ + char is_evname[32]; /* event counter name */ + int is_flags; /* see below */ + int is_type; /* level, edge */ + int is_idtvec; + int is_minlevel; +}; + +#define IS_LEGACY 0x0001 /* legacy ISA irq source */ +#define IS_IPI 0x0002 +#define IS_LOG 0x0004 + + +/* + * Interrupt handler chains. *_intr_establish() insert a handler into + * the list. The handler is called with its (single) argument. + */ + +struct intrhand { + int (*ih_fun)(void *); + void *ih_arg; + int ih_level; + struct intrhand *ih_next; + int ih_pin; + int ih_slot; + struct cpu_info *ih_cpu; + int ih_irq; + char *ih_what; +}; + +#define IMASK(ci,level) (ci)->ci_imask[(level)] +#define IUNMASK(ci,level) (ci)->ci_iunmask[(level)] + +extern void Xspllower(int); + +static __inline int splraise(int); +static __inline void spllower(int); +static __inline void softintr(int); + +/* + * Convert spl level to local APIC level + */ +#define APIC_LEVEL(l) ((l) << 4) + +/* + * compiler barrier: prevent reordering of instructions. + * XXX something similar will move to <sys/cdefs.h> + * or thereabouts. + * This prevents the compiler from reordering code around + * this "instruction", acting as a sequence point for code generation. + */ + +#define __splbarrier() __asm __volatile("":::"memory") + +/* + * Add a mask to cpl, and return the old value of cpl. + */ +static __inline int +splraise(int nlevel) +{ + int olevel; + struct cpu_info *ci = curcpu(); + + olevel = ci->ci_ilevel; + if (nlevel > olevel) + ci->ci_ilevel = nlevel; + __splbarrier(); + return (olevel); +} + +/* + * Restore a value to cpl (unmasking interrupts). If any unmasked + * interrupts are pending, call Xspllower() to process them. + */ +static __inline void +spllower(int nlevel) +{ + struct cpu_info *ci = curcpu(); + + __splbarrier(); + /* + * Since this should only lower the interrupt level, + * the XOR below should only show interrupts that + * are being unmasked. + */ + if (ci->ci_ipending & IUNMASK(ci,nlevel)) + Xspllower(nlevel); + else + ci->ci_ilevel = nlevel; +} + +/* + * Hardware interrupt masks + */ +#define splbio() splraise(IPL_BIO) +#define splnet() splraise(IPL_NET) +#define spltty() splraise(IPL_TTY) +#define splaudio() splraise(IPL_AUDIO) +#define splclock() splraise(IPL_CLOCK) +#define splstatclock() splclock() +#define splserial() splraise(IPL_SERIAL) +#define splipi() splraise(IPL_IPI) + +#define spllpt() spltty() + +#define spllpt() spltty() + +/* + * Software interrupt masks + * + * NOTE: spllowersoftclock() is used by hardclock() to lower the priority from + * clock to softclock before it calls softclock(). + */ +#define spllowersoftclock() spllower(IPL_SOFTCLOCK) + +#define splsoftclock() splraise(IPL_SOFTCLOCK) +#define splsoftnet() splraise(IPL_SOFTNET) +#define splsoftserial() splraise(IPL_SOFTSERIAL) + +/* + * Miscellaneous + */ +#define splimp() splraise(IPL_IMP) +#define splvm() splraise(IPL_IMP) +#define splhigh() splraise(IPL_HIGH) +#define spl0() spllower(IPL_NONE) +#define splsched() splraise(IPL_SCHED) +#define spllock() splhigh() +#define splx(x) spllower(x) + +/* SPL asserts */ +#ifdef DIAGNOSTIC +/* + * Although this function is implemented in MI code, it must be in this MD + * header because we don't want this header to include MI includes. + */ +void splassert_fail(int, int, const char *); +extern int splassert_ctl; +void splassert_check(int, const char *); +#define splassert(__wantipl) do { \ + if (__predict_false(splassert_ctl > 0)) { \ + splassert_check(__wantipl, __func__); \ + } \ +} while (0) +#else +#define splassert(wantipl) do { /* nada */ } while (0) +#endif + +/* + * Software interrupt registration + * + * We hand-code this to ensure that it's atomic. + * + * XXX always scheduled on the current CPU. + */ +static __inline void +softintr(int sir) +{ + struct cpu_info *ci = curcpu(); + + __asm __volatile("lock ; orl %1, %0" : + "=m"(ci->ci_ipending) : "ir" (1 << sir)); +} + +/* + * XXX + */ +#define setsoftnet() softintr(SIR_NET) + +#define IPLSHIFT 4 /* The upper nibble of vectors is the IPL. */ +#define IPL(level) ((level) >> IPLSHIFT) /* Extract the IPL. */ + +/* + * Stub declarations. + */ + +extern void Xsoftclock(void); +extern void Xsoftnet(void); +extern void Xsoftserial(void); + +extern struct intrstub i8259_stubs[]; +extern struct intrstub ioapic_edge_stubs[]; +extern struct intrstub ioapic_level_stubs[]; + +struct cpu_info; + +extern char idt_allocmap[]; + +void intr_default_setup(void); +int x86_nmi(void); +void intr_calculatemasks(struct cpu_info *); +int intr_allocate_slot_cpu(struct cpu_info *, struct pic *, int, int *); +int intr_allocate_slot(struct pic *, int, int, int, struct cpu_info **, int *, + int *); +void *intr_establish(int, struct pic *, int, int, int, int (*)(void *), void *); +void intr_disestablish(struct intrhand *); +void cpu_intr_init(struct cpu_info *); +int intr_find_mpmapping(int bus, int pin, int *handle); +void intr_printconfig(void); + +#ifdef MULTIPROCESSOR +int x86_send_ipi(struct cpu_info *, int); +void x86_broadcast_ipi(int); +void x86_multicast_ipi(int, int); +void x86_ipi_handler(void); +void x86_intlock(struct intrframe); +void x86_intunlock(struct intrframe); +void x86_softintlock(void); +void x86_softintunlock(void); + +extern void (*ipifunc[X86_NIPI])(struct cpu_info *); +#endif + +#endif /* !_LOCORE */ + +/* + * Generic software interrupt support. + */ + +#define X86_SOFTINTR_SOFTCLOCK 0 +#define X86_SOFTINTR_SOFTNET 1 +#define X86_SOFTINTR_SOFTSERIAL 2 +#define X86_NSOFTINTR 3 + +#ifndef _LOCORE +#include <sys/queue.h> + +struct x86_soft_intrhand { + TAILQ_ENTRY(x86_soft_intrhand) + sih_q; + struct x86_soft_intr *sih_intrhead; + void (*sih_fn)(void *); + void *sih_arg; + int sih_pending; +}; + +struct x86_soft_intr { + TAILQ_HEAD(, x86_soft_intrhand) + softintr_q; + int softintr_ssir; + struct simplelock softintr_slock; +}; + +#define x86_softintr_lock(si, s) \ +do { \ + (s) = splhigh(); \ + simple_lock(&si->softintr_slock); \ +} while (/*CONSTCOND*/ 0) + +#define x86_softintr_unlock(si, s) \ +do { \ + simple_unlock(&si->softintr_slock); \ + splx((s)); \ +} while (/*CONSTCOND*/ 0) + +void *softintr_establish(int, void (*)(void *), void *); +void softintr_disestablish(void *); +void softintr_init(void); +void softintr_dispatch(int); + +#define softintr_schedule(arg) \ +do { \ + struct x86_soft_intrhand *__sih = (arg); \ + struct x86_soft_intr *__si = __sih->sih_intrhead; \ + int __s; \ + \ + x86_softintr_lock(__si, __s); \ + if (__sih->sih_pending == 0) { \ + TAILQ_INSERT_TAIL(&__si->softintr_q, __sih, sih_q); \ + __sih->sih_pending = 1; \ + softintr(__si->softintr_ssir); \ + } \ + x86_softintr_unlock(__si, __s); \ +} while (/*CONSTCOND*/ 0) +#endif /* _LOCORE */ + +#endif /* !_X86_INTR_H_ */ diff --git a/sys/arch/amd64/include/intrdefs.h b/sys/arch/amd64/include/intrdefs.h new file mode 100644 index 00000000000..d1b46308c38 --- /dev/null +++ b/sys/arch/amd64/include/intrdefs.h @@ -0,0 +1,93 @@ +/* $OpenBSD: intrdefs.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: intrdefs.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */ + +#ifndef _i386_INTRDEFS_H +#define _i386_INTRDEFS_H + +/* + * Interrupt priority levels. + * + * There are tty, network and disk drivers that use free() at interrupt + * time, so imp > (tty | net | bio). + * + * Since run queues may be manipulated by both the statclock and tty, + * network, and disk drivers, clock > imp. + * + * IPL_HIGH must block everything that can manipulate a run queue. + * + * We need serial drivers to run at the absolute highest priority to + * avoid overruns, so serial > high. + * + * The level numbers are picked to fit into APIC vector priorities. + * + */ +#define IPL_NONE 0x0 /* nothing */ +#define IPL_SOFTCLOCK 0x4 /* timeouts */ +#define IPL_SOFTNET 0x5 /* protocol stacks */ +#define IPL_BIO 0x6 /* block I/O */ +#define IPL_NET 0x7 /* network */ +#define IPL_SOFTSERIAL 0x8 /* serial */ +#define IPL_TTY 0x9 /* terminal */ +#define IPL_VM 0xa /* memory allocation */ +#define IPL_IMP IPL_VM +#define IPL_AUDIO 0xb /* audio */ +#define IPL_CLOCK 0xc /* clock */ +#define IPL_SCHED IPL_CLOCK +#define IPL_STATCLOCK IPL_CLOCK +#define IPL_HIGH 0xd /* everything */ +#define IPL_SERIAL 0xd /* serial */ +#define IPL_IPI 0xe /* inter-processor interrupts */ +#define NIPL 16 + +/* Interrupt sharing types. */ +#define IST_NONE 0 /* none */ +#define IST_PULSE 1 /* pulsed */ +#define IST_EDGE 2 /* edge-triggered */ +#define IST_LEVEL 3 /* level-triggered */ + +/* + * Local APIC masks. Must not conflict with SIR_* above, and must + * be >= NUM_LEGACY_IRQs. Note that LIR_IPI must be first. + */ +#define LIR_IPI 31 +#define LIR_TIMER 30 + +/* Soft interrupt masks. */ +#define SIR_CLOCK 29 +#define SIR_NET 28 +#define SIR_SERIAL 27 + + +/* + * Maximum # of interrupt sources per CPU. 32 to fit in one word. + * ioapics can theoretically produce more, but it's not likely to + * happen. For multiple ioapics, things can be routed to different + * CPUs. + */ +#define MAX_INTR_SOURCES 32 +#define NUM_LEGACY_IRQS 16 + +/* + * Low and high boundaries between which interrupt gates will + * be allocated in the IDT. + */ +#define IDT_INTR_LOW (0x20 + NUM_LEGACY_IRQS) +#define IDT_INTR_HIGH 0xef + +#define X86_IPI_HALT 0x00000001 +#define X86_IPI_MICROSET 0x00000002 +#define X86_IPI_FLUSH_FPU 0x00000004 +#define X86_IPI_SYNCH_FPU 0x00000008 +#define X86_IPI_TLB 0x00000010 +#define X86_IPI_MTRR 0x00000020 +#define X86_IPI_GDT 0x00000040 + +#define X86_NIPI 7 + +#define X86_IPI_NAMES { "halt IPI", "timeset IPI", "FPU flush IPI", \ + "FPU synch IPI", "TLB shootdown IPI", \ + "MTRR update IPI", "GDT update IPI" } + +#define IREENT_MAGIC 0x18041969 + +#endif /* _X86_INTRDEFS_H */ diff --git a/sys/arch/amd64/include/isa_machdep.h b/sys/arch/amd64/include/isa_machdep.h new file mode 100644 index 00000000000..306eed9ef8e --- /dev/null +++ b/sys/arch/amd64/include/isa_machdep.h @@ -0,0 +1,237 @@ +/* $OpenBSD: isa_machdep.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: isa_machdep.h,v 1.2 2003/05/09 23:51:28 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1997, 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. + * + * 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) 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. + * + * @(#)isa.h 5.7 (Berkeley) 5/9/91 + */ + +/* + * Various pieces of the i386 port want to include this file without + * or in spite of using isavar.h, and should be fixed. + */ + +#ifndef _I386_ISA_MACHDEP_H_ /* XXX */ +#define _I386_ISA_MACHDEP_H_ /* XXX */ + +#include <machine/bus.h> +#include <dev/isa/isadmavar.h> + +/* + * XXX THIS FILE IS A MESS. copyright: berkeley's probably. + * contents from isavar.h and isareg.h, mostly the latter. + * perhaps charles's? + * + * copyright from berkeley's isa.h which is now dev/isa/isareg.h. + */ + +/* + * Types provided to machine-independent ISA code. + */ + +typedef void *isa_chipset_tag_t; + +struct device; /* XXX */ +struct isabus_attach_args; /* XXX */ + +/* + * Functions provided to machine-independent ISA code. + */ +void isa_attach_hook(struct device *, struct device *, + struct isabus_attach_args *); +int isa_intr_alloc(isa_chipset_tag_t, int, int, int *); +const struct evcnt *isa_intr_evcnt(isa_chipset_tag_t ic, int irq); +void *isa_intr_establish(isa_chipset_tag_t ic, int irq, int type, + int level, int (*ih_fun)(void *), void *ih_arg, char *); +void isa_intr_disestablish(isa_chipset_tag_t ic, void *handler); +int isa_mem_alloc(bus_space_tag_t, bus_size_t, bus_size_t, + bus_addr_t, int, bus_addr_t *, bus_space_handle_t *); +void isa_mem_free(bus_space_tag_t, bus_space_handle_t, bus_size_t); + +#define isa_dmainit(ic, bst, dmat, d) \ + _isa_dmainit(&(ic)->ic_dmastate, (bst), (dmat), (d)) +#define isa_dmacascade(ic, c) \ + _isa_dmacascade(&(ic)->ic_dmastate, (c)) +#define isa_dmamaxsize(ic, c) \ + _isa_dmamaxsize(&(ic)->ic_dmastate, (c)) +#define isa_dmamap_create(ic, c, s, f) \ + _isa_dmamap_create(&(ic)->ic_dmastate, (c), (s), (f)) +#define isa_dmamap_destroy(ic, c) \ + _isa_dmamap_destroy(&(ic)->ic_dmastate, (c)) +#define isa_dmastart(ic, c, a, n, p, f, bf) \ + _isa_dmastart(&(ic)->ic_dmastate, (c), (a), (n), (p), (f), (bf)) +#define isa_dmaabort(ic, c) \ + _isa_dmaabort(&(ic)->ic_dmastate, (c)) +#define isa_dmacount(ic, c) \ + _isa_dmacount(&(ic)->ic_dmastate, (c)) +#define isa_dmafinished(ic, c) \ + _isa_dmafinished(&(ic)->ic_dmastate, (c)) +#define isa_dmadone(ic, c) \ + _isa_dmadone(&(ic)->ic_dmastate, (c)) +#define isa_dmafreeze(ic) \ + _isa_dmafreeze(&(ic)->ic_dmastate) +#define isa_dmathaw(ic) \ + _isa_dmathaw(&(ic)->ic_dmastate) +#define isa_dmamem_alloc(ic, c, s, ap, f) \ + _isa_dmamem_alloc(&(ic)->ic_dmastate, (c), (s), (ap), (f)) +#define isa_dmamem_free(ic, c, a, s) \ + _isa_dmamem_free(&(ic)->ic_dmastate, (c), (a), (s)) +#define isa_dmamem_map(ic, c, a, s, kp, f) \ + _isa_dmamem_map(&(ic)->ic_dmastate, (c), (a), (s), (kp), (f)) +#define isa_dmamem_unmap(ic, c, k, s) \ + _isa_dmamem_unmap(&(ic)->ic_dmastate, (c), (k), (s)) +#define isa_dmamem_mmap(ic, c, a, s, o, p, f) \ + _isa_dmamem_mmap(&(ic)->ic_dmastate, (c), (a), (s), (o), (p), (f)) +#define isa_drq_alloc(ic, c) \ + _isa_drq_alloc(&(ic)->ic_dmastate, c) +#define isa_drq_free(ic, c) \ + _isa_drq_free(&(ic)->ic_dmastate, c) +#define isa_drq_isfree(ic, c) \ + _isa_drq_isfree(&(ic)->ic_dmastate, (c)) +#define isa_malloc(ic, c, s, p, f) \ + _isa_malloc(&(ic)->ic_dmastate, (c), (s), (p), (f)) +#define isa_free(a, p) \ + _isa_free((a), (p)) +#define isa_mappage(m, o, p) \ + _isa_mappage((m), (o), (p)) + +int isa_intr_check(isa_chipset_tag_t, int, int); + +/* + * for ACPI code + */ + +void isa_reinit_irq(void); + +/* + * ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED + * BY PORTABLE CODE. + */ + +extern struct x86_bus_dma_tag isa_bus_dma_tag; + +/* + * XXX Various seemingly PC-specific constants, some of which may be + * unnecessary anyway. + */ + +/* + * RAM Physical Address Space (ignoring the above mentioned "hole") + */ +#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */ +#define RAM_END 0x1000000 /* End of RAM Memory */ +#define RAM_SIZE (RAM_END - RAM_BEGIN) + +/* + * Oddball Physical Memory Addresses + */ +#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */ +#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */ +#define WEITEK_FPU 0xC0000000 /* WTL 2167 */ +#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */ + +/* + * stuff that used to be in pccons.c + */ +#define MONO_BASE 0x3B4 +#define MONO_BUF 0xB0000 +#define CGA_BASE 0x3D4 +#define CGA_BUF 0xB8000 + +/* + * Variables and macros to deal with the ISA I/O hole. + * XXX These should be converted to machine- and bus-mapping-independent + * function definitions, invoked through the softc. + */ + +extern u_long atdevbase; /* kernel virtual address of "hole" */ + +/* + * Given a kernel virtual address for some location + * in the "hole" I/O space, return a physical address. + */ +#define ISA_PHYSADDR(v) ((void *) ((u_long)(v) - atdevbase + IOM_BEGIN)) + +/* + * Given a physical address in the "hole", + * return a kernel virtual address. + */ +#define ISA_HOLE_VADDR(p) ((void *) ((u_long)(p) - IOM_BEGIN + atdevbase)) + + +/* + * Miscellanous functions. + */ +void sysbeep(int, int); /* beep with the system speaker */ + +#endif /* _I386_ISA_MACHDEP_H_ XXX */ diff --git a/sys/arch/amd64/include/kcore.h b/sys/arch/amd64/include/kcore.h new file mode 100644 index 00000000000..ddb4d1d7a85 --- /dev/null +++ b/sys/arch/amd64/include/kcore.h @@ -0,0 +1,49 @@ +/* $NetBSD: kcore.h,v 1.1 2003/04/26 18:39:43 fvdl Exp $ */ + +/* + * Copyright (c) 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. + */ + +/* + * Modified for NetBSD/i386 by Jason R. Thorpe, Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + * + * And once again modified for x86-64 by Frank van der Linden of + * Wasabi Systems, Inc. + */ + +#ifndef _AMD64KCORE_H_ +#define _AMD64_KCORE_H_ + +typedef struct cpu_kcore_hdr { + u_int64_t ptdpaddr; /* PA of PML4 */ + u_int64_t nmemsegs; /* Number of RAM segments */ +#if 0 + phys_ram_seg_t memsegs[]; /* RAM segments */ +#endif +} cpu_kcore_hdr_t; + +#endif /* _AMD64_KCORE_H_ */ diff --git a/sys/arch/amd64/include/limits.h b/sys/arch/amd64/include/limits.h new file mode 100644 index 00000000000..8cde663caa5 --- /dev/null +++ b/sys/arch/amd64/include/limits.h @@ -0,0 +1,57 @@ +/* $OpenBSD: limits.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/* + * Copyright (c) 1988 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. + * + * @(#)limits.h 7.2 (Berkeley) 6/28/90 + */ + +#ifndef _MACHINE_LIMITS_H_ +#define _MACHINE_LIMITS_H_ + +#define MB_LEN_MAX 1 /* no multibyte characters */ + +#if !defined(_ANSI_SOURCE) +#define SIZE_MAX ULONG_MAX /* max value for a size_t */ +#define SSIZE_MAX LONG_MAX /* max value for a ssize_t */ + +#if !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE) +#define SIZE_T_MAX ULONG_MAX /* max value for a size_t */ + +#define UQUAD_MAX 0xffffffffffffffffULL /* max unsigned quad */ +#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */ +#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */ + +#endif /* !_POSIX_C_SOURCE && !_XOPEN_SOURCE */ +#endif /* !_ANSI_SOURCE */ + +#endif /* _MACHINE_LIMITS_H_ */ diff --git a/sys/arch/amd64/include/loadfile_machdep.h b/sys/arch/amd64/include/loadfile_machdep.h new file mode 100644 index 00000000000..7de50b522ee --- /dev/null +++ b/sys/arch/amd64/include/loadfile_machdep.h @@ -0,0 +1,60 @@ +/* XXX - DSR */ +/* $OpenBSD: loadfile_machdep.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: loadfile_machdep.h,v 1.1 1999/04/29 03:17:12 tsubai Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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. + */ + +#define BOOT_ELF +#define ELFSIZE 64 + +#define LOAD_KERNEL (LOAD_ALL & ~LOAD_TEXTA) +#define COUNT_KERNEL (COUNT_ALL & ~COUNT_TEXTA) + +#define LOADADDR(a) ((((u_long)(a)) + offset)&0xfffffff) +#define ALIGNENTRY(a) ((u_long)(a)) +#define READ(f, b, c) read((f), (void *)LOADADDR(b), (c)) +#define BCOPY(s, d, c) memcpy((void *)LOADADDR(d), (void *)(s), (c)) +#define BZERO(d, c) memset((void *)LOADADDR(d), 0, (c)) +#define WARN(a) (void)(printf a, \ + printf((errno ? ": %s\n" : "\n"), \ + strerror(errno))) +#define PROGRESS(a) (void) printf a +#define ALLOC(a) alloc(a) +#define FREE(a, b) free(a, b) +#define OKMAGIC(a) ((a) == OMAGIC) + +void run_loadfile(u_long *, int); diff --git a/sys/arch/amd64/include/mcontext.h b/sys/arch/amd64/include/mcontext.h new file mode 100644 index 00000000000..ec1ed5f816c --- /dev/null +++ b/sys/arch/amd64/include/mcontext.h @@ -0,0 +1,108 @@ +/* $OpenBSD: mcontext.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: mcontext.h,v 1.1 2003/04/26 18:39:44 fvdl Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Klaus Klein. + * + * 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. + */ + +#ifndef _AMD64_MCONTEXT_H_ +#define _AMD64_MCONTEXT_H_ + +/* + * Layout of mcontext_t according to the System V Application Binary Interface, + * Intel386(tm) Architecture Processor Supplement, Fourth Edition. + */ + +/* + * General register state + */ +#define _NGREG 26 +typedef long __greg_t; +typedef __greg_t __gregset_t[_NGREG]; + +/* + * This is laid out to match trapframe and intrframe (see <machine/frame.h>). + * Hence, memcpy between gregs and a trapframe is possible. + */ +#define _REG_RDI 0 +#define _REG_RSI 1 +#define _REG_RDX 2 +#define _REG_RCX 3 +#define _REG_R8 4 +#define _REG_R9 5 +#define _REG_R10 6 +#define _REG_R11 7 +#define _REG_R12 8 +#define _REG_R13 9 +#define _REG_R14 10 +#define _REG_R15 11 +#define _REG_RBP 12 +#define _REG_RBX 13 +#define _REG_RAX 14 +#define _REG_GS 15 +#define _REG_FS 16 +#define _REG_ES 17 +#define _REG_DS 18 +#define _REG_TRAPNO 19 +#define _REG_ERR 20 +#define _REG_RIP 21 +#define _REG_CS 22 +#define _REG_RFL 23 +#define _REG_URSP 24 +#define _REG_SS 25 + +/* + * Floating point register state + */ +typedef char __fpregset_t[512]; + +/* + * The padding below is to make __fpregs have a 16-byte aligned offset + * within ucontext_t. + */ + +typedef struct { + __gregset_t __gregs; + long __pad; + __fpregset_t __fpregs; +} mcontext_t; + +#define _UC_UCONTEXT_ALIGN (~0xf) + +#ifdef _KERNEL +#define _UC_MACHINE_SP(uc) ((uc)->uc_mcontext.__gregs[_REG_URSP]) +#endif + +#endif /* !_AMD64_MCONTEXT_H_ */ diff --git a/sys/arch/amd64/include/mpbiosreg.h b/sys/arch/amd64/include/mpbiosreg.h new file mode 100644 index 00000000000..8041f5bb930 --- /dev/null +++ b/sys/arch/amd64/include/mpbiosreg.h @@ -0,0 +1,138 @@ +/* $OpenBSD: mpbiosreg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: mpbiosreg.h,v 1.3 2003/03/04 23:27:32 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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. + */ + +#ifndef _X86_MPBIOSREG_H_ +#define _X86_MPBIOSREG_H_ + +#define BIOS_BASE (0xf0000) +#define BIOS_SIZE (0x10000) +#define BIOS_COUNT (BIOS_SIZE) + +/* + * Multiprocessor config table entry types. + */ + +#define MPS_MCT_CPU 0 +#define MPS_MCT_BUS 1 +#define MPS_MCT_IOAPIC 2 +#define MPS_MCT_IOINT 3 +#define MPS_MCT_LINT 4 + +#define MPS_MCT_NTYPES 5 + +/* MP Floating Pointer Structure */ +struct mpbios_fps { + u_int32_t signature; +/* string defined by the Intel MP Spec as identifying the MP table */ +#define MP_FP_SIG 0x5f504d5f /* _MP_ */ + + u_int32_t pap; + u_int8_t length; + u_int8_t spec_rev; + u_int8_t checksum; + u_int8_t mpfb1; /* system configuration */ + u_int8_t mpfb2; /* flags */ +#define MPFPS_FLAG_IMCR 0x80 /* IMCR present */ + u_int8_t mpfb3; /* unused */ + u_int8_t mpfb4; /* unused */ + u_int8_t mpfb5; /* unused */ +}; + +/* MP Configuration Table Header */ +struct mpbios_cth { + u_int32_t signature; +#define MP_CT_SIG 0x504d4350 /* PCMP */ + + u_int16_t base_len; + u_int8_t spec_rev; + u_int8_t checksum; + u_int8_t oem_id[8]; + u_int8_t product_id[12]; + u_int32_t oem_table_pointer; + u_int16_t oem_table_size; + u_int16_t entry_count; + u_int32_t apic_address; + u_int16_t ext_len; + u_int8_t ext_cksum; + u_int8_t reserved; +}; + +struct mpbios_proc { + u_int8_t type; + u_int8_t apic_id; + u_int8_t apic_version; + u_int8_t cpu_flags; +#define PROCENTRY_FLAG_EN 0x01 +#define PROCENTRY_FLAG_BP 0x02 + u_int32_t cpu_signature; + u_int32_t feature_flags; + u_int32_t reserved1; + u_int32_t reserved2; +}; + +struct mpbios_bus { + u_int8_t type; + u_int8_t bus_id; + char bus_type[6]; +}; + +struct mpbios_ioapic { + u_int8_t type; + u_int8_t apic_id; + u_int8_t apic_version; + u_int8_t apic_flags; +#define IOAPICENTRY_FLAG_EN 0x01 + u_int32_t apic_address; +}; + +struct mpbios_int { + u_int8_t type; + u_int8_t int_type; + u_int16_t int_flags; + u_int8_t src_bus_id; + u_int8_t src_bus_irq; + u_int8_t dst_apic_id; +#define MPS_ALL_APICS 0xff + u_int8_t dst_apic_int; +}; + + +#endif /* !_X86_MPBIOSREG_H_ */ diff --git a/sys/arch/amd64/include/mpbiosvar.h b/sys/arch/amd64/include/mpbiosvar.h new file mode 100644 index 00000000000..b10bbe44fc7 --- /dev/null +++ b/sys/arch/amd64/include/mpbiosvar.h @@ -0,0 +1,62 @@ +/* $OpenBSD: mpbiosvar.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: mpbiosvar.h,v 1.2 2003/04/02 07:53:57 thorpej Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by RedBack Networks Inc. + * + * Author: Bill Sommerfeld + * + * 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. + */ + + +#ifndef _X86_MPBIOSVAR_H_ +#define _X86_MPBIOSVAR_H_ + +#define MP_TRAMPOLINE (2 * PAGE_SIZE) + +#if !defined(_LOCORE) + +#include <machine/mpbiosreg.h> +#include <machine/mpconfig.h> + +#if defined(_KERNEL) +void mpbios_scan(struct device *); +int mpbios_probe(struct device *); + +extern int mpbios_scanned; +#endif + +#endif + +#endif /* !_X86_MPBIOSVAR_H_ */ diff --git a/sys/arch/amd64/include/mpconfig.h b/sys/arch/amd64/include/mpconfig.h new file mode 100644 index 00000000000..7c12822824c --- /dev/null +++ b/sys/arch/amd64/include/mpconfig.h @@ -0,0 +1,65 @@ +/* $NetBSD: mpconfig.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ + +/* + * Definitions originally from the mpbios code, but now used for ACPI + * MP config as well. + */ + +#ifndef _X86_MPCONFIG_H +#define _X86_MPCONFIG_H + +/* + * Interrupt typess + */ +#define MPS_INTTYPE_INT 0 +#define MPS_INTTYPE_NMI 1 +#define MPS_INTTYPE_SMI 2 +#define MPS_INTTYPE_ExtINT 3 + +#define MPS_INTPO_DEF 0 +#define MPS_INTPO_ACTHI 1 +#define MPS_INTPO_ACTLO 3 + +#define MPS_INTTR_DEF 0 +#define MPS_INTTR_EDGE 1 +#define MPS_INTTR_LEVEL 3 + +#ifndef _LOCORE + +struct mpbios_int; + +struct mp_bus +{ + char *mb_name; /* XXX bus name */ + int mb_idx; /* XXX bus index */ + void (*mb_intr_print)(int); + void (*mb_intr_cfg)(const struct mpbios_int *, u_int32_t *); + struct mp_intr_map *mb_intrs; + u_int32_t mb_data; /* random bus-specific datum. */ +}; + +struct mp_intr_map +{ + struct mp_intr_map *next; + struct mp_bus *bus; + int bus_pin; + struct ioapic_softc *ioapic; + int ioapic_pin; + int ioapic_ih; /* int handle, for apic_intr_est */ + int type; /* from mp spec intr record */ + int flags; /* from mp spec intr record */ + u_int32_t redir; + int cpu_id; +}; + +#if defined(_KERNEL) +extern int mp_verbose; +extern struct mp_bus *mp_busses; +extern struct mp_intr_map *mp_intrs; +extern int mp_nintr; +extern int mp_isa_bus, mp_eisa_bus; +extern int mp_nbus; +#endif +#endif + +#endif /* _X86_MPCONFIG_H */ diff --git a/sys/arch/amd64/include/mtrr.h b/sys/arch/amd64/include/mtrr.h new file mode 100644 index 00000000000..ab17926ecf5 --- /dev/null +++ b/sys/arch/amd64/include/mtrr.h @@ -0,0 +1,160 @@ +/* $OpenBSD: mtrr.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: mtrr.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Bill Sommerfeld + * + * 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. + */ + +#ifndef _X86_MTRR_H_ +#define _X86_MTRR_H_ + +#define MTRR_I686_FIXED_IDX64K 0 +#define MTRR_I686_FIXED_IDX16K 1 +#define MTRR_I686_FIXED_IDX4K 3 + +#define MTRR_I686_NVAR 8 + +#define MTRR_I686_64K_START 0x00000 +#define MTRR_I686_16K_START 0x80000 +#define MTRR_I686_4K_START 0xc0000 + +#define MTRR_I686_NFIXED_64K 1 +#define MTRR_I686_NFIXED_16K 2 +#define MTRR_I686_NFIXED_4K 8 +#define MTRR_I686_NFIXED 11 +#define MTRR_I686_NFIXED_SOFT_64K (MTRR_I686_NFIXED_64K * 8) +#define MTRR_I686_NFIXED_SOFT_16K (MTRR_I686_NFIXED_16K * 8) +#define MTRR_I686_NFIXED_SOFT_4K (MTRR_I686_NFIXED_4K * 8) +#define MTRR_I686_NFIXED_SOFT (MTRR_I686_NFIXED * 8) + +#define MTRR_I686_ENABLE_MASK 0x0800 +#define MTRR_I686_FIXED_ENABLE_MASK 0x0400 + +#define MTRR_I686_CAP_VCNT_MASK 0x00ff +#define MTRR_I686_CAP_FIX_MASK 0x0100 +#define MTRR_I686_CAP_WC_MASK 0x0400 + +#define MTRR_TYPE_UC 0 +#define MTRR_TYPE_WC 1 +#define MTRR_TYPE_UNDEF1 2 +#define MTRR_TYPE_UNDEF2 3 +#define MTRR_TYPE_WT 4 +#define MTRR_TYPE_WP 5 +#define MTRR_TYPE_WB 6 + +struct mtrr_state { + uint32_t msraddr; + uint64_t msrval; +}; + +#define MTRR_PRIVATE 0x0001 /* 'own' range, reset at exit */ +#define MTRR_FIXED 0x0002 /* use fixed range mtrr */ +#define MTRR_VALID 0x0004 /* entry is valid */ + +#define MTRR_CANTSET MTRR_FIXED + +#define MTRR_I686_MASK_VALID (1 << 11) + +/* + * AMD K6 MTRRs. + * + * There are two of these MTRR-like registers in the UWCRR. + */ + +#define MTRR_K6_ADDR_SHIFT 17 +#define MTRR_K6_ADDR (0x7fffU << MTRR_K6_ADDR_SHIFT) +#define MTRR_K6_MASK_SHIFT 2 +#define MTRR_K6_MASK (0x7fffU << MTRR_K6_MASK_SHIFT) +#define MTRR_K6_WC (1U << 1) /* write-combine */ +#define MTRR_K6_UC (1U << 0) /* uncached */ + +#define MTRR_K6_NVAR 2 + +#ifdef _KERNEL + +#define mtrr_base_value(mtrrp) \ + (((uint64_t)(mtrrp)->base) | ((uint64_t)(mtrrp)->type)) +#define mtrr_mask_value(mtrrp) \ + ((~((mtrrp)->len - 1) & 0x0000000ffffff000)) + + +#define mtrr_len(val) \ + ((~((val) & 0x0000000ffffff000)+1) & 0x0000000ffffff000) +#define mtrr_base(val) ((val) & 0x0000000ffffff000) +#define mtrr_type(val) ((uint8_t)((val) & 0x00000000000000ff)) +#define mtrr_valid(val) (((val) & MTRR_I686_MASK_VALID) != 0) + +struct proc; +struct mtrr; + +void i686_mtrr_init_first(void); +void k6_mtrr_init_first(void); + +struct mtrr_funcs { + void (*init_cpu)(struct cpu_info *ci); + void (*reload_cpu)(struct cpu_info *ci); + void (*clean)(struct proc *p); + int (*set)(struct mtrr *, int *n, struct proc *p, int flags); + int (*get)(struct mtrr *, int *n, struct proc *p, int flags); + void (*commit)(void); + void (*dump)(const char *tag); +}; + +extern struct mtrr_funcs i686_mtrr_funcs; +extern struct mtrr_funcs k6_mtrr_funcs; +extern struct mtrr_funcs *mtrr_funcs; + +#define mtrr_init_cpu(ci) mtrr_funcs->init_cpu(ci) +#define mtrr_reload_cpu(ci) mtrr_funcs->reload_cpu(ci) +#define mtrr_clean(p) mtrr_funcs->clean(p) +#define mtrr_set(mp,n,p,f) mtrr_funcs->set(mp,n,p,f) +#define mtrr_get(mp,n,p,f) mtrr_funcs->get(mp,n,p,f) +#define mtrr_dump(s) mtrr_funcs->dump(s) +#define mtrr_commit() mtrr_funcs->commit() + +#define MTRR_GETSET_USER 0x0001 +#define MTRR_GETSET_KERNEL 0x0002 + +#endif /* _KERNEL */ + +struct mtrr { + uint64_t base; /* physical base address */ + uint64_t len; + uint8_t type; + int flags; + pid_t owner; /* valid if MTRR_PRIVATE set in flags */ +}; + +#endif /* _X86_MTRR_H_ */ diff --git a/sys/arch/amd64/include/param.h b/sys/arch/amd64/include/param.h new file mode 100644 index 00000000000..7e3f512977f --- /dev/null +++ b/sys/arch/amd64/include/param.h @@ -0,0 +1,173 @@ +/* $OpenBSD: param.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)param.h 5.8 (Berkeley) 6/28/91 + */ + +#ifdef _KERNEL +#ifdef _LOCORE +#include <machine/psl.h> +#else +#include <machine/cpu.h> +#endif +#endif + +#define _MACHINE amd64 +#define MACHINE "amd64" +#define _MACHINE_ARCH x86_64 +#define MACHINE_ARCH "x86_64" +#define MID_MACHINE MID_X86_64 + +/* + * Round p (pointer or byte index) up to a correctly-aligned value + * for all data types (int, long, ...). The result is u_long and + * must be cast to any desired pointer type. + * + * ALIGNED_POINTER is a boolean macro that checks whether an address + * is valid to fetch data elements of type t from on this architecture. + * This does not reflect the optimal alignment, just the possibility + * (within reasonable limits). + * + */ +#define ALIGNBYTES (sizeof(long) - 1) +#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ALIGNBYTES) +#define ALIGNED_POINTER(p,t) 1 + +#define PGSHIFT 12 /* LOG2(NBPG) */ +#define NBPG (1 << PGSHIFT) /* bytes/page */ +#define PGOFSET (NBPG-1) /* byte offset into page */ + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (PAGE_SIZE - 1) + +#define NPTEPG (NBPG/(sizeof (pt_entry_t))) + +#define KERNBASE 0xffffffff80000000 /* start of kernel virtual space */ +#define KERNTEXTOFF (KERNBASE+0x100000) /* start of kernel text */ +#define BTOPKERNBASE ((u_long)KERNBASE >> PGSHIFT) + +#define KERNTEXTOFF_HI 0xffffffff +#define KERNTEXTOFF_LO 0x80100000 + +#define KERNBASE_HI 0xffffffff +#define KERNBASE_LO 0x80000000 + +#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */ +#define DEV_BSIZE (1 << DEV_BSHIFT) +#define BLKDEV_IOSIZE 2048 +#ifndef MAXPHYS +#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */ +#endif + +#define SSIZE 1 /* initial stack size/NBPG */ +#define SINCR 1 /* increment of stack/NBPG */ +#define UPAGES 5 /* pages of u-area */ +#define USPACE (UPAGES * NBPG) /* total size of u-area */ + +#ifndef MSGBUFSIZE +#define MSGBUFSIZE 4*NBPG /* default message buffer size */ +#endif + +/* + * Constants related to network buffer management. + * MCLBYTES must be no larger than NBPG (the software page size), and, + * on machines that exchange pages of input or output buffers with mbuf + * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple + * of the hardware page size. + */ +#define MSIZE 256 /* size of an mbuf */ +#define MCLSHIFT 11 /* convert bytes to m_buf clusters */ +#define MCLBYTES (1 << MCLSHIFT) /* size of a m_buf cluster */ +#define MCLOFSET (MCLBYTES - 1) /* offset within a m_buf cluster */ + +#ifndef NMBCLUSTERS +#define NMBCLUSTERS 2048 /* map size, max cluster allocation */ +#endif + +/* + * Minimum and maximum sizes of the kernel malloc arena in PAGE_SIZE-sized + * logical pages. + */ +#define NKMEMPAGES_MIN_DEFAULT ((8 * 1024 * 1024) >> PAGE_SHIFT) +#define NKMEMPAGES_MAX_DEFAULT ((128 * 1024 * 1024) >> PAGE_SHIFT) + +/* pages ("clicks") to disk blocks */ +#define ctod(x) ((x) << (PGSHIFT - DEV_BSHIFT)) +#define dtoc(x) ((x) >> (PGSHIFT - DEV_BSHIFT)) + +/* bytes to pages */ +#define ctob(x) ((x) << PGSHIFT) +#define btoc(x) (((x) + PGOFSET) >> PGSHIFT) + +/* bytes to disk blocks */ +#define dbtob(x) ((x) << DEV_BSHIFT) +#define btodb(x) ((x) >> DEV_BSHIFT) + +/* + * Map a ``block device block'' to a file system block. + * This should be device dependent, and should use the bsize + * field from the disk label. + * For now though just use DEV_BSIZE. + */ +#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE / DEV_BSIZE)) + +/* + * XXXfvdl the PD* stuff is different from i386. + */ +/* + * Mach derived conversion macros + */ +#define x86_round_pdr(x) \ + ((((unsigned long)(x)) + (NBPD_L2 - 1)) & ~(NBPD_L2 - 1)) +#define x86_trunc_pdr(x) ((unsigned long)(x) & ~(NBPD_L2 - 1)) +#define x86_btod(x) ((unsigned long)(x) >> L2_SHIFT) +#define x86_dtob(x) ((unsigned long)(x) << L2_SHIFT) +#define x86_round_page(x) ((((unsigned long)(x)) + PGOFSET) & ~PGOFSET) +#define x86_trunc_page(x) ((unsigned long)(x) & ~PGOFSET) +#define x86_btop(x) ((unsigned long)(x) >> PGSHIFT) +#define x86_ptob(x) ((unsigned long)(x) << PGSHIFT) + +#define btop(x) x86_btop(x) +#define ptob(x) x86_ptob(x) +#define round_pdr(x) x86_round_pdr(x) + +/* XXX - oh, the horror.. Just for now. */ +#define KERNEL_PROC_LOCK(p) +#define KERNEL_PROC_UNLOCK(p) +#define KERNEL_LOCK(i) +#define KERNEL_UNLOCK() diff --git a/sys/arch/amd64/include/pcb.h b/sys/arch/amd64/include/pcb.h new file mode 100644 index 00000000000..af95ea5aa9b --- /dev/null +++ b/sys/arch/amd64/include/pcb.h @@ -0,0 +1,130 @@ +/* $NetBSD: pcb.h,v 1.1 2003/04/26 18:39:45 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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) 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. + * + * @(#)pcb.h 5.10 (Berkeley) 5/12/91 + */ + +/* + * XXXfvdl these copyrights don't really match anymore + */ + +#ifndef _AMD64_PCB_H_ +#define _AMD64_PCB_H_ + +#include <sys/signal.h> + +#include <machine/segments.h> +#include <machine/tss.h> +#include <machine/fpu.h> +#include <machine/sysarch.h> + +#define NIOPORTS 1024 /* # of ports we allow to be mapped */ + +/* + * Please note that the pcb_savefpu field in struct below must be + * on a 16-byte boundary. + */ +struct pcb { + /* + * XXXfvdl + * It's overkill to have a TSS here, as it's only needed + * for compatibility processes who use an I/O permission map. + * The pcb fields below are not in the TSS anymore (and there's + * not enough room in the TSS to store them all) + * Should just make this a pointer and allocate. + */ + struct x86_64_tss pcb_tss; + u_int64_t pcb_cr3; + u_int64_t pcb_rsp; + u_int64_t pcb_rbp; + u_int64_t pcb_usersp; + u_int64_t pcb_ldt_sel; + struct savefpu pcb_savefpu; /* floating point state */ + int pcb_cr0; /* saved image of CR0 */ + int pcb_flags; +#define PCB_USER_LDT 0x01 /* has user-set LDT */ + caddr_t pcb_onfault; /* copyin/out fault recovery */ + struct cpu_info *pcb_fpcpu; /* cpu holding our fp state. */ + unsigned pcb_iomap[NIOPORTS/32]; /* I/O bitmap */ + struct pmap *pcb_pmap; /* back pointer to our pmap */ +}; + +/* + * The pcb is augmented with machine-dependent additional data for + * core dumps. For the i386, there is nothing to add. + */ +struct md_coredump { + long md_pad[8]; +}; + +#endif /* _AMD64_PCB_H_ */ diff --git a/sys/arch/amd64/include/pci_machdep.h b/sys/arch/amd64/include/pci_machdep.h new file mode 100644 index 00000000000..e7852418297 --- /dev/null +++ b/sys/arch/amd64/include/pci_machdep.h @@ -0,0 +1,110 @@ +/* $OpenBSD: pci_machdep.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pci_machdep.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ + +/* + * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1994 Charles M. Hannum. 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +/* + * Machine-specific definitions for PCI autoconfiguration. + */ + +/* + * i386-specific PCI structure and type definitions. + * NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE. + * + * Configuration tag; created from a {bus,device,function} triplet by + * pci_make_tag(), and passed to pci_conf_read() and pci_conf_write(). + * We could instead always pass the {bus,device,function} triplet to + * the read and write routines, but this would cause extra overhead. + * + * Mode 2 is historical and deprecated by the Revision 2.0 specification. + */ +union x86_pci_tag_u { + u_int32_t mode1; + struct { + u_int16_t port; + u_int8_t enable; + u_int8_t forward; + } mode2; +}; + +extern struct x86_bus_dma_tag pci_bus_dma_tag; + +/* + * Types provided to machine-independent PCI code + */ +typedef void *pci_chipset_tag_t; +typedef union x86_pci_tag_u pcitag_t; +typedef int pci_intr_handle_t; + +/* + * i386-specific PCI variables and functions. + * NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE. + */ +extern int pci_mode; +int pci_mode_detect(void); +int pci_bus_flags(void); +struct pci_attach_args; + +/* + * Functions provided to machine-independent PCI code. + */ +void pci_attach_hook(struct device *, struct device *, + struct pcibus_attach_args *); +int pci_bus_maxdevs(pci_chipset_tag_t, int); +pcitag_t pci_make_tag(pci_chipset_tag_t, int, int, int); +void pci_decompose_tag(pci_chipset_tag_t, pcitag_t, + int *, int *, int *); +pcireg_t pci_conf_read(pci_chipset_tag_t, pcitag_t, int); +void pci_conf_write(pci_chipset_tag_t, pcitag_t, int, + pcireg_t); +int pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); +const char *pci_intr_string(pci_chipset_tag_t, pci_intr_handle_t); +const struct evcnt *pci_intr_evcnt(pci_chipset_tag_t, pci_intr_handle_t); +void *pci_intr_establish(pci_chipset_tag_t, pci_intr_handle_t, + int, int (*)(void *), void *, char *); +void pci_intr_disestablish(pci_chipset_tag_t, void *); +void pci_decompose_tag(pci_chipset_tag_t, pcitag_t, + int *, int *, int *); + +#define pci_enumerate_bus(sc, m, p) \ + pci_enumerate_bus_generic((sc), (m), (p)) + +/* + * ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED + * BY PORTABLE CODE. + */ + +/* + * Section 6.2.4, `Miscellaneous Functions' of the PCI Specification, + * says that 255 means `unknown' or `no connection' to the interrupt + * controller on a PC. + */ +#define X86_PCI_INTERRUPT_LINE_NO_CONNECTION 0xff diff --git a/sys/arch/amd64/include/pic.h b/sys/arch/amd64/include/pic.h new file mode 100644 index 00000000000..c9d9a5082a6 --- /dev/null +++ b/sys/arch/amd64/include/pic.h @@ -0,0 +1,40 @@ +/* $OpenBSD: pic.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pic.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ + +#ifndef _X86_PIC_H +#define _X86_PIC_H + +#include <sys/device.h> +#include <sys/lock.h> + +struct cpu_info; + +/* + * Structure common to all PIC softcs + */ +struct pic { + struct device pic_dev; + int pic_type; + simple_lock_t pic_lock; + void (*pic_hwmask)(struct pic *, int); + void (*pic_hwunmask)(struct pic *, int); + void (*pic_addroute)(struct pic *, struct cpu_info *, int, int, int); + void (*pic_delroute)(struct pic *, struct cpu_info *, int, int, int); + struct intrstub *pic_level_stubs; + struct intrstub *pic_edge_stubs; +}; + +#define pic_name pic_dev.dv_xname + +/* + * PIC types. + */ +#define PIC_I8259 0 +#define PIC_IOAPIC 1 +#define PIC_LAPIC 2 +#define PIC_SOFT 3 + +extern struct pic i8259_pic; +extern struct pic local_pic; +extern struct pic softintr_pic; +#endif diff --git a/sys/arch/amd64/include/pio.h b/sys/arch/amd64/include/pio.h new file mode 100644 index 00000000000..9d54de16fc5 --- /dev/null +++ b/sys/arch/amd64/include/pio.h @@ -0,0 +1,232 @@ +/* $OpenBSD: pio.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pio.h,v 1.2 2003/02/27 11:22:46 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +#ifndef _X86_PIO_H_ +#define _X86_PIO_H_ + +/* + * Functions to provide access to x86 programmed I/O instructions. + * + * The in[bwl]() and out[bwl]() functions are split into two varieties: one to + * use a small, constant, 8-bit port number, and another to use a large or + * variable port number. The former can be compiled as a smaller instruction. + */ + + +#ifdef __OPTIMIZE__ + +#define __use_immediate_port(port) \ + (__builtin_constant_p((port)) && (port) < 0x100) + +#else + +#define __use_immediate_port(port) 0 + +#endif + + +#define inb(port) \ + (/* CONSTCOND */ __use_immediate_port(port) ? __inbc(port) : __inb(port)) + +static __inline u_int8_t +__inbc(unsigned port) +{ + u_int8_t data; + __asm __volatile("inb %w1,%0" : "=a" (data) : "id" (port)); + return data; +} + +static __inline u_int8_t +__inb(unsigned port) +{ + u_int8_t data; + __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insb(unsigned port, void *addr, int cnt) +{ + void *dummy1; + int dummy2; + __asm __volatile("cld\n\trepne\n\tinsb" : + "=D" (dummy1), "=c" (dummy2) : + "d" (port), "0" (addr), "1" (cnt) : + "memory"); +} + +#define inw(port) \ + (/* CONSTCOND */ __use_immediate_port(port) ? __inwc(port) : __inw(port)) + +static __inline u_int16_t +__inwc(unsigned port) +{ + u_int16_t data; + __asm __volatile("inw %w1,%0" : "=a" (data) : "id" (port)); + return data; +} + +static __inline u_int16_t +__inw(unsigned port) +{ + u_int16_t data; + __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insw(unsigned port, void *addr, int cnt) +{ + void *dummy1; + int dummy2; + __asm __volatile("cld\n\trepne\n\tinsw" : + "=D" (dummy1), "=c" (dummy2) : + "d" (port), "0" (addr), "1" (cnt) : + "memory"); +} + +#define inl(port) \ + (/* CONSTCOND */ __use_immediate_port(port) ? __inlc(port) : __inl(port)) + +static __inline u_int32_t +__inlc(unsigned port) +{ + u_int32_t data; + __asm __volatile("inl %w1,%0" : "=a" (data) : "id" (port)); + return data; +} + +static __inline u_int32_t +__inl(unsigned port) +{ + u_int32_t data; + __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insl(unsigned port, void *addr, int cnt) +{ + void *dummy1; + int dummy2; + __asm __volatile("cld\n\trepne\n\tinsl" : + "=D" (dummy1), "=c" (dummy2) : + "d" (port), "0" (addr), "1" (cnt) : + "memory"); +} + +#define outb(port, data) \ + (/* CONSTCOND */__use_immediate_port(port) ? __outbc(port, data) : \ + __outb(port, data)) + +static __inline void +__outbc(unsigned port, u_int8_t data) +{ + __asm __volatile("outb %0,%w1" : : "a" (data), "id" (port)); +} + +static __inline void +__outb(unsigned port, u_int8_t data) +{ + __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsb(unsigned port, const void *addr, int cnt) +{ + void *dummy1; + int dummy2; + __asm __volatile("cld\n\trepne\n\toutsb" : + "=S" (dummy1), "=c" (dummy2) : + "d" (port), "0" (addr), "1" (cnt)); +} + +#define outw(port, data) \ + (/* CONSTCOND */ __use_immediate_port(port) ? __outwc(port, data) : \ + __outw(port, data)) + +static __inline void +__outwc(unsigned port, u_int16_t data) +{ + __asm __volatile("outw %0,%w1" : : "a" (data), "id" (port)); +} + +static __inline void +__outw(unsigned port, u_int16_t data) +{ + __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsw(unsigned port, const void *addr, int cnt) +{ + void *dummy1; + int dummy2; + __asm __volatile("cld\n\trepne\n\toutsw" : + "=S" (dummy1), "=c" (dummy2) : + "d" (port), "0" (addr), "1" (cnt)); +} + +#define outl(port, data) \ + (/* CONSTCOND */ __use_immediate_port(port) ? __outlc(port, data) : \ + __outl(port, data)) + +static __inline void +__outlc(unsigned port, u_int32_t data) +{ + __asm __volatile("outl %0,%w1" : : "a" (data), "id" (port)); +} + +static __inline void +__outl(unsigned port, u_int32_t data) +{ + __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsl(unsigned port, const void *addr, int cnt) +{ + void *dummy1; + int dummy2; + __asm __volatile("cld\n\trepne\n\toutsl" : + "=S" (dummy1), "=c" (dummy2) : + "d" (port), "0" (addr), "1" (cnt)); +} + +#endif /* _X86_PIO_H_ */ diff --git a/sys/arch/amd64/include/pmap.h b/sys/arch/amd64/include/pmap.h new file mode 100644 index 00000000000..a9366187930 --- /dev/null +++ b/sys/arch/amd64/include/pmap.h @@ -0,0 +1,592 @@ +/* $OpenBSD: pmap.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pmap.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */ + +/* + * + * Copyright (c) 1997 Charles D. Cranor and Washington University. + * 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 acknowledgment: + * This product includes software developed by Charles D. Cranor and + * Washington University. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +/* + * pmap.h: see pmap.c for the history of this pmap module. + */ + +#ifndef _AMD64_PMAP_H_ +#define _AMD64_PMAP_H_ + +#ifndef _LOCORE +#include <machine/cpufunc.h> +#include <machine/pte.h> +#include <machine/segments.h> +#include <uvm/uvm_object.h> +#endif + +/* + * The x86_64 pmap module closely resembles the i386 one. It uses + * the same recursive entry scheme, and the same alternate area + * trick for accessing non-current pmaps. See the i386 pmap.h + * for a description. The obvious difference is that 3 extra + * levels of page table need to be dealt with. The level 1 page + * table pages are at: + * + * l1: 0x00007f8000000000 - 0x00007fffffffffff (39 bits, needs PML4 entry) + * + * The alternate space is at: + * + * l1: 0xffffff8000000000 - 0xffffffffffffffff (39 bits, needs PML4 entry) + * + * The rest is kept as physical pages in 3 UVM objects, and is + * temporarily mapped for virtual access when needed. + * + * Note that address space is signed, so the layout for 48 bits is: + * + * +---------------------------------+ 0xffffffffffffffff + * | | + * | alt.L1 table (PTE pages) | + * | | + * +---------------------------------+ 0xffffff8000000000 + * ~ ~ + * | | + * | Kernel Space | + * | | + * | | + * +---------------------------------+ 0xffff800000000000 = 0x0000008000000000 + * | | + * | alt.L1 table (PTE pages) | + * | | + * +---------------------------------+ 0x00007f8000000000 + * ~ ~ + * | | + * | User Space | + * | | + * | | + * +---------------------------------+ 0x0000000000000000 + * + * In other words, there is a 'VA hole' at 0x0000008000000000 - + * 0xffff800000000000 which will trap, just as on, for example, + * sparcv9. + * + * The unused space can be used if needed, but it adds a little more + * complexity to the calculations. + */ + +/* + * The first generation of Hammer processors can use 48 bits of + * virtual memory, and 40 bits of physical memory. This will be + * more for later generations. These defines can be changed to + * variable names containing the # of bits, extracted from an + * extended cpuid instruction (variables are harder to use during + * bootstrap, though) + */ +#define VIRT_BITS 48 +#define PHYS_BITS 40 + +/* + * Mask to get rid of the sign-extended part of addresses. + */ +#define VA_SIGN_MASK 0xffff000000000000 +#define VA_SIGN_NEG(va) ((va) | VA_SIGN_MASK) +/* + * XXXfvdl this one's not right. + */ +#define VA_SIGN_POS(va) ((va) & ~VA_SIGN_MASK) + +#define L4_SLOT_PTE 255 +#define L4_SLOT_KERN 256 +#define L4_SLOT_KERNBASE 511 +#define L4_SLOT_APTE 510 + +#define PDIR_SLOT_KERN L4_SLOT_KERN +#define PDIR_SLOT_PTE L4_SLOT_PTE +#define PDIR_SLOT_APTE L4_SLOT_APTE + +/* + * the following defines give the virtual addresses of various MMU + * data structures: + * PTE_BASE and APTE_BASE: the base VA of the linear PTE mappings + * PTD_BASE and APTD_BASE: the base VA of the recursive mapping of the PTD + * PDP_PDE and APDP_PDE: the VA of the PDE that points back to the PDP/APDP + * + */ + +#define PTE_BASE ((pt_entry_t *) (L4_SLOT_PTE * NBPD_L4)) +#define APTE_BASE ((pt_entry_t *) (VA_SIGN_NEG((L4_SLOT_APTE * NBPD_L4)))) + +#define L1_BASE PTE_BASE +#define AL1_BASE APTE_BASE + +#define L2_BASE ((pd_entry_t *)((char *)L1_BASE + L4_SLOT_PTE * NBPD_L3)) +#define L3_BASE ((pd_entry_t *)((char *)L2_BASE + L4_SLOT_PTE * NBPD_L2)) +#define L4_BASE ((pd_entry_t *)((char *)L3_BASE + L4_SLOT_PTE * NBPD_L1)) + +#define AL2_BASE ((pd_entry_t *)((char *)AL1_BASE + L4_SLOT_PTE * NBPD_L3)) +#define AL3_BASE ((pd_entry_t *)((char *)AL2_BASE + L4_SLOT_PTE * NBPD_L2)) +#define AL4_BASE ((pd_entry_t *)((char *)AL3_BASE + L4_SLOT_PTE * NBPD_L1)) + +#define PDP_PDE (L4_BASE + PDIR_SLOT_PTE) +#define APDP_PDE (L4_BASE + PDIR_SLOT_APTE) + +#define PDP_BASE L4_BASE +#define APDP_BASE AL4_BASE + +#define NKL4_MAX_ENTRIES (unsigned long)1 +#define NKL3_MAX_ENTRIES (unsigned long)(NKL4_MAX_ENTRIES * 512) +#define NKL2_MAX_ENTRIES (unsigned long)(NKL3_MAX_ENTRIES * 512) +#define NKL1_MAX_ENTRIES (unsigned long)(NKL2_MAX_ENTRIES * 512) + +#define NKL4_KIMG_ENTRIES 1 +#define NKL3_KIMG_ENTRIES 1 +#define NKL2_KIMG_ENTRIES 8 + +/* + * Since kva space is below the kernel in its entirety, we start off + * with zero entries on each level. + */ +#define NKL4_START_ENTRIES 0 +#define NKL3_START_ENTRIES 0 +#define NKL2_START_ENTRIES 0 +#define NKL1_START_ENTRIES 0 /* XXX */ + +#define NTOPLEVEL_PDES (PAGE_SIZE / (sizeof (pd_entry_t))) + +#define KERNSPACE (NKL4_ENTRIES * NBPD_L4) + +#define NPDPG (PAGE_SIZE / sizeof (pd_entry_t)) + +#define ptei(VA) (((VA_SIGN_POS(VA)) & L1_MASK) >> L1_SHIFT) + +/* + * pl*_pi: index in the ptp page for a pde mapping a VA. + * (pl*_i below is the index in the virtual array of all pdes per level) + */ +#define pl1_pi(VA) (((VA_SIGN_POS(VA)) & L1_MASK) >> L1_SHIFT) +#define pl2_pi(VA) (((VA_SIGN_POS(VA)) & L2_MASK) >> L2_SHIFT) +#define pl3_pi(VA) (((VA_SIGN_POS(VA)) & L3_MASK) >> L3_SHIFT) +#define pl4_pi(VA) (((VA_SIGN_POS(VA)) & L4_MASK) >> L4_SHIFT) + +/* + * pl*_i: generate index into pde/pte arrays in virtual space + */ +#define pl1_i(VA) (((VA_SIGN_POS(VA)) & L1_FRAME) >> L1_SHIFT) +#define pl2_i(VA) (((VA_SIGN_POS(VA)) & L2_FRAME) >> L2_SHIFT) +#define pl3_i(VA) (((VA_SIGN_POS(VA)) & L3_FRAME) >> L3_SHIFT) +#define pl4_i(VA) (((VA_SIGN_POS(VA)) & L4_FRAME) >> L4_SHIFT) +#define pl_i(va, lvl) \ + (((VA_SIGN_POS(va)) & ptp_masks[(lvl)-1]) >> ptp_shifts[(lvl)-1]) + +#define PTP_MASK_INITIALIZER { L1_FRAME, L2_FRAME, L3_FRAME, L4_FRAME } +#define PTP_SHIFT_INITIALIZER { L1_SHIFT, L2_SHIFT, L3_SHIFT, L4_SHIFT } +#define NKPTP_INITIALIZER { NKL1_START_ENTRIES, NKL2_START_ENTRIES, \ + NKL3_START_ENTRIES, NKL4_START_ENTRIES } +#define NKPTPMAX_INITIALIZER { NKL1_MAX_ENTRIES, NKL2_MAX_ENTRIES, \ + NKL3_MAX_ENTRIES, NKL4_MAX_ENTRIES } +#define NBPD_INITIALIZER { NBPD_L1, NBPD_L2, NBPD_L3, NBPD_L4 } +#define PDES_INITIALIZER { L2_BASE, L3_BASE, L4_BASE } +#define APDES_INITIALIZER { AL2_BASE, AL3_BASE, AL4_BASE } + +/* + * PTP macros: + * a PTP's index is the PD index of the PDE that points to it + * a PTP's offset is the byte-offset in the PTE space that this PTP is at + * a PTP's VA is the first VA mapped by that PTP + * + * note that PAGE_SIZE == number of bytes in a PTP (4096 bytes == 1024 entries) + * NBPD == number of bytes a PTP can map (4MB) + */ + +#define ptp_va2o(va, lvl) (pl_i(va, (lvl)+1) * PAGE_SIZE) + +#define PTP_LEVELS 4 + +/* + * PG_AVAIL usage: we make use of the ignored bits of the PTE + */ + +#define PG_W PG_AVAIL1 /* "wired" mapping */ +#define PG_PVLIST PG_AVAIL2 /* mapping has entry on pvlist */ +/* PG_AVAIL3 not used */ + +/* + * Number of PTE's per cache line. 8 byte pte, 64-byte cache line + * Used to avoid false sharing of cache lines. + */ +#define NPTECL 8 + + +#if defined(_KERNEL) && !defined(_LOCORE) +/* + * pmap data structures: see pmap.c for details of locking. + */ + +struct pmap; +typedef struct pmap *pmap_t; + +/* + * we maintain a list of all non-kernel pmaps + */ + +LIST_HEAD(pmap_head, pmap); /* struct pmap_head: head of a pmap list */ + +/* + * the pmap structure + * + * note that the pm_obj contains the simple_lock, the reference count, + * page list, and number of PTPs within the pmap. + * + * pm_lock is the same as the spinlock for vm object 0. Changes to + * the other objects may only be made if that lock has been taken + * (the other object locks are only used when uvm_pagealloc is called) + */ + +struct pmap { + struct uvm_object pm_obj[PTP_LEVELS-1]; /* objects for lvl >= 1) */ +#define pm_lock pm_obj[0].vmobjlock +#define pm_obj_l1 pm_obj[0] +#define pm_obj_l2 pm_obj[1] +#define pm_obj_l3 pm_obj[2] + LIST_ENTRY(pmap) pm_list; /* list (lck by pm_list lock) */ + pd_entry_t *pm_pdir; /* VA of PD (lck by object lock) */ + paddr_t pm_pdirpa; /* PA of PD (read-only after create) */ + struct vm_page *pm_ptphint[PTP_LEVELS-1]; + /* pointer to a PTP in our pmap */ + struct pmap_statistics pm_stats; /* pmap stats (lck by object lock) */ + + int pm_flags; /* see below */ + + union descriptor *pm_ldt; /* user-set LDT */ + int pm_ldt_len; /* number of LDT entries */ + int pm_ldt_sel; /* LDT selector */ + u_int32_t pm_cpus; /* mask of CPUs using pmap */ +}; + +/* pm_flags */ +#define PMF_USER_LDT 0x01 /* pmap has user-set LDT */ + +/* + * for each managed physical page we maintain a list of <PMAP,VA>'s + * which it is mapped at. the list is headed by a pv_head structure. + * there is one pv_head per managed phys page (allocated at boot time). + * the pv_head structure points to a list of pv_entry structures (each + * describes one mapping). + */ + +struct pv_entry; + +struct pv_head { + struct simplelock pvh_lock; /* locks every pv on this list */ + struct pv_entry *pvh_list; /* head of list (locked by pvh_lock) */ +}; + +struct pv_entry { /* locked by its list's pvh_lock */ + struct pv_entry *pv_next; /* next entry */ + struct pmap *pv_pmap; /* the pmap */ + vaddr_t pv_va; /* the virtual address */ + struct vm_page *pv_ptp; /* the vm_page of the PTP */ +}; + +/* + * pv_entrys are dynamically allocated in chunks from a single page. + * we keep track of how many pv_entrys are in use for each page and + * we can free pv_entry pages if needed. there is one lock for the + * entire allocation system. + */ + +struct pv_page_info { + TAILQ_ENTRY(pv_page) pvpi_list; + struct pv_entry *pvpi_pvfree; + int pvpi_nfree; +}; + +/* + * number of pv_entry's in a pv_page + * (note: won't work on systems where NPBG isn't a constant) + */ + +#define PVE_PER_PVPAGE ((PAGE_SIZE - sizeof(struct pv_page_info)) / \ + sizeof(struct pv_entry)) + +/* + * a pv_page: where pv_entrys are allocated from + */ + +struct pv_page { + struct pv_page_info pvinfo; + struct pv_entry pvents[PVE_PER_PVPAGE]; +}; + +/* + * pmap_remove_record: a record of VAs that have been unmapped, used to + * flush TLB. if we have more than PMAP_RR_MAX then we stop recording. + */ + +#define PMAP_RR_MAX 16 /* max of 16 pages (64K) */ + +struct pmap_remove_record { + int prr_npages; + vaddr_t prr_vas[PMAP_RR_MAX]; +}; + +/* + * global kernel variables + */ + +/* PTDpaddr: is the physical address of the kernel's PDP */ +extern u_long PTDpaddr; + +extern struct pmap kernel_pmap_store; /* kernel pmap */ +extern int pmap_pg_g; /* do we support PG_G? */ + +extern paddr_t ptp_masks[]; +extern int ptp_shifts[]; +extern long nkptp[], nbpd[], nkptpmax[]; +extern pd_entry_t *pdes[]; + +/* + * macros + */ + +#define pmap_kernel() (&kernel_pmap_store) +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) +#define pmap_update(pmap) /* nothing (yet) */ + +#define pmap_clear_modify(pg) pmap_clear_attrs(pg, PG_M) +#define pmap_clear_reference(pg) pmap_clear_attrs(pg, PG_U) +#define pmap_copy(DP,SP,D,L,S) +#define pmap_is_modified(pg) pmap_test_attrs(pg, PG_M) +#define pmap_is_referenced(pg) pmap_test_attrs(pg, PG_U) +#define pmap_move(DP,SP,D,L,S) +#define pmap_phys_address(ppn) ptob(ppn) +#define pmap_valid_entry(E) ((E) & PG_V) /* is PDE or PTE valid? */ + + +/* + * prototypes + */ + +void pmap_bootstrap(vaddr_t); +boolean_t pmap_clear_attrs(struct vm_page *, unsigned); +static void pmap_page_protect(struct vm_page *, vm_prot_t); +void pmap_page_remove (struct vm_page *); +static void pmap_protect(struct pmap *, vaddr_t, + vaddr_t, vm_prot_t); +void pmap_remove(struct pmap *, vaddr_t, vaddr_t); +boolean_t pmap_test_attrs(struct vm_page *, unsigned); +static void pmap_update_pg(vaddr_t); +static void pmap_update_2pg(vaddr_t,vaddr_t); +void pmap_write_protect(struct pmap *, vaddr_t, + vaddr_t, vm_prot_t); + +vaddr_t reserve_dumppages(vaddr_t); /* XXX: not a pmap fn */ + +void pmap_tlb_shootdown(pmap_t, vaddr_t, pt_entry_t, int32_t *); +void pmap_tlb_shootnow(int32_t); +void pmap_do_tlb_shootdown(struct cpu_info *); +void pmap_prealloc_lowmem_ptps(void); + +#define PMAP_GROWKERNEL /* turn on pmap_growkernel interface */ + +/* + * Do idle page zero'ing uncached to avoid polluting the cache. + */ +boolean_t pmap_pageidlezero(struct vm_page *); +#define PMAP_PAGEIDLEZERO(pg) pmap_pageidlezero((pg)) + +/* + * inline functions + */ + +static __inline void +pmap_remove_all(struct pmap *pmap) +{ + /* Nothing. */ +} + +/* + * pmap_update_pg: flush one page from the TLB (or flush the whole thing + * if hardware doesn't support one-page flushing) + */ + +__inline static void +pmap_update_pg(va) + vaddr_t va; +{ + invlpg(va); +} + +/* + * pmap_update_2pg: flush two pages from the TLB + */ + +__inline static void +pmap_update_2pg(va, vb) + vaddr_t va, vb; +{ + invlpg(va); + invlpg(vb); +} + +/* + * pmap_page_protect: change the protection of all recorded mappings + * of a managed page + * + * => this function is a frontend for pmap_page_remove/pmap_clear_attrs + * => we only have to worry about making the page more protected. + * unprotecting a page is done on-demand at fault time. + */ + +__inline static void +pmap_page_protect(struct vm_page *pg, vm_prot_t prot) +{ + if ((prot & VM_PROT_WRITE) == 0) { + if (prot & (VM_PROT_READ|VM_PROT_EXECUTE)) { + (void) pmap_clear_attrs(pg, PG_RW); + } else { + pmap_page_remove(pg); + } + } +} + +/* + * pmap_protect: change the protection of pages in a pmap + * + * => this function is a frontend for pmap_remove/pmap_write_protect + * => we only have to worry about making the page more protected. + * unprotecting a page is done on-demand at fault time. + */ + +__inline static void +pmap_protect(pmap, sva, eva, prot) + struct pmap *pmap; + vaddr_t sva, eva; + vm_prot_t prot; +{ + if ((prot & VM_PROT_WRITE) == 0) { + if (prot & (VM_PROT_READ|VM_PROT_EXECUTE)) { + pmap_write_protect(pmap, sva, eva, prot); + } else { + pmap_remove(pmap, sva, eva); + } + } +} + +/* + * various address inlines + * + * vtopte: return a pointer to the PTE mapping a VA, works only for + * user and PT addresses + * + * kvtopte: return a pointer to the PTE mapping a kernel VA + */ + +#include <lib/libkern/libkern.h> + +static __inline pt_entry_t * +vtopte(vaddr_t va) +{ + + KASSERT(va < (L4_SLOT_KERN * NBPD_L4)); + + return (PTE_BASE + pl1_i(va)); +} + +static __inline pt_entry_t * +kvtopte(vaddr_t va) +{ + + KASSERT(va >= (L4_SLOT_KERN * NBPD_L4)); + +#ifdef LARGEPAGES + { + pd_entry_t *pde; + + pde = L1_BASE + pl2_i(va); + if (*pde & PG_PS) + return ((pt_entry_t *)pde); + } +#endif + + return (PTE_BASE + pl1_i(va)); +} + +#define pmap_pte_set(p, n) x86_atomic_testset_u64(p, n) +#define pmap_pte_clearbits(p, b) x86_atomic_clearbits_u64(p, b) +#define pmap_cpu_has_pg_n() (1) +#define pmap_cpu_has_invlpg (1) + +paddr_t vtophys(vaddr_t); +vaddr_t pmap_map(vaddr_t, paddr_t, paddr_t, vm_prot_t); + +#if 0 /* XXXfvdl was USER_LDT, need to check if that can be supported */ +void pmap_ldt_cleanup(struct proc *); +#define PMAP_FORK +#endif /* USER_LDT */ + +/* + * Hooks for the pool allocator. + */ +/* #define POOL_VTOPHYS(va) vtophys((vaddr_t) (va)) */ + +#endif /* _KERNEL && !_LOCORE */ +#endif /* _AMD64_PMAP_H_ */ diff --git a/sys/arch/amd64/include/proc.h b/sys/arch/amd64/include/proc.h new file mode 100644 index 00000000000..89e8360b954 --- /dev/null +++ b/sys/arch/amd64/include/proc.h @@ -0,0 +1,63 @@ +/* $OpenBSD: proc.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: proc.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */ + +/* + * Copyright (c) 1991 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. + * + * @(#)proc.h 7.1 (Berkeley) 5/15/91 + */ + +#ifndef _AMD64_PROC_H +#define _AMD64_PROC_H + +#include <machine/frame.h> + +/* + * Machine-dependent part of the proc structure for amd64. + */ +struct mdproc { + struct trapframe *md_regs; /* registers on current frame */ + int md_tss_sel; /* TSS selector */ + int md_flags; + /* Syscall handling function */ + void (*md_syscall)(struct trapframe); + __volatile int md_astpending; +}; + +/* md_flags */ +#define MDP_USEDFPU 0x0001 /* has used the FPU */ +#define MDP_COMPAT 0x0002 /* x86 compatibility process */ +#define MDP_SYSCALL 0x0004 /* entered kernel via syscall ins */ +#define MDP_USEDMTRR 0x0008 /* has set volatile MTRRs */ +#define MDP_IRET 0x0010 /* return via iret, not sysret */ + +#endif /* _AMD64_PROC_H */ diff --git a/sys/arch/amd64/include/profile.h b/sys/arch/amd64/include/profile.h new file mode 100644 index 00000000000..5d928249a31 --- /dev/null +++ b/sys/arch/amd64/include/profile.h @@ -0,0 +1,65 @@ +/* $OpenBSD: profile.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: profile.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */ + +/* + * Copyright (c) 1992, 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. + * + * @(#)profile.h 8.1 (Berkeley) 6/11/93 + */ + +#define _MCOUNT_DECL static __inline void _mcount + +#define MCOUNT_ENTRY "mcount" + +/* + * XXXfvdl this is screwed by -fomit-frame-pointer being included in + * -O. + */ +#define MCOUNT \ +extern void mcount __P((void)) __asm__(MCOUNT_ENTRY); \ +void \ +mcount() \ +{ \ + _mcount((u_long)__builtin_return_address(1), \ + (u_long)__builtin_return_address(0)); \ +} + + +#ifdef _KERNEL +/* + * Note that we assume splhigh() and splx() cannot call mcount() + * recursively. + */ +#define MCOUNT_ENTER s = splhigh() +#define MCOUNT_EXIT splx(s) +#endif /* _KERNEL */ + diff --git a/sys/arch/amd64/include/psl.h b/sys/arch/amd64/include/psl.h new file mode 100644 index 00000000000..689c507c487 --- /dev/null +++ b/sys/arch/amd64/include/psl.h @@ -0,0 +1,87 @@ +/* $OpenBSD: psl.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: psl.h,v 1.1 2003/02/26 21:26:11 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)psl.h 5.2 (Berkeley) 1/18/91 + */ + +#ifndef _X86_PSL_H_ +#define _X86_PSL_H_ + +/* + * 386 processor status longword. + */ +#define PSL_C 0x00000001 /* carry flag */ +#define PSL_PF 0x00000004 /* parity flag */ +#define PSL_AF 0x00000010 /* auxiliary carry flag */ +#define PSL_Z 0x00000040 /* zero flag */ +#define PSL_N 0x00000080 /* sign flag */ +#define PSL_T 0x00000100 /* trap flag */ +#define PSL_I 0x00000200 /* interrupt enable flag */ +#define PSL_D 0x00000400 /* direction flag */ +#define PSL_V 0x00000800 /* overflow flag */ +#define PSL_IOPL 0x00003000 /* i/o privilege level */ +#define PSL_NT 0x00004000 /* nested task */ +#define PSL_RF 0x00010000 /* resume flag */ +#define PSL_VM 0x00020000 /* virtual 8086 mode */ +#define PSL_AC 0x00040000 /* alignment check flag */ +#define PSL_VIF 0x00080000 /* virtual interrupt enable flag */ +#define PSL_VIP 0x00100000 /* virtual interrupt pending flag */ +#define PSL_ID 0x00200000 /* identification flag */ + +#define PSL_MBO 0x00000002 /* must be one bits */ +#define PSL_MBZ 0xffc08028 /* must be zero bits */ + +#define PSL_USERSET (PSL_MBO | PSL_I) +#if defined(_KERNEL_OPT) +#include "opt_vm86.h" +#endif +#ifdef VM86 +#define PSL_USERSTATIC (PSL_MBO | PSL_MBZ | PSL_I | PSL_IOPL | PSL_NT | PSL_VIF | PSL_VIP) +#else +#define PSL_USERSTATIC (PSL_MBO | PSL_MBZ | PSL_I | PSL_IOPL | PSL_NT | PSL_VM | PSL_VIF | PSL_VIP) +#endif +#define PSL_USER (PSL_C | PSL_MBO | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_V) + +/* + * ??? + */ +#ifdef _KERNEL +#include <machine/intr.h> +#endif + +#endif /* !_X86_PSL_H_ */ diff --git a/sys/arch/amd64/include/pte.h b/sys/arch/amd64/include/pte.h new file mode 100644 index 00000000000..eaa883d3f6f --- /dev/null +++ b/sys/arch/amd64/include/pte.h @@ -0,0 +1,137 @@ +/* $OpenBSD: pte.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pte.h,v 1.1 2003/04/26 18:39:47 fvdl Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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 _AMD64_PTE_H_ +#define _AMD64_PTE_H_ + +/* + * amd64 MMU hardware structure: + * + * the (first generation) amd64 MMU is a 4-level MMU which maps 2^48 bytes + * of virtual memory. The pagesize we use is is 4K (4096 [0x1000] bytes), + * although 2M and 4M can be used as well. The indexes in the levels + * are 9 bits wide (512 64bit entries per level), dividing the bits + * 9-9-9-9-12. + * + * The top level table, called PML4, contains 512 64bit entries pointing + * to 3rd level table. The 3rd level table is called the 'page directory + * pointers directory' and has 512 entries pointing to page directories. + * The 2nd level is the page directory, containing 512 pointers to + * page table pages. Lastly, level 1 consists of pages containing 512 + * PTEs. + * + * Simply put, levels 4-1 all consist of pages containing 512 + * entries pointing to the next level. Level 0 is the actual PTEs + * themselves. + * + * For a description on the other bits, which are i386 compatible, + * see the i386 pte.h + */ + +#if !defined(_LOCORE) + +/* + * here we define the data types for PDEs and PTEs + */ + +typedef u_int64_t pd_entry_t; /* PDE */ +typedef u_int64_t pt_entry_t; /* PTE */ + +#endif + +/* + * now we define various for playing with virtual addresses + */ + +#define L1_SHIFT 12 +#define L2_SHIFT 21 +#define L3_SHIFT 30 +#define L4_SHIFT 39 +#define NBPD_L1 (1ULL << L1_SHIFT) /* # bytes mapped by L1 ent (4K) */ +#define NBPD_L2 (1ULL << L2_SHIFT) /* # bytes mapped by L2 ent (2MB) */ +#define NBPD_L3 (1ULL << L3_SHIFT) /* # bytes mapped by L3 ent (1G) */ +#define NBPD_L4 (1ULL << L4_SHIFT) /* # bytes mapped by L4 ent (512G) */ + +#define L4_MASK 0x0000ff8000000000 +#define L3_MASK 0x0000007fc0000000 +#define L2_MASK 0x000000003fe00000 +#define L1_MASK 0x00000000001ff000 + +#define L4_FRAME L4_MASK +#define L3_FRAME (L4_FRAME|L3_MASK) +#define L2_FRAME (L3_FRAME|L2_MASK) +#define L1_FRAME (L2_FRAME|L1_MASK) + +/* + * PDE/PTE bits. These are no different from their i386 counterparts. + */ + +#define PG_V 0x0000000000000001 /* valid */ +#define PG_RO 0x0000000000000000 /* read-only */ +#define PG_RW 0x0000000000000002 /* read-write */ +#define PG_u 0x0000000000000004 /* user accessible */ +#define PG_PROT 0x0000000000000006 +#define PG_N 0x0000000000000018 /* non-cacheable */ +#define PG_U 0x0000000000000020 /* used */ +#define PG_M 0x0000000000000040 /* modified */ +#define PG_PS 0x0000000000000080 /* 2MB page size */ +#define PG_G 0x0000000000000100 /* not flushed */ +#define PG_AVAIL1 0x0000000000000200 +#define PG_AVAIL2 0x0000000000000400 +#define PG_AVAIL3 0x0000000000000800 +#define PG_NX 0x8000000000000000 /* non-executable */ +#define PG_FRAME 0xfffffffffffff000 + +#define PG_LGFRAME 0xffffffffffc00000 /* large (2M) page frame mask */ + +/* + * short forms of protection codes + */ + +#define PG_KR 0x0000000000000000 /* kernel read-only */ +#define PG_KW 0x0000000000000002 /* kernel read-write */ + +/* + * page protection exception bits + */ + +#define PGEX_P 0x01 /* protection violation (vs. no mapping) */ +#define PGEX_W 0x02 /* exception during a write cycle */ +#define PGEX_U 0x04 /* exception while in user mode (upl) */ + +#endif /* _AMD64_PTE_H_ */ diff --git a/sys/arch/amd64/include/ptrace.h b/sys/arch/amd64/include/ptrace.h new file mode 100644 index 00000000000..27c0bf29c1d --- /dev/null +++ b/sys/arch/amd64/include/ptrace.h @@ -0,0 +1,41 @@ +/* $OpenBSD: ptrace.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: ptrace.h,v 1.1 2003/04/26 18:39:47 fvdl Exp $ */ + +/* + * Copyright (c) 1993 Christopher G. Demetriou + * 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 Christopher G. Demetriou. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +/* + * i386-dependent ptrace definitions + */ +#define PT_STEP (PT_FIRSTMACH + 0) +#define PT_GETREGS (PT_FIRSTMACH + 1) +#define PT_SETREGS (PT_FIRSTMACH + 2) +#define PT_GETFPREGS (PT_FIRSTMACH + 3) +#define PT_SETFPREGS (PT_FIRSTMACH + 4) diff --git a/sys/arch/amd64/include/reg.h b/sys/arch/amd64/include/reg.h new file mode 100644 index 00000000000..f594a44c6fc --- /dev/null +++ b/sys/arch/amd64/include/reg.h @@ -0,0 +1,102 @@ +/* $OpenBSD: reg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: reg.h,v 1.1 2003/04/26 18:39:47 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)reg.h 5.5 (Berkeley) 1/18/91 + */ + +#ifndef _AMD64_REG_H_ +#define _AMD64_REG_H_ + +#include <machine/mcontext.h> +#include <machine/fpu.h> + +/* + * XXX + * The #defines aren't used in the kernel, but some user-level code still + * expects them. + */ + +/* When referenced during a trap/exception, registers are at these offsets */ + +#define tR15 0 +#define tR14 1 +#define tR13 2 +#define tR12 3 +#define tR11 4 +#define tR10 5 +#define tR9 6 +#define tR8 7 +#define tRDI 8 +#define tRSI 9 +#define tRBP 10 +#define tRBX 11 +#define tRDX 12 +#define tRCX 13 +#define tRAX 14 + +#define tRIP 17 +#define tCS 18 +#define tRFLAGS 19 +#define tRSP 20 +#define tSS 21 + +/* + * Registers accessible to ptrace(2) syscall for debugger use. + * Same as mcontext.__gregs and struct trapframe, they must + * remain synced (XXX should use common structure). + */ +struct reg { + long regs[_NGREG]; +}; + +struct fpreg { + struct fxsave64 fxstate; +}; + +#define fp_fcw fxstate.fx_fcw +#define fp_fsw fxstate.fx_fsw +#define fp_ftw fxstate.fx_ftw +#define fp_fop fxstate.fx_fop +#define fp_rip fxstate.fx_rip +#define fp_rdp fxstate.fx_rdp +#define fp_mxcsr fxstate.fx_mxcsr +#define fp_mxcsr_mask fxstate.fx_mxcsr_mask +#define fp_st fxstate.fx_st +#define fp_xmm fxstate.fx_xmm + +#endif /* !_AMD64_REG_H_ */ diff --git a/sys/arch/amd64/include/segments.h b/sys/arch/amd64/include/segments.h new file mode 100644 index 00000000000..636f3a38fee --- /dev/null +++ b/sys/arch/amd64/include/segments.h @@ -0,0 +1,305 @@ +/* $OpenBSD: segments.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: segments.h,v 1.1 2003/04/26 18:39:47 fvdl Exp $ */ + +/*- + * Copyright (c) 1995, 1997 + * Charles M. Hannum. All rights reserved. + * Copyright (c) 1989, 1990 William F. Jolitz + * Copyright (c) 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. + * + * @(#)segments.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Adapted for NetBSD/amd64 by fvdl@wasabisystems.com. + */ + +/* + * 386 Segmentation Data Structures and definitions + * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989 + */ + +#ifndef _AMD64_SEGMENTS_H_ +#define _AMD64_SEGMENTS_H_ + +/* + * Selectors + */ + +#define ISPL(s) ((s) & SEL_RPL) /* what is the priority level of a selector */ +#define SEL_KPL 0 /* kernel privilege level */ +#define SEL_UPL 3 /* user privilege level */ +#define SEL_RPL 3 /* requester's privilege level mask */ +#define ISLDT(s) ((s) & SEL_LDT) /* is it local or global */ +#define SEL_LDT 4 /* local descriptor table */ + +/* Dynamically allocated TSSs and LDTs start (byte offset) */ +#define SYSSEL_START (NGDT_MEM << 3) +#define DYNSEL_START (SYSSEL_START + (NGDT_SYS << 4)) + +/* + * These define the index not from the start of the GDT, but from + * the part of the GDT that they're allocated from. + * First NGDT_MEM entries are 8-byte descriptors for CS and DS. + * Next NGDT_SYS entries are 16-byte descriptors defining LDTs. + * + * The rest is 16-byte descriptors for TSS and LDT. + */ + +#define IDXSEL(s) (((s) >> 3) & 0x1fff) +#define IDXDYNSEL(s) ((((s) & ~SEL_RPL) - DYNSEL_START) >> 4) + +#define GSEL(s,r) (((s) << 3) | r) +#define GSYSSEL(s,r) ((((s) << 4) + SYSSEL_START) | r) +#define GDYNSEL(s,r) ((((s) << 4) + DYNSEL_START) | r | SEL_KPL) + +#define LSEL(s,r) ((s) | r | SEL_LDT) + +#define USERMODE(c, f) (ISPL(c) == SEL_UPL) +#define KERNELMODE(c, f) (ISPL(c) == SEL_KPL) + +#ifndef _LOCORE + +/* + * Memory and System segment descriptors + */ + +/* + * Below is used for TSS and LDT. + */ +struct sys_segment_descriptor { +/*BITFIELDTYPE*/ u_int64_t sd_lolimit:16;/* segment extent (lsb) */ +/*BITFIELDTYPE*/ u_int64_t sd_lobase:24;/* segment base address (lsb) */ +/*BITFIELDTYPE*/ u_int64_t sd_type:5; /* segment type */ +/*BITFIELDTYPE*/ u_int64_t sd_dpl:2; /* segment descriptor priority level */ +/*BITFIELDTYPE*/ u_int64_t sd_p:1; /* segment descriptor present */ +/*BITFIELDTYPE*/ u_int64_t sd_hilimit:4;/* segment extent (msb) */ +/*BITFIELDTYPE*/ u_int64_t sd_xx1:3; /* avl, long and def32 (not used) */ +/*BITFIELDTYPE*/ u_int64_t sd_gran:1; /* limit granularity (byte/page) */ +/*BITFIELDTYPE*/ u_int64_t sd_hibase:40;/* segment base address (msb) */ +/*BITFIELDTYPE*/ u_int64_t sd_xx2:8; /* reserved */ +/*BITFIELDTYPE*/ u_int64_t sd_zero:5; /* must be zero */ +/*BITFIELDTYPE*/ u_int64_t sd_xx3:19; /* reserved */ +} __attribute__((packed)); + +/* + * Below is used for cs, ds, etc. + */ +struct mem_segment_descriptor { + unsigned sd_lolimit:16; /* segment extent (lsb) */ + unsigned sd_lobase:24; /* segment base address (lsb) */ + unsigned sd_type:5; /* segment type */ + unsigned sd_dpl:2; /* segment descriptor priority level */ + unsigned sd_p:1; /* segment descriptor present */ + unsigned sd_hilimit:4; /* segment extent (msb) */ + unsigned sd_avl:1; /* available */ + unsigned sd_long:1; /* long mode */ + unsigned sd_def32:1; /* default 32 vs 16 bit size */ + unsigned sd_gran:1; /* limit granularity (byte/page) */ + unsigned sd_hibase:8; /* segment base address (msb) */ +} __attribute__((packed)); + +/* + * Gate descriptors (e.g. indirect descriptors) + */ +struct gate_descriptor { +/*BITFIELDTYPE*/ u_int64_t gd_looffset:16;/* gate offset (lsb) */ +/*BITFIELDTYPE*/ u_int64_t gd_selector:16;/* gate segment selector */ +/*BITFIELDTYPE*/ u_int64_t gd_ist:3; /* IST select */ +/*BITFIELDTYPE*/ u_int64_t gd_xx1:5; /* reserved */ +/*BITFIELDTYPE*/ u_int64_t gd_type:5; /* segment type */ +/*BITFIELDTYPE*/ u_int64_t gd_dpl:2; /* segment descriptor priority level */ +/*BITFIELDTYPE*/ u_int64_t gd_p:1; /* segment descriptor present */ +/*BITFIELDTYPE*/ u_int64_t gd_hioffset:48;/* gate offset (msb) */ +/*BITFIELDTYPE*/ u_int64_t gd_xx2:8; /* reserved */ +/*BITFIELDTYPE*/ u_int64_t gd_zero:5; /* must be zero */ +/*BITFIELDTYPE*/ u_int64_t gd_xx3:19; /* reserved */ +} __attribute__((packed)); + +/* + * region descriptors, used to load gdt/idt tables before segments yet exist. + */ +struct region_descriptor { + u_int16_t rd_limit; /* segment extent */ + u_int64_t rd_base; /* base address */ +} __attribute__((packed)); + +#ifdef _KERNEL +#if 0 +extern struct sys_segment_descriptor *ldt; +#endif +extern struct gate_descriptor *idt; +extern char *gdtstore; +extern char *ldtstore; + +void setgate(struct gate_descriptor *, void *, int, int, int, int); +void unsetgate(struct gate_descriptor *); +void setregion(struct region_descriptor *, void *, u_int16_t); +void set_sys_segment(struct sys_segment_descriptor *, void *, size_t, + int, int, int); +void set_mem_segment(struct mem_segment_descriptor *, void *, size_t, + int, int, int, int, int); +int idt_vec_alloc(int, int); +void idt_vec_set(int, void (*)(void)); +void idt_vec_free(int); +void cpu_init_idt(void); + +#endif /* _KERNEL */ + +#endif /* !_LOCORE */ + +/* system segments and gate types */ +#define SDT_SYSNULL 0 /* system null */ +#define SDT_SYS286TSS 1 /* system 286 TSS available */ +#define SDT_SYSLDT 2 /* system local descriptor table */ +#define SDT_SYS286BSY 3 /* system 286 TSS busy */ +#define SDT_SYS286CGT 4 /* system 286 call gate */ +#define SDT_SYSTASKGT 5 /* system task gate */ +#define SDT_SYS286IGT 6 /* system 286 interrupt gate */ +#define SDT_SYS286TGT 7 /* system 286 trap gate */ +#define SDT_SYSNULL2 8 /* system null again */ +#define SDT_SYS386TSS 9 /* system 386 TSS available */ +#define SDT_SYSNULL3 10 /* system null again */ +#define SDT_SYS386BSY 11 /* system 386 TSS busy */ +#define SDT_SYS386CGT 12 /* system 386 call gate */ +#define SDT_SYSNULL4 13 /* system null again */ +#define SDT_SYS386IGT 14 /* system 386 interrupt gate */ +#define SDT_SYS386TGT 15 /* system 386 trap gate */ + +/* memory segment types */ +#define SDT_MEMRO 16 /* memory read only */ +#define SDT_MEMROA 17 /* memory read only accessed */ +#define SDT_MEMRW 18 /* memory read write */ +#define SDT_MEMRWA 19 /* memory read write accessed */ +#define SDT_MEMROD 20 /* memory read only expand dwn limit */ +#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */ +#define SDT_MEMRWD 22 /* memory read write expand dwn limit */ +#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */ +#define SDT_MEME 24 /* memory execute only */ +#define SDT_MEMEA 25 /* memory execute only accessed */ +#define SDT_MEMER 26 /* memory execute read */ +#define SDT_MEMERA 27 /* memory execute read accessed */ +#define SDT_MEMEC 28 /* memory execute only conforming */ +#define SDT_MEMEAC 29 /* memory execute only accessed conforming */ +#define SDT_MEMERC 30 /* memory execute read conforming */ +#define SDT_MEMERAC 31 /* memory execute read accessed conforming */ + +/* is memory segment descriptor pointer ? */ +#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && \ + (s->d_type) <= SDT_MEMERAC) + +/* is 286 gate descriptor pointer ? */ +#define IS286GDP(s) ((s->d_type) >= SDT_SYS286CGT && \ + (s->d_type) < SDT_SYS286TGT) + +/* is 386 gate descriptor pointer ? */ +#define IS386GDP(s) ((s->d_type) >= SDT_SYS386CGT && \ + (s->d_type) < SDT_SYS386TGT) + +/* is gate descriptor pointer ? */ +#define ISGDP(s) (IS286GDP(s) || IS386GDP(s)) + +/* is segment descriptor pointer ? */ +#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s)) + +/* is system segment descriptor pointer ? */ +#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s)) + +/* + * Segment Protection Exception code bits + */ +#define SEGEX_EXT 0x01 /* recursive or externally induced */ +#define SEGEX_IDT 0x02 /* interrupt descriptor table */ +#define SEGEX_TI 0x04 /* local descriptor table */ + +/* + * Entries in the Interrupt Descriptor Table (IDT) + */ +#define NIDT 256 +#define NRSVIDT 32 /* reserved entries for cpu exceptions */ + +/* + * Entries in the Global Descriptor Table (GDT) + * The code and data descriptors must come first. There + * are NGDT_MEM of them. + * + * Then come the predefined LDT (and possibly TSS) descriptors. + * There are NGDT_SYS of them. + */ +#define GNULL_SEL 0 /* Null descriptor */ +#define GCODE_SEL 1 /* Kernel code descriptor */ +#define GDATA_SEL 2 /* Kernel data descriptor */ +#define GUCODE_SEL 3 /* User code descriptor */ +#define GUDATA_SEL 4 /* User data descriptor */ +#define GAPM32CODE_SEL 5 +#define GAPM16CODE_SEL 6 +#define GAPMDATA_SEL 7 +#define GBIOSCODE_SEL 8 +#define GBIOSDATA_SEL 9 +#define GPNPBIOSCODE_SEL 10 +#define GPNPBIOSDATA_SEL 11 +#define GPNPBIOSSCRATCH_SEL 12 +#define GPNPBIOSTRAMP_SEL 13 +#define GUCODE32_SEL 14 +#define GUDATA32_SEL 15 +#define NGDT_MEM 16 + +#define GLDT_SEL 0 /* Default LDT descriptor */ +#define NGDT_SYS 1 + +#define GDT_SYS_OFFSET (NGDT_MEM << 3) + +#define GDT_ADDR_MEM(s,i) \ + ((struct mem_segment_descriptor *)((s) + ((i) << 3))) +#define GDT_ADDR_SYS(s,i) \ + ((struct sys_segment_descriptor *)((s) + (((i) << 4) + SYSSEL_START))) + +/* + * Byte offsets in the Local Descriptor Table (LDT) + * Strange order because of syscall/sysret insns + */ +#define LSYS5CALLS_SEL 0 /* iBCS system call gate */ +#define LUCODE32_SEL 8 /* 32 bit user code descriptor */ +#define LUDATA_SEL 16 /* User data descriptor */ +#define LUCODE_SEL 24 /* User code descriptor */ +#define LSOL26CALLS_SEL 32 /* Solaris 2.6 system call gate */ +#define LUDATA32_SEL 56 /* 32 bit user data descriptor (needed?)*/ +#define LBSDICALLS_SEL 128 /* BSDI system call gate */ + +#define LDT_SIZE 144 + +#define LSYSRETBASE_SEL LUCODE32_SEL + +#endif /* _AMD64_SEGMENTS_H_ */ diff --git a/sys/arch/amd64/include/setjmp.h b/sys/arch/amd64/include/setjmp.h new file mode 100644 index 00000000000..01d6066450f --- /dev/null +++ b/sys/arch/amd64/include/setjmp.h @@ -0,0 +1,21 @@ +/* $OpenBSD: setjmp.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: setjmp.h,v 1.1 2003/04/26 18:39:47 fvdl Exp $ */ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + * These are only the callee-saved registers, code calling setjmp + * will expect the rest to be clobbered anyway. + */ + +#define _JB_RBX 0 +#define _JB_RBP 1 +#define _JB_R12 2 +#define _JB_R13 3 +#define _JB_R14 4 +#define _JB_R15 5 +#define _JB_RSP 6 +#define _JB_PC 7 +#define _JB_SIGFLAG 8 +#define _JB_SIGMASK 9 + +#define _JBLEN 11 /* size, in longs, of a jmp_buf */ diff --git a/sys/arch/amd64/include/signal.h b/sys/arch/amd64/include/signal.h new file mode 100644 index 00000000000..79227ad5f6e --- /dev/null +++ b/sys/arch/amd64/include/signal.h @@ -0,0 +1,88 @@ +/* $NetBSD: signal.h,v 1.2 2003/04/28 23:16:17 bjh21 Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1989, 1991 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. + * + * @(#)signal.h 7.16 (Berkeley) 3/17/91 + */ + +#ifndef _AMD64_SIGNAL_H_ +#define _AMD64_SIGNAL_H_ + +typedef int sig_atomic_t; + +#ifndef _ANSI_SOURCE +#include <machine/trap.h> + +/* + * Information pushed on stack when a signal is delivered. + * This is used by the kernel to restore state following + * execution of the signal handler. It is also made available + * to the handler to allow it to restore state properly if + * a non-standard exit is performed. + */ +struct sigcontext { + /* plain match trapframe */ + long sc_rdi; + long sc_rsi; + long sc_rdx; + long sc_rcx; + long sc_r8; + long sc_r9; + long sc_r10; + long sc_r11; + long sc_r12; + long sc_r13; + long sc_r14; + long sc_r15; + long sc_rbp; + long sc_rbx; + long sc_rax; + long sc_gs; + long sc_fs; + long sc_es; + long sc_ds; + long sc_trapno; + long sc_err; + long sc_rip; + long sc_cs; + long sc_rflags; + long sc_rsp; + long sc_ss; + + int sc_onstack; + int sc_mask; +}; + +#endif /* !_ANSI_SOURCE */ +#endif /* !_AMD64_SIGNAL_H_ */ + diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h new file mode 100644 index 00000000000..ef6db41a1fc --- /dev/null +++ b/sys/arch/amd64/include/specialreg.h @@ -0,0 +1,604 @@ +/* $OpenBSD: specialreg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ +/* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */ + +/*- + * Copyright (c) 1991 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. + * + * @(#)specialreg.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Bits in 386 special registers: + */ +#define CR0_PE 0x00000001 /* Protected mode Enable */ +#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */ +#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */ +#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */ +#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */ +#define CR0_PG 0x80000000 /* PaGing enable */ + +/* + * Bits in 486 special registers: + */ +#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ +#define CR0_WP 0x00010000 /* Write Protect (honor PG_RW in all modes) */ +#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */ +#define CR0_NW 0x20000000 /* Not Write-through */ +#define CR0_CD 0x40000000 /* Cache Disable */ + +/* + * Cyrix 486 DLC special registers, accessible as IO ports. + */ +#define CCR0 0xc0 /* configuration control register 0 */ +#define CCR0_NC0 0x01 /* first 64K of each 1M memory region is non-cacheable */ +#define CCR0_NC1 0x02 /* 640K-1M region is non-cacheable */ +#define CCR0_A20M 0x04 /* enables A20M# input pin */ +#define CCR0_KEN 0x08 /* enables KEN# input pin */ +#define CCR0_FLUSH 0x10 /* enables FLUSH# input pin */ +#define CCR0_BARB 0x20 /* flushes internal cache when entering hold state */ +#define CCR0_CO 0x40 /* cache org: 1=direct mapped, 0=2x set assoc */ +#define CCR0_SUSPEND 0x80 /* enables SUSP# and SUSPA# pins */ + +#define CCR1 0xc1 /* configuration control register 1 */ +#define CCR1_RPL 0x01 /* enables RPLSET and RPLVAL# pins */ +/* the remaining 7 bits of this register are reserved */ + +/* + * bits in the pentiums %cr4 register: + */ + +#define CR4_VME 0x00000001 /* virtual 8086 mode extension enable */ +#define CR4_PVI 0x00000002 /* protected mode virtual interrupt enable */ +#define CR4_TSD 0x00000004 /* restrict RDTSC instruction to cpl 0 only */ +#define CR4_DE 0x00000008 /* debugging extension */ +#define CR4_PSE 0x00000010 /* large (4MB) page size enable */ +#define CR4_PAE 0x00000020 /* physical address extension enable */ +#define CR4_MCE 0x00000040 /* machine check enable */ +#define CR4_PGE 0x00000080 /* page global enable */ +#define CR4_PCE 0x00000100 /* enable RDPMC instruction for all cpls */ +#define CR4_OSFXSR 0x00000200 /* enable fxsave/fxrestor and SSE */ +#define CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */ + +/* + * CPUID "features" bits: + */ + +#define CPUID_FPU 0x00000001 /* processor has an FPU? */ +#define CPUID_VME 0x00000002 /* has virtual mode (%cr4's VME/PVI) */ +#define CPUID_DE 0x00000004 /* has debugging extension */ +#define CPUID_PSE 0x00000008 /* has page 4MB page size extension */ +#define CPUID_TSC 0x00000010 /* has time stamp counter */ +#define CPUID_MSR 0x00000020 /* has mode specific registers */ +#define CPUID_PAE 0x00000040 /* has phys address extension */ +#define CPUID_MCE 0x00000080 /* has machine check exception */ +#define CPUID_CX8 0x00000100 /* has CMPXCHG8B instruction */ +#define CPUID_APIC 0x00000200 /* has enabled APIC */ +#define CPUID_B10 0x00000400 /* reserved, MTRR */ +#define CPUID_SEP 0x00000800 /* has SYSENTER/SYSEXIT extension */ +#define CPUID_MTRR 0x00001000 /* has memory type range register */ +#define CPUID_PGE 0x00002000 /* has page global extension */ +#define CPUID_MCA 0x00004000 /* has machine check architecture */ +#define CPUID_CMOV 0x00008000 /* has CMOVcc instruction */ +#define CPUID_PAT 0x00010000 /* Page Attribute Table */ +#define CPUID_PSE36 0x00020000 /* 36-bit PSE */ +#define CPUID_PN 0x00040000 /* processor serial number */ +#define CPUID_CFLUSH 0x00080000 /* CFLUSH insn supported */ +#define CPUID_B20 0x00100000 /* reserved */ +#define CPUID_DS 0x00200000 /* Debug Store */ +#define CPUID_ACPI 0x00400000 /* ACPI performance modulation regs */ +#define CPUID_MMX 0x00800000 /* MMX supported */ +#define CPUID_FXSR 0x01000000 /* fast FP/MMX save/restore */ +#define CPUID_SSE 0x02000000 /* streaming SIMD extensions */ +#define CPUID_SSE2 0x04000000 /* streaming SIMD extensions #2 */ +#define CPUID_SS 0x08000000 /* self-snoop */ +#define CPUID_HTT 0x10000000 /* Hyper-Threading Technology */ +#define CPUID_TM 0x20000000 /* thermal monitor (TCC) */ +#define CPUID_IA64 0x40000000 /* IA-64 architecture */ +#define CPUID_SBF 0x80000000 /* signal break on FERR */ + +#define CPUID_FLAGS1 "\20\1FPU\2VME\3DE\4PSE\5TSC\6MSR\7PAE" \ + "\10MCE\11CX8\12APIC\13B10\14SEP\15MTRR" +#define CPUID_MASK1 0x00001fff +#define CPUID_FLAGS2 "\20\16PGE\17MCA\20CMOV\21PAT\22PSE36\23PN\24CFLUSH" \ + "\25B20\26DS\27ACPI\30MMX" +#define CPUID_MASK2 0x00ffe000 +#define CPUID_FLAGS3 "\20\31FXSR\32SSE\33SSE2\34SS\35HTT\36TM\37IA64\40SBF" +#define CPUID_MASK3 0xff000000 + +/* + * AMD/VIA processor specific flags. + */ + +#define CPUID_MPC 0x00080000 /* Multiprocessing Capable */ +#define CPUID_NXE 0x00100000 /* No-Execute Extension */ +#define CPUID_MMXX 0x00400000 /* AMD MMX Extensions */ +#define CPUID_3DNOW2 0x40000000 /* 3DNow! Instruction Extension */ +#define CPUID_3DNOW 0x80000000 /* 3DNow! Instructions */ + +#define CPUID_EXT_FLAGS2 "\20\16PGE\17MCA\20CMOV\21PAT\22PSE36\23PN" \ + "\24MPC\25NXE\26B21\27MMXX\30MMX" +#define CPUID_EXT_FLAGS3 "\20\31FXSR\32SSE\33SSE2\34B27\35B28\36LONG" \ + "\0373DNOW2\0403DNOW" + +#define CPUID2FAMILY(cpuid) (((cpuid) >> 8) & 15) +#define CPUID2MODEL(cpuid) (((cpuid) >> 4) & 15) +#define CPUID2STEPPING(cpuid) ((cpuid) & 15) + +#define CPUID(code, eax, ebx, ecx, edx) \ + __asm("cpuid" \ + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ + : "a" (code)); + + +/* + * Model-specific registers for the i386 family + */ +#define MSR_P5_MC_ADDR 0x000 /* P5 only */ +#define MSR_P5_MC_TYPE 0x001 /* P5 only */ +#define MSR_TSC 0x010 +#define MSR_CESR 0x011 /* P5 only (trap on P6) */ +#define MSR_CTR0 0x012 /* P5 only (trap on P6) */ +#define MSR_CTR1 0x013 /* P5 only (trap on P6) */ +#define MSR_APICBASE 0x01b +#define MSR_EBL_CR_POWERON 0x02a +#define MSR_TEST_CTL 0x033 +#define MSR_BIOS_UPDT_TRIG 0x079 +#define MSR_BBL_CR_D0 0x088 /* PII+ only */ +#define MSR_BBL_CR_D1 0x089 /* PII+ only */ +#define MSR_BBL_CR_D2 0x08a /* PII+ only */ +#define MSR_BIOS_SIGN 0x08b +#define MSR_PERFCTR0 0x0c1 +#define MSR_PERFCTR1 0x0c2 +#define MSR_MTRRcap 0x0fe +#define MSR_BBL_CR_ADDR 0x116 /* PII+ only */ +#define MSR_BBL_CR_DECC 0x118 /* PII+ only */ +#define MSR_BBL_CR_CTL 0x119 /* PII+ only */ +#define MSR_BBL_CR_TRIG 0x11a /* PII+ only */ +#define MSR_BBL_CR_BUSY 0x11b /* PII+ only */ +#define MSR_BBL_CR_CTR3 0x11e /* PII+ only */ +#define MSR_SYSENTER_CS 0x174 /* PII+ only */ +#define MSR_SYSENTER_ESP 0x175 /* PII+ only */ +#define MSR_SYSENTER_EIP 0x176 /* PII+ only */ +#define MSR_MCG_CAP 0x179 +#define MSR_MCG_STATUS 0x17a +#define MSR_MCG_CTL 0x17b +#define MSR_EVNTSEL0 0x186 +#define MSR_EVNTSEL1 0x187 +#define MSR_DEBUGCTLMSR 0x1d9 +#define MSR_LASTBRANCHFROMIP 0x1db +#define MSR_LASTBRANCHTOIP 0x1dc +#define MSR_LASTINTFROMIP 0x1dd +#define MSR_LASTINTTOIP 0x1de +#define MSR_ROB_CR_BKUPTMPDR6 0x1e0 +#define MSR_MTRRphysBase0 0x200 +#define MSR_MTRRphysMask0 0x201 +#define MSR_MTRRphysBase1 0x202 +#define MSR_MTRRphysMask1 0x203 +#define MSR_MTRRphysBase2 0x204 +#define MSR_MTRRphysMask2 0x205 +#define MSR_MTRRphysBase3 0x206 +#define MSR_MTRRphysMask3 0x207 +#define MSR_MTRRphysBase4 0x208 +#define MSR_MTRRphysMask4 0x209 +#define MSR_MTRRphysBase5 0x20a +#define MSR_MTRRphysMask5 0x20b +#define MSR_MTRRphysBase6 0x20c +#define MSR_MTRRphysMask6 0x20d +#define MSR_MTRRphysBase7 0x20e +#define MSR_MTRRphysMask7 0x20f +#define MSR_MTRRfix64K_00000 0x250 +#define MSR_MTRRfix16K_80000 0x258 +#define MSR_MTRRfix16K_A0000 0x259 +#define MSR_MTRRfix4K_C0000 0x268 +#define MSR_MTRRfix4K_C8000 0x269 +#define MSR_MTRRfix4K_D0000 0x26a +#define MSR_MTRRfix4K_D8000 0x26b +#define MSR_MTRRfix4K_E0000 0x26c +#define MSR_MTRRfix4K_E8000 0x26d +#define MSR_MTRRfix4K_F0000 0x26e +#define MSR_MTRRfix4K_F8000 0x26f +#define MSR_MTRRdefType 0x2ff +#define MSR_MC0_CTL 0x400 +#define MSR_MC0_STATUS 0x401 +#define MSR_MC0_ADDR 0x402 +#define MSR_MC0_MISC 0x403 +#define MSR_MC1_CTL 0x404 +#define MSR_MC1_STATUS 0x405 +#define MSR_MC1_ADDR 0x406 +#define MSR_MC1_MISC 0x407 +#define MSR_MC2_CTL 0x408 +#define MSR_MC2_STATUS 0x409 +#define MSR_MC2_ADDR 0x40a +#define MSR_MC2_MISC 0x40b +#define MSR_MC4_CTL 0x40c +#define MSR_MC4_STATUS 0x40d +#define MSR_MC4_ADDR 0x40e +#define MSR_MC4_MISC 0x40f +#define MSR_MC3_CTL 0x410 +#define MSR_MC3_STATUS 0x411 +#define MSR_MC3_ADDR 0x412 +#define MSR_MC3_MISC 0x413 + +/* + * AMD K6/K7 MSRs. + */ +#define MSR_K6_UWCCR 0xc0000085 +#define MSR_K7_EVNTSEL0 0xc0010000 +#define MSR_K7_EVNTSEL1 0xc0010001 +#define MSR_K7_EVNTSEL2 0xc0010002 +#define MSR_K7_EVNTSEL3 0xc0010003 +#define MSR_K7_PERFCTR0 0xc0010004 +#define MSR_K7_PERFCTR1 0xc0010005 +#define MSR_K7_PERFCTR2 0xc0010006 +#define MSR_K7_PERFCTR3 0xc0010007 + +/* + * Constants related to MTRRs + */ +#define MTRR_N64K 8 /* numbers of fixed-size entries */ +#define MTRR_N16K 16 +#define MTRR_N4K 64 + +/* + * the following four 3-byte registers control the non-cacheable regions. + * These registers must be written as three separate bytes. + * + * NCRx+0: A31-A24 of starting address + * NCRx+1: A23-A16 of starting address + * NCRx+2: A15-A12 of starting address | NCR_SIZE_xx. + * + * The non-cacheable region's starting address must be aligned to the + * size indicated by the NCR_SIZE_xx field. + */ +#define NCR1 0xc4 +#define NCR2 0xc7 +#define NCR3 0xca +#define NCR4 0xcd + +#define NCR_SIZE_0K 0 +#define NCR_SIZE_4K 1 +#define NCR_SIZE_8K 2 +#define NCR_SIZE_16K 3 +#define NCR_SIZE_32K 4 +#define NCR_SIZE_64K 5 +#define NCR_SIZE_128K 6 +#define NCR_SIZE_256K 7 +#define NCR_SIZE_512K 8 +#define NCR_SIZE_1M 9 +#define NCR_SIZE_2M 10 +#define NCR_SIZE_4M 11 +#define NCR_SIZE_8M 12 +#define NCR_SIZE_16M 13 +#define NCR_SIZE_32M 14 +#define NCR_SIZE_4G 15 + +/* + * Performance monitor events. + * + * Note that 586-class and 686-class CPUs have different performance + * monitors available, and they are accessed differently: + * + * 686-class: `rdpmc' instruction + * 586-class: `rdmsr' instruction, CESR MSR + * + * The descriptions of these events are too lenghy to include here. + * See Appendix A of "Intel Architecture Software Developer's + * Manual, Volume 3: System Programming" for more information. + */ + +/* + * 586-class CESR MSR format. Lower 16 bits is CTR0, upper 16 bits + * is CTR1. + */ + +#define PMC5_CESR_EVENT 0x003f +#define PMC5_CESR_OS 0x0040 +#define PMC5_CESR_USR 0x0080 +#define PMC5_CESR_E 0x0100 +#define PMC5_CESR_P 0x0200 + +#define PMC5_DATA_READ 0x00 +#define PMC5_DATA_WRITE 0x01 +#define PMC5_DATA_TLB_MISS 0x02 +#define PMC5_DATA_READ_MISS 0x03 +#define PMC5_DATA_WRITE_MISS 0x04 +#define PMC5_WRITE_M_E 0x05 +#define PMC5_DATA_LINES_WBACK 0x06 +#define PMC5_DATA_CACHE_SNOOP 0x07 +#define PMC5_DATA_CACHE_SNOOP_HIT 0x08 +#define PMC5_MEM_ACCESS_BOTH_PIPES 0x09 +#define PMC5_BANK_CONFLICTS 0x0a +#define PMC5_MISALIGNED_DATA 0x0b +#define PMC5_INST_READ 0x0c +#define PMC5_INST_TLB_MISS 0x0d +#define PMC5_INST_CACHE_MISS 0x0e +#define PMC5_SEGMENT_REG_LOAD 0x0f +#define PMC5_BRANCHES 0x12 +#define PMC5_BTB_HITS 0x13 +#define PMC5_BRANCH_TAKEN 0x14 +#define PMC5_PIPELINE_FLUSH 0x15 +#define PMC5_INST_EXECUTED 0x16 +#define PMC5_INST_EXECUTED_V_PIPE 0x17 +#define PMC5_BUS_UTILIZATION 0x18 +#define PMC5_WRITE_BACKUP_STALL 0x19 +#define PMC5_DATA_READ_STALL 0x1a +#define PMC5_WRITE_E_M_STALL 0x1b +#define PMC5_LOCKED_BUS 0x1c +#define PMC5_IO_CYCLE 0x1d +#define PMC5_NONCACHE_MEM_READ 0x1e +#define PMC5_AGI_STALL 0x1f +#define PMC5_FLOPS 0x22 +#define PMC5_BP0_MATCH 0x23 +#define PMC5_BP1_MATCH 0x24 +#define PMC5_BP2_MATCH 0x25 +#define PMC5_BP3_MATCH 0x26 +#define PMC5_HARDWARE_INTR 0x27 +#define PMC5_DATA_RW 0x28 +#define PMC5_DATA_RW_MISS 0x29 + +/* + * 686-class Event Selector MSR format. + */ + +#define PMC6_EVTSEL_EVENT 0x000000ff +#define PMC6_EVTSEL_UNIT 0x0000ff00 +#define PMC6_EVTSEL_UNIT_SHIFT 8 +#define PMC6_EVTSEL_USR (1 << 16) +#define PMC6_EVTSEL_OS (1 << 17) +#define PMC6_EVTSEL_E (1 << 18) +#define PMC6_EVTSEL_PC (1 << 19) +#define PMC6_EVTSEL_INT (1 << 20) +#define PMC6_EVTSEL_EN (1 << 22) /* PerfEvtSel0 only */ +#define PMC6_EVTSEL_INV (1 << 23) +#define PMC6_EVTSEL_COUNTER_MASK 0xff000000 +#define PMC6_EVTSEL_COUNTER_MASK_SHIFT 24 + +/* Data Cache Unit */ +#define PMC6_DATA_MEM_REFS 0x43 +#define PMC6_DCU_LINES_IN 0x45 +#define PMC6_DCU_M_LINES_IN 0x46 +#define PMC6_DCU_M_LINES_OUT 0x47 +#define PMC6_DCU_MISS_OUTSTANDING 0x48 + +/* Instruction Fetch Unit */ +#define PMC6_IFU_IFETCH 0x80 +#define PMC6_IFU_IFETCH_MISS 0x81 +#define PMC6_ITLB_MISS 0x85 +#define PMC6_IFU_MEM_STALL 0x86 +#define PMC6_ILD_STALL 0x87 + +/* L2 Cache */ +#define PMC6_L2_IFETCH 0x28 +#define PMC6_L2_LD 0x29 +#define PMC6_L2_ST 0x2a +#define PMC6_L2_LINES_IN 0x24 +#define PMC6_L2_LINES_OUT 0x26 +#define PMC6_L2_M_LINES_INM 0x25 +#define PMC6_L2_M_LINES_OUTM 0x27 +#define PMC6_L2_RQSTS 0x2e +#define PMC6_L2_ADS 0x21 +#define PMC6_L2_DBUS_BUSY 0x22 +#define PMC6_L2_DBUS_BUSY_RD 0x23 + +/* External Bus Logic */ +#define PMC6_BUS_DRDY_CLOCKS 0x62 +#define PMC6_BUS_LOCK_CLOCKS 0x63 +#define PMC6_BUS_REQ_OUTSTANDING 0x60 +#define PMC6_BUS_TRAN_BRD 0x65 +#define PMC6_BUS_TRAN_RFO 0x66 +#define PMC6_BUS_TRANS_WB 0x67 +#define PMC6_BUS_TRAN_IFETCH 0x68 +#define PMC6_BUS_TRAN_INVAL 0x69 +#define PMC6_BUS_TRAN_PWR 0x6a +#define PMC6_BUS_TRANS_P 0x6b +#define PMC6_BUS_TRANS_IO 0x6c +#define PMC6_BUS_TRAN_DEF 0x6d +#define PMC6_BUS_TRAN_BURST 0x6e +#define PMC6_BUS_TRAN_ANY 0x70 +#define PMC6_BUS_TRAN_MEM 0x6f +#define PMC6_BUS_DATA_RCV 0x64 +#define PMC6_BUS_BNR_DRV 0x61 +#define PMC6_BUS_HIT_DRV 0x7a +#define PMC6_BUS_HITM_DRDV 0x7b +#define PMC6_BUS_SNOOP_STALL 0x7e + +/* Floating Point Unit */ +#define PMC6_FLOPS 0xc1 +#define PMC6_FP_COMP_OPS_EXE 0x10 +#define PMC6_FP_ASSIST 0x11 +#define PMC6_MUL 0x12 +#define PMC6_DIV 0x12 +#define PMC6_CYCLES_DIV_BUSY 0x14 + +/* Memory Ordering */ +#define PMC6_LD_BLOCKS 0x03 +#define PMC6_SB_DRAINS 0x04 +#define PMC6_MISALIGN_MEM_REF 0x05 +#define PMC6_EMON_KNI_PREF_DISPATCHED 0x07 /* P-III only */ +#define PMC6_EMON_KNI_PREF_MISS 0x4b /* P-III only */ + +/* Instruction Decoding and Retirement */ +#define PMC6_INST_RETIRED 0xc0 +#define PMC6_UOPS_RETIRED 0xc2 +#define PMC6_INST_DECODED 0xd0 +#define PMC6_EMON_KNI_INST_RETIRED 0xd8 +#define PMC6_EMON_KNI_COMP_INST_RET 0xd9 + +/* Interrupts */ +#define PMC6_HW_INT_RX 0xc8 +#define PMC6_CYCLES_INT_MASKED 0xc6 +#define PMC6_CYCLES_INT_PENDING_AND_MASKED 0xc7 + +/* Branches */ +#define PMC6_BR_INST_RETIRED 0xc4 +#define PMC6_BR_MISS_PRED_RETIRED 0xc5 +#define PMC6_BR_TAKEN_RETIRED 0xc9 +#define PMC6_BR_MISS_PRED_TAKEN_RET 0xca +#define PMC6_BR_INST_DECODED 0xe0 +#define PMC6_BTB_MISSES 0xe2 +#define PMC6_BR_BOGUS 0xe4 +#define PMC6_BACLEARS 0xe6 + +/* Stalls */ +#define PMC6_RESOURCE_STALLS 0xa2 +#define PMC6_PARTIAL_RAT_STALLS 0xd2 + +/* Segment Register Loads */ +#define PMC6_SEGMENT_REG_LOADS 0x06 + +/* Clocks */ +#define PMC6_CPU_CLK_UNHALTED 0x79 + +/* MMX Unit */ +#define PMC6_MMX_INSTR_EXEC 0xb0 /* Celeron, P-II, P-IIX only */ +#define PMC6_MMX_SAT_INSTR_EXEC 0xb1 /* P-II and P-III only */ +#define PMC6_MMX_UOPS_EXEC 0xb2 /* P-II and P-III only */ +#define PMC6_MMX_INSTR_TYPE_EXEC 0xb3 /* P-II and P-III only */ +#define PMC6_FP_MMX_TRANS 0xcc /* P-II and P-III only */ +#define PMC6_MMX_ASSIST 0xcd /* P-II and P-III only */ +#define PMC6_MMX_INSTR_RET 0xc3 /* P-II only */ + +/* Segment Register Renaming */ +#define PMC6_SEG_RENAME_STALLS 0xd4 /* P-II and P-III only */ +#define PMC6_SEG_REG_RENAMES 0xd5 /* P-II and P-III only */ +#define PMC6_RET_SEG_RENAMES 0xd6 /* P-II and P-III only */ + +/* + * AMD K7 Event Selector MSR format. + */ + +#define K7_EVTSEL_EVENT 0x000000ff +#define K7_EVTSEL_UNIT 0x0000ff00 +#define K7_EVTSEL_UNIT_SHIFT 8 +#define K7_EVTSEL_USR (1 << 16) +#define K7_EVTSEL_OS (1 << 17) +#define K7_EVTSEL_E (1 << 18) +#define K7_EVTSEL_PC (1 << 19) +#define K7_EVTSEL_INT (1 << 20) +#define K7_EVTSEL_EN (1 << 22) +#define K7_EVTSEL_INV (1 << 23) +#define K7_EVTSEL_COUNTER_MASK 0xff000000 +#define K7_EVTSEL_COUNTER_MASK_SHIFT 24 + +/* Segment Register Loads */ +#define K7_SEGMENT_REG_LOADS 0x20 + +#define K7_STORES_TO_ACTIVE_INST_STREAM 0x21 + +/* Data Cache Unit */ +#define K7_DATA_CACHE_ACCESS 0x40 +#define K7_DATA_CACHE_MISS 0x41 +#define K7_DATA_CACHE_REFILL 0x42 +#define K7_DATA_CACHE_REFILL_SYSTEM 0x43 +#define K7_DATA_CACHE_WBACK 0x44 +#define K7_L2_DTLB_HIT 0x45 +#define K7_L2_DTLB_MISS 0x46 +#define K7_MISALIGNED_DATA_REF 0x47 +#define K7_SYSTEM_REQUEST 0x64 +#define K7_SYSTEM_REQUEST_TYPE 0x65 + +#define K7_SNOOP_HIT 0x73 +#define K7_SINGLE_BIT_ECC_ERROR 0x74 +#define K7_CACHE_LINE_INVAL 0x75 +#define K7_CYCLES_PROCESSOR_IS_RUNNING 0x76 +#define K7_L2_REQUEST 0x79 +#define K7_L2_REQUEST_BUSY 0x7a + +/* Instruction Fetch Unit */ +#define K7_IFU_IFETCH 0x80 +#define K7_IFU_IFETCH_MISS 0x81 +#define K7_IFU_REFILL_FROM_L2 0x82 +#define K7_IFU_REFILL_FROM_SYSTEM 0x83 +#define K7_ITLB_L1_MISS 0x84 +#define K7_ITLB_L2_MISS 0x85 +#define K7_SNOOP_RESYNC 0x86 +#define K7_IFU_STALL 0x87 + +#define K7_RETURN_STACK_HITS 0x88 +#define K7_RETURN_STACK_OVERFLOW 0x89 + +/* Retired */ +#define K7_RETIRED_INST 0xc0 +#define K7_RETIRED_OPS 0xc1 +#define K7_RETIRED_BRANCHES 0xc2 +#define K7_RETIRED_BRANCH_MISPREDICTED 0xc3 +#define K7_RETIRED_TAKEN_BRANCH 0xc4 +#define K7_RETIRED_TAKEN_BRANCH_MISPREDICTED 0xc5 +#define K7_RETIRED_FAR_CONTROL_TRANSFER 0xc6 +#define K7_RETIRED_RESYNC_BRANCH 0xc7 +#define K7_RETIRED_NEAR_RETURNS 0xc8 +#define K7_RETIRED_NEAR_RETURNS_MISPREDICTED 0xc9 +#define K7_RETIRED_INDIRECT_MISPREDICTED 0xca + +/* Interrupts */ +#define K7_CYCLES_INT_MASKED 0xcd +#define K7_CYCLES_INT_PENDING_AND_MASKED 0xce +#define K7_HW_INTR_RECV 0xcf + +#define K7_INSTRUCTION_DECODER_EMPTY 0xd0 +#define K7_DISPATCH_STALLS 0xd1 +#define K7_BRANCH_ABORTS_TO_RETIRE 0xd2 +#define K7_SERIALIZE 0xd3 +#define K7_SEGMENT_LOAD_STALL 0xd4 +#define K7_ICU_FULL 0xd5 +#define K7_RESERVATION_STATIONS_FULL 0xd6 +#define K7_FPU_FULL 0xd7 +#define K7_LS_FULL 0xd8 +#define K7_ALL_QUIET_STALL 0xd9 +#define K7_FAR_TRANSFER_OR_RESYNC_BRANCH_PENDING 0xda + +#define K7_BP0_MATCH 0xdc +#define K7_BP1_MATCH 0xdd +#define K7_BP2_MATCH 0xde +#define K7_BP3_MATCH 0xdf + +/* + * Extended Feature Enable Register of the x86-64 + */ + +#define MSR_EFER 0xc0000080 + +#define EFER_SCE 0x00000001 /* SYSCALL extension */ +#define EFER_LME 0x00000100 /* Long Mode Enabled */ +#define EFER_LMA 0x00000400 /* Long Mode Active */ +#define EFER_NXE 0x00000800 /* No-Execute Enable */ +#define EFER_FFXSR 0x00004000 /* Fast FXSAVE/FXRSTOR */ + +#define MSR_STAR 0xc0000081 /* 32 bit syscall gate addr */ +#define MSR_LSTAR 0xc0000082 /* 64 bit syscall gate addr */ +#define MSR_CSTAR 0xc0000083 /* compat syscall gate addr */ +#define MSR_SFMASK 0xc0000084 /* flags to clear on syscall */ + +#define MSR_FSBASE 0xc0000100 /* 64bit offset for fs: */ +#define MSR_GSBASE 0xc0000101 /* 64bit offset for gs: */ +#define MSR_KERNELGSBASE 0xc0000102 /* storage for swapgs ins */ diff --git a/sys/arch/amd64/include/spinlock.h b/sys/arch/amd64/include/spinlock.h new file mode 100644 index 00000000000..be9e806ff5e --- /dev/null +++ b/sys/arch/amd64/include/spinlock.h @@ -0,0 +1,10 @@ +/* $OpenBSD: spinlock.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +#ifndef _MACHINE_SPINLOCK_H_ +#define _MACHINE_SPINLOCK_H_ + +#define _SPINLOCK_UNLOCKED (0) +#define _SPINLOCK_LOCKED (1) +typedef int _spinlock_lock_t; + +#endif diff --git a/sys/arch/amd64/include/stdarg.h b/sys/arch/amd64/include/stdarg.h new file mode 100644 index 00000000000..671b1e4d191 --- /dev/null +++ b/sys/arch/amd64/include/stdarg.h @@ -0,0 +1,57 @@ +/* $OpenBSD: stdarg.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: stdarg.h,v 1.2 2003/04/28 23:16:17 bjh21 Exp $ */ + +/*- + * Copyright (c) 1991, 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. + * + * @(#)stdarg.h 8.1 (Berkeley) 6/10/93 + */ + +#ifndef _AMD64_STDARG_H_ +#define _AMD64_STDARG_H_ + +#include <machine/ansi.h> + +typedef _BSD_VA_LIST_ va_list; + +#define va_start(ap, last) __builtin_stdarg_start((ap), (last)) +#define va_arg __builtin_va_arg +#define va_end(ap) __builtin_va_end(ap) +#define __va_copy(dest, src) __builtin_va_copy((dest), (src)) + +#if !defined(_ANSI_SOURCE) && \ + (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE) || \ + defined(_ISOC99_SOURCE) || (__STDC_VERSION__ - 0) >= 199901L) +#define va_copy(dest, src) __va_copy((dest), (src)) +#endif + +#endif /* !_AMD64_STDARG_H_ */ diff --git a/sys/arch/amd64/include/sysarch.h b/sys/arch/amd64/include/sysarch.h new file mode 100644 index 00000000000..6ae6d006262 --- /dev/null +++ b/sys/arch/amd64/include/sysarch.h @@ -0,0 +1,120 @@ +/* $OpenBSD: sysarch.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: sysarch.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ + +#ifndef _AMD64_SYSARCH_H_ +#define _AMD64_SYSARCH_H_ + +/* + * Architecture specific syscalls (amd64) + */ +#define X86_64_GET_LDT 0 +#define X86_64_SET_LDT 1 +#define X86_64_IOPL 2 +#define X86_64_GET_IOPERM 3 +#define X86_64_SET_IOPERM 4 +#define X86_64_VM86 5 +#define X86_64_PMC_INFO 8 +#define X86_64_PMC_STARTSTOP 9 +#define X86_64_PMC_READ 10 +#define X86_64_GET_MTRR 11 +#define X86_64_SET_MTRR 12 + +/* + * XXXfvdl todo. + */ + +#if 0 + +struct x86_64_get_ldt_args { + int start; + union descriptor *desc; + int num; +}; + +struct x86_64_set_ldt_args { + int start; + union descriptor *desc; + int num; +}; + +#endif + +struct x86_64_iopl_args { + int iopl; +}; + +#if 0 + +struct x86_64_get_ioperm_args { + u_long *iomap; +}; + +struct x86_64_set_ioperm_args { + u_long *iomap; +}; + +struct x86_64_pmc_info_args { + int type; + int flags; +}; + +#define PMC_TYPE_NONE 0 +#define PMC_TYPE_I586 1 +#define PMC_TYPE_I686 2 + +#define PMC_INFO_HASTSC 0x01 + +#define PMC_NCOUNTERS 2 + +struct x86_64_pmc_startstop_args { + int counter; + u_int64_t val; + u_int8_t event; + u_int8_t unit; + u_int8_t compare; + u_int8_t flags; +}; + +#define PMC_SETUP_KERNEL 0x01 +#define PMC_SETUP_USER 0x02 +#define PMC_SETUP_EDGE 0x04 +#define PMC_SETUP_INV 0x08 + +struct x86_64_pmc_read_args { + int counter; + u_int64_t val; + u_int64_t time; +}; + +#endif /* todo */ + +struct x86_64_get_mtrr_args { + struct mtrr *mtrrp; + int *n; +}; + +struct x86_64_set_mtrr_args { + struct mtrr *mtrrp; + int *n; +}; + + +#ifdef _KERNEL +int x86_64_iopl(struct proc *, void *, register_t *); +int x86_64_get_mtrr(struct proc *, void *, register_t *); +int x86_64_set_mtrr(struct proc *, void *, register_t *); +#else +int x86_64_get_ldt(int, union descriptor *, int); +int x86_64_set_ldt(int, union descriptor *, int); +int x86_64_iopl(int); +int x86_64_get_ioperm(u_long *); +int x86_64_set_ioperm(u_long *); +int x86_64_pmc_info(struct x86_64_pmc_info_args *); +int x86_64_pmc_startstop(struct x86_64_pmc_startstop_args *); +int x86_64_pmc_read(struct x86_64_pmc_read_args *); +int x86_64_set_mtrr(struct mtrr *, int *); +int x86_64_get_mtrr(struct mtrr *, int *); +int sysarch(int, void *); +#endif + +#endif /* !_AMD64_SYSARCH_H_ */ diff --git a/sys/arch/amd64/include/trap.h b/sys/arch/amd64/include/trap.h new file mode 100644 index 00000000000..f3353efc973 --- /dev/null +++ b/sys/arch/amd64/include/trap.h @@ -0,0 +1,74 @@ +/* $OpenBSD: trap.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: trap.h,v 1.4 1994/10/27 04:16:30 cgd Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)trap.h 5.4 (Berkeley) 5/9/91 + */ + +/* + * Trap type values + * also known in trap.c for name strings + */ + +#define T_PRIVINFLT 0 /* privileged instruction */ +#define T_BPTFLT 1 /* breakpoint trap */ +#define T_ARITHTRAP 2 /* arithmetic trap */ +#define T_ASTFLT 3 /* asynchronous system trap */ +#define T_PROTFLT 4 /* protection fault */ +#define T_TRCTRAP 5 /* trace trap */ +#define T_PAGEFLT 6 /* page fault */ +#define T_ALIGNFLT 7 /* alignment fault */ +#define T_DIVIDE 8 /* integer divide fault */ +#define T_NMI 9 /* non-maskable interrupt */ +#define T_OFLOW 10 /* overflow trap */ +#define T_BOUND 11 /* bounds check fault */ +#define T_DNA 12 /* device not available fault */ +#define T_DOUBLEFLT 13 /* double fault */ +#define T_FPOPFLT 14 /* fp coprocessor operand fetch fault (![P]Pro)*/ +#define T_TSSFLT 15 /* invalid tss fault */ +#define T_SEGNPFLT 16 /* segment not present fault */ +#define T_STKFLT 17 /* stack fault */ +#define T_MCA 18 /* machine check ([P]Pro) */ +#define T_XMM 19 /* SSE FP exception */ +#define T_RESERVED 20 /* reserved fault base */ + +/* Trap's coming from user mode */ +#define T_USER 0x100 + +/* Flags kludged into the trap code */ +#define TC_TSS 0x80000000 +#define TC_FLAGMASK (TC_TSS) diff --git a/sys/arch/amd64/include/tss.h b/sys/arch/amd64/include/tss.h new file mode 100644 index 00000000000..c674e0952dd --- /dev/null +++ b/sys/arch/amd64/include/tss.h @@ -0,0 +1,62 @@ +/* $OpenBSD: tss.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: tss.h,v 1.1 2003/04/26 18:39:49 fvdl Exp $ */ + +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, 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 for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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 _AMD64_TSS_H_ +#define _AMD64_TSS_H_ + +/* + * TSS structure. Since TSS hw switching is not supported in long + * mode, this is mainly there for the I/O permission map in + * normal processes. + */ + +struct x86_64_tss { + u_int32_t tss_reserved1; + u_int64_t tss_rsp0; + u_int64_t tss_rsp1; + u_int64_t tss_rsp3; + u_int32_t tss_reserved2; + u_int32_t tss_reserved3; + u_int64_t tss_ist[7]; + u_int32_t tss_reserved4; + u_int32_t tss_reserved5; + u_int16_t tss_reserved6; + u_int16_t tss_iobase; +} __attribute__((packed)); + +#endif /* _AMD64_TSS_H_ */ diff --git a/sys/arch/amd64/include/types.h b/sys/arch/amd64/include/types.h new file mode 100644 index 00000000000..dc95c7e0a4e --- /dev/null +++ b/sys/arch/amd64/include/types.h @@ -0,0 +1,81 @@ +/* $OpenBSD: types.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ + +/*- + * Copyright (c) 1990 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. + * + * @(#)types.h 7.5 (Berkeley) 3/9/91 + */ + +#ifndef _MACHTYPES_H_ +#define _MACHTYPES_H_ + +#include <sys/cdefs.h> + +#if defined(_KERNEL) +typedef struct label_t { + long val[8]; +} label_t; +#endif + +typedef unsigned long paddr_t; +typedef unsigned long psize_t; +typedef unsigned long vaddr_t; +typedef unsigned long vsize_t; + +#define __BIT_TYPES_DEFINED__ +typedef __signed char int8_t; +typedef unsigned char u_int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long u_int64_t; +typedef unsigned long long uint64_t; + +typedef long register_t; + +/* The amd64 does not have strict alignment requirements. */ +#define __NO_STRICT_ALIGNMENT + +#define __HAVE_DEVICE_REGISTER +#define __HAVE_NWSCONS +#define __HAVE_CPU_COUNTER +#define __HAVE_SYSCALL_INTERN +#define __HAVE_MINIMAL_EMUL +#define __HAVE_GENERIC_SOFT_INTERRUPTS +#define __HAVE_CPU_MAXPROC + +#endif /* _MACHTYPES_H_ */ diff --git a/sys/arch/amd64/include/userret.h b/sys/arch/amd64/include/userret.h new file mode 100644 index 00000000000..4422d1b25dd --- /dev/null +++ b/sys/arch/amd64/include/userret.h @@ -0,0 +1,99 @@ +/* $OpenBSD: userret.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: userret.h,v 1.1 2003/04/26 18:39:49 fvdl Exp $ */ + +/* + * XXXfvdl same as i386 counterpart, but should probably be independent. + */ + +/*- + * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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) 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. + * + */ + +#include <sys/signalvar.h> +#include <machine/cpu.h> + +static __inline void userret(struct proc *); + +/* + * Define the code needed before returning to user mode, for + * trap and syscall. + */ +static __inline void +userret(struct proc *p) +{ + int sig; + + while ((sig = CURSIG(p)) != 0) + postsig(sig); + + curpriority = p->p_priority = p->p_usrpri; +} diff --git a/sys/arch/amd64/include/vmparam.h b/sys/arch/amd64/include/vmparam.h new file mode 100644 index 00000000000..a7657f1bbff --- /dev/null +++ b/sys/arch/amd64/include/vmparam.h @@ -0,0 +1,132 @@ +/* $OpenBSD: vmparam.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: vmparam.h,v 1.1 2003/04/26 18:39:49 fvdl Exp $ */ + +/*- + * Copyright (c) 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. + * + * @(#)vmparam.h 5.9 (Berkeley) 5/12/91 + */ + +#ifndef _VMPARAM_H_ +#define _VMPARAM_H_ + +/* + * Machine dependent constants for amd64. + */ + +/* + * USRSTACK is the top (end) of the user stack. Immediately above the + * user stack resides the user structure, which is UPAGES long and contains + * the kernel stack. + * + * Immediately after the user structure is the page table map, and then + * kernal address space. + */ +#define USRSTACK VM_MAXUSER_ADDRESS + +/* + * Virtual memory related constants, all in bytes + */ +#define MAXTSIZ (64*1024*1024) /* max text size */ +#ifndef DFLDSIZ +#define DFLDSIZ (128*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ (1*1024*1024*1024) /* max data size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ (2*1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ (32*1024*1024) /* max stack size */ +#endif + +/* + * Size of shared memory map + */ +#ifndef SHMMAXPGS +#define SHMMAXPGS 8192 +#endif + +/* + * Size of User Raw I/O map + */ +#define USRIOSIZE 300 + +/* + * The time for a process to be blocked before being very swappable. + * This is a number of seconds which the system takes as being a non-trivial + * amount of real time. You probably shouldn't change this; + * it is used in subtle ways (fractions and multiples of it are, that is, like + * half of a ``long time'', almost a long time, etc.) + * It is related to human patience and other factors which don't really + * change over time. + */ +#define MAXSLP 20 + +/* + * Mach derived constants + */ + +/* user/kernel map constants */ +#define VM_MIN_ADDRESS 0 +#define VM_MAXUSER_ADDRESS 0x00007f7fffffc000 +#define VM_MAX_ADDRESS 0x00007fbfdfeff000 +#define VM_MIN_KERNEL_ADDRESS 0xffff800000000000 +#define VM_MAX_KERNEL_ADDRESS 0xffff800100000000 + +#define VM_MAXUSER_ADDRESS32 0xffffc000 + +/* virtual sizes (bytes) for various kernel submaps */ +#define VM_PHYS_SIZE (USRIOSIZE*PAGE_SIZE) + +#define VM_PHYSSEG_MAX 5 /* 1 "hole" + 4 free lists */ +#define VM_PHYSSEG_STRAT VM_PSTRAT_BIGFIRST +#define VM_PHYSSEG_NOADD /* can't add RAM after vm_mem_init */ + +#define VM_NFREELIST 2 +#define VM_FREELIST_DEFAULT 0 +#define VM_FREELIST_FIRST16 1 + +/* + * pmap specific data stored in the vm_physmem[] array + */ +#define __HAVE_PMAP_PHYSSEG +struct pmap_physseg { + struct pv_head *pvhead; /* pv_head array */ + unsigned char *attrs; /* attrs array */ +}; + +#endif /* _VMPARAM_H_ */ diff --git a/sys/arch/amd64/isa/clock.c b/sys/arch/amd64/isa/clock.c new file mode 100644 index 00000000000..524ad712ec3 --- /dev/null +++ b/sys/arch/amd64/isa/clock.c @@ -0,0 +1,765 @@ +/* $OpenBSD: clock.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: clock.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ + +/*- + * Copyright (c) 1993, 1994 Charles M. Hannum. + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * 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. + * + * @(#)clock.c 7.2 (Berkeley) 5/12/91 + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * 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 Mellon + * the rights to redistribute these changes. + */ +/* + Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + * Primitive clock interrupt routines. + */ + +/* #define CLOCKDEBUG */ +/* #define CLOCK_PARANOIA */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/timeout.h> + +#include <machine/cpu.h> +#include <machine/intr.h> +#include <machine/pio.h> +#include <machine/cpufunc.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/ic/mc146818reg.h> +#include <dev/ic/i8253reg.h> +#include <i386/isa/nvram.h> +#include <dev/clock_subr.h> +#include <machine/specialreg.h> + +#ifndef __x86_64__ +#include "mca.h" +#endif +#if NMCA > 0 +#include <machine/mca_machdep.h> /* for MCA_system */ +#endif + +#include "pcppi.h" +#if (NPCPPI > 0) +#include <dev/isa/pcppivar.h> + +#ifdef CLOCKDEBUG +int clock_debug = 0; +#define DPRINTF(arg) if (clock_debug) printf arg +#else +#define DPRINTF(arg) +#endif + +int sysbeepmatch(struct device *, void *, void *); +void sysbeepattach(struct device *, struct device *, void *); + +struct cfattach sysbeep_ca = { + sizeof(struct device), sysbeepmatch, sysbeepattach +}; + +struct cfdriver sysbeep_cd = { + NULL, "sysbeep", DV_DULL +}; + +static int ppi_attached; +static pcppi_tag_t ppicookie; +#endif /* PCPPI */ + +void spinwait(int); +int clockintr(void *); +int rtcintr(void *); +int gettick(void); +void sysbeep(int, int); +void rtcdrain(void *v); +int rtcget(mc_todregs *); +void rtcput(mc_todregs *); +int bcdtobin(int); +int bintobcd(int); +void findcpuspeed(void); + +__inline u_int mc146818_read(void *, u_int); +__inline void mc146818_write(void *, u_int, u_int); + +__inline u_int +mc146818_read(sc, reg) + void *sc; /* XXX use it? */ + u_int reg; +{ + + outb(IO_RTC, reg); + DELAY(1); + return (inb(IO_RTC+1)); +} + +__inline void +mc146818_write(sc, reg, datum) + void *sc; /* XXX use it? */ + u_int reg, datum; +{ + + outb(IO_RTC, reg); + DELAY(1); + outb(IO_RTC+1, datum); + DELAY(1); +} + +/* minimal initialization, enough for delay() */ +void +initrtclock() +{ + u_long tval; + + /* + * Compute timer_count, the count-down count the timer will be + * set to. Also, correctly round + * this by carrying an extra bit through the division. + */ + tval = (TIMER_FREQ * 2) / (u_long) hz; + tval = (tval / 2) + (tval & 0x1); + + /* initialize 8253 clock */ + outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); + + /* Correct rounding will buy us a better precision in timekeeping */ + outb(IO_TIMER1+TIMER_CNTR0, tval % 256); + outb(IO_TIMER1+TIMER_CNTR0, tval / 256); +} + +/* + * microtime() makes use of the following globals. Note that isa_timer_tick + * may be redundant to the `tick' variable, but is kept here for stability. + * isa_timer_count is the countdown count for the timer. timer_msb_table[] + * and timer_lsb_table[] are used to compute the microsecond increment + * for time.tv_usec in the follow fashion: + * + * time.tv_usec += isa_timer_msb_table[cnt_msb] - isa_timer_lsb_table[cnt_lsb]; + */ +#define ISA_TIMER_MSB_TABLE_SIZE 128 + +u_long isa_timer_tick; /* the number of microseconds in a tick */ +u_short isa_timer_count; /* the countdown count for the timer */ +u_short isa_timer_msb_table[ISA_TIMER_MSB_TABLE_SIZE]; /* timer->usec MSB */ +u_short isa_timer_lsb_table[256]; /* timer->usec conversion for LSB */ + +void +startrtclock() +{ + int s; + + findcpuspeed(); /* use the clock (while it's free) + to find the cpu speed */ + initrtclock(); + + /* Check diagnostic status */ + if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */ + printf("RTC BIOS diagnostic error %b\n", s, NVRAM_DIAG_BITS); +} + +int +clockintr(void *arg) +{ + struct clockframe *frame = arg; +#if defined(I586_CPU) || defined(I686_CPU) + static int microset_iter; /* call cc_microset once/sec */ + struct cpu_info *ci = curcpu(); + + /* + * If we have a cycle counter, do the microset thing. + */ + if (ci->ci_feature_flags & CPUID_TSC) { + if ( +#if defined(MULTIPROCESSOR) + CPU_IS_PRIMARY(ci) && +#endif + (microset_iter--) == 0) { + cc_microset_time = time; + microset_iter = hz - 1; +#if defined(MULTIPROCESSOR) + x86_broadcast_ipi(X86_IPI_MICROSET); +#endif + cc_microset(ci); + } + } +#endif + hardclock(frame); + + return 1; +} + +int +rtcintr(void *arg) +{ + struct clockframe *frame = arg; + u_int stat = 0; + + /* + * If rtcintr is 'late', next intr may happen immediately. + * Get them all. (Also, see comment in cpu_initclocks().) + */ + while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) { + statclock(frame); + stat = 1; + } + + return (stat); +} + +int +gettick() +{ + u_long ef; + u_char lo, hi; + + /* Don't want someone screwing with the counter while we're here. */ + ef = read_rflags(); + disable_intr(); + /* Select counter 0 and latch it. */ + outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); + lo = inb(IO_TIMER1+TIMER_CNTR0); + hi = inb(IO_TIMER1+TIMER_CNTR0); + write_rflags(ef); + return ((hi << 8) | lo); +} + +/* + * Wait "n" microseconds. + * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. + * Note: timer had better have been programmed before this is first used! + * (Note that we use `rate generator' mode, which counts at 1:1; `square + * wave' mode counts at 2:1). + */ +void +i8254_delay(int n) +{ + int limit, tick, otick; + + /* + * Read the counter first, so that the rest of the setup overhead is + * counted. + */ + otick = gettick(); + +#ifdef __GNUC__ + /* + * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so + * we can take advantage of the intermediate 64-bit quantity to prevent + * loss of significance. + */ + n -= 5; + if (n < 0) + return; + __asm __volatile("mul %2\n\tdiv %3" + : "=a" (n) + : "0" (n), "r" (TIMER_FREQ), "r" (1000000) + : "%edx", "cc"); +#else + /* + * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and + * without any avoidable overflows. + */ + n -= 20; + { + int sec = n / 1000000, + usec = n % 1000000; + n = sec * TIMER_FREQ + + usec * (TIMER_FREQ / 1000000) + + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 + + usec * (TIMER_FREQ % 1000) / 1000000; + } +#endif + + limit = TIMER_FREQ / hz; + + while (n > 0) { + tick = gettick(); + if (tick > otick) + n -= limit - (tick - otick); + else + n -= otick - tick; + otick = tick; + } +} + +#if (NPCPPI > 0) +int +sysbeepmatch(parent, match, aux) + struct device *parent; + void *match; + void *aux; +{ + return (!ppi_attached); +} + +void +sysbeepattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + printf("\n"); + + ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie; + ppi_attached = 1; +} +#endif + +void +sysbeep(pitch, period) + int pitch, period; +{ +#if (NPCPPI > 0) + if (ppi_attached) + pcppi_bell(ppicookie, pitch, period, 0); +#endif +} + +unsigned int delaycount; /* calibrated loop variable (1 millisecond) */ + +#define FIRST_GUESS 0x2000 + +void +findcpuspeed() +{ + int i; + int remainder; + + /* Put counter in count down mode */ + outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN); + outb(TIMER_CNTR0, 0xff); + outb(TIMER_CNTR0, 0xff); + for (i = FIRST_GUESS; i; i--) + ; + /* Read the value left in the counter */ + remainder = gettick(); + /* + * Formula for delaycount is: + * (loopcount * timer clock speed) / (counter ticks * 1000) + */ + delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff-remainder); +} + +void +rtcdrain(void *v) +{ + struct timeout *to = (struct timeout *)v; + + if (to != NULL) + timeout_del(to); + + /* + * Drain any un-acknowledged RTC interrupts. + * See comment in cpu_initclocks(). + */ + while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) + ; /* Nothing. */ +} + +void +i8254_initclocks() +{ + static struct timeout rtcdrain_timeout; + + stathz = 128; + profhz = 1024; + + /* + * XXX If you're doing strange things with multiple clocks, you might + * want to keep track of clock handlers. + */ + isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr,0,"clock"); + isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr, 0, "rtc"); + + mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); + mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE); + + /* + * On a number of i386 systems, the rtc will fail to start when booting + * the system. This is due to us missing to acknowledge an interrupt + * during early stages of the boot process. If we do not acknowledge + * the interrupt, the rtc clock will not generate further interrupts. + * To solve this, once interrupts are enabled, use a timeout (once) + * to drain any un-acknowledged rtc interrupt(s). + */ + timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout); + timeout_add(&rtcdrain_timeout, 1); +} + +int +rtcget(regs) + mc_todregs *regs; +{ + if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ + return (-1); + MC146818_GETTOD(NULL, regs); /* XXX softc */ + return (0); +} + +void +rtcput(regs) + mc_todregs *regs; +{ + MC146818_PUTTOD(NULL, regs); /* XXX softc */ +} + +int +bcdtobin(n) + int n; +{ + + return (((n >> 4) & 0x0f) * 10 + (n & 0x0f)); +} + +int +bintobcd(n) + int n; +{ + + return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f)); +} + +static int timeset; + +/* + * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), + * to be called at splclock() + */ +static int cmoscheck(void); +static int +cmoscheck() +{ + int i; + unsigned short cksum = 0; + + for (i = 0x10; i <= 0x2d; i++) + cksum += mc146818_read(NULL, i); /* XXX softc */ + + return (cksum == (mc146818_read(NULL, 0x2e) << 8) + + mc146818_read(NULL, 0x2f)); +} + +#if NMCA > 0 +/* + * Check whether the CMOS layout is PS/2 like, to be called at splclock(). + */ +static int cmoscheckps2(void); +static int +cmoscheckps2() +{ +#if 0 + /* Disabled until I find out the CRC checksum algorithm IBM uses */ + int i; + unsigned short cksum = 0; + + for (i = 0x10; i <= 0x31; i++) + cksum += mc146818_read(NULL, i); /* XXX softc */ + + return (cksum == (mc146818_read(NULL, 0x32) << 8) + + mc146818_read(NULL, 0x33)); +#else + /* Check 'incorrect checksum' bit of IBM PS/2 Diagnostic Status Byte */ + return ((mc146818_read(NULL, NVRAM_DIAG) & (1<<6)) == 0); +#endif +} +#endif /* NMCA > 0 */ + +/* + * patchable to control century byte handling: + * 1: always update + * -1: never touch + * 0: try to figure out itself + */ +int rtc_update_century = 0; + +/* + * Expand a two-digit year as read from the clock chip + * into full width. + * Being here, deal with the CMOS century byte. + */ +static int centb = NVRAM_CENTURY; +static int clock_expandyear(int); +static int +clock_expandyear(clockyear) + int clockyear; +{ + int s, clockcentury, cmoscentury; + + clockcentury = (clockyear < 70) ? 20 : 19; + clockyear += 100 * clockcentury; + + if (rtc_update_century < 0) + return (clockyear); + + s = splclock(); + if (cmoscheck()) + cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); +#if NMCA > 0 + else if (MCA_system && cmoscheckps2()) + cmoscentury = mc146818_read(NULL, (centb = 0x37)); +#endif + else + cmoscentury = 0; + splx(s); + if (!cmoscentury) { +#ifdef DIAGNOSTIC + printf("clock: unknown CMOS layout\n"); +#endif + return (clockyear); + } + cmoscentury = bcdtobin(cmoscentury); + + if (cmoscentury != clockcentury) { + /* XXX note: saying "century is 20" might confuse the naive. */ + printf("WARNING: NVRAM century is %d but RTC year is %d\n", + cmoscentury, clockyear); + + /* Kludge to roll over century. */ + if ((rtc_update_century > 0) || + ((cmoscentury == 19) && (clockcentury == 20) && + (clockyear == 2000))) { + printf("WARNING: Setting NVRAM century to %d\n", + clockcentury); + s = splclock(); + mc146818_write(NULL, centb, bintobcd(clockcentury)); + splx(s); + } + } else if (cmoscentury == 19 && rtc_update_century == 0) + rtc_update_century = 1; /* will update later in resettodr() */ + + return (clockyear); +} + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +void +inittodr(base) + time_t base; +{ + mc_todregs rtclk; + struct clock_ymdhms dt; + int s; +#if defined(I586_CPU) || defined(I686_CPU) + struct cpu_info *ci = curcpu(); +#endif + /* + * We mostly ignore the suggested time (which comes from the + * file system) and go for the RTC clock time stored in the + * CMOS RAM. If the time can't be obtained from the CMOS, or + * if the time obtained from the CMOS is 5 or more years less + * than the suggested time, we used the suggested time. (In + * the latter case, it's likely that the CMOS battery has + * died.) + */ + + /* + * if the file system time is more than a year older than the + * kernel, warn and then set the base time to the CONFIG_TIME. + */ + if (base < 30*SECYR) { /* if before 2000, something's odd... */ + printf("WARNING: preposterous time in file system\n"); + base = 30*SECYR; + } + + s = splclock(); + if (rtcget(&rtclk)) { + splx(s); + printf("WARNING: invalid time in clock chip\n"); + goto fstime; + } + splx(s); +#ifdef DEBUG_CLOCK + printf("readclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], + rtclk[MC_MONTH], rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], + rtclk[MC_SEC]); +#endif + + dt.dt_sec = bcdtobin(rtclk[MC_SEC]); + dt.dt_min = bcdtobin(rtclk[MC_MIN]); + dt.dt_hour = bcdtobin(rtclk[MC_HOUR]); + dt.dt_day = bcdtobin(rtclk[MC_DOM]); + dt.dt_mon = bcdtobin(rtclk[MC_MONTH]); + dt.dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR])); + + /* + * If time_t is 32 bits, then the "End of Time" is + * Mon Jan 18 22:14:07 2038 (US/Eastern) + * This code copes with RTC's past the end of time if time_t + * is an int32 or less. Needed because sometimes RTCs screw + * up or are badly set, and that would cause the time to go + * negative in the calculation below, which causes Very Bad + * Mojo. This at least lets the user boot and fix the problem. + * Note the code is self eliminating once time_t goes to 64 bits. + */ + if (sizeof(time_t) <= sizeof(int32_t)) { + if (dt.dt_year >= 2038) { + printf("WARNING: RTC time at or beyond 2038.\n"); + dt.dt_year = 2037; + printf("WARNING: year set back to 2037.\n"); + printf("WARNING: CHECK AND RESET THE DATE!\n"); + } + } + + time.tv_sec = clock_ymdhms_to_secs(&dt); +#ifdef DEBUG_CLOCK + printf("readclock: %ld (%ld)\n", time.tv_sec, base); +#endif +#if defined(I586_CPU) || defined(I686_CPU) + if (ci->ci_feature_flags & CPUID_TSC) { + cc_microset_time = time; + cc_microset(ci); + } +#endif + + if (base != 0 && base < time.tv_sec - 5*SECYR) + printf("WARNING: file system time much less than clock time\n"); + else if (base > time.tv_sec + 5*SECYR) { + printf("WARNING: clock time much less than file system time\n"); + printf("WARNING: using file system time\n"); + goto fstime; + } + + timeset = 1; + return; + +fstime: + timeset = 1; + time.tv_sec = base; + printf("WARNING: CHECK AND RESET THE DATE!\n"); +} + +/* + * Reset the clock. + */ +void +resettodr() +{ + mc_todregs rtclk; + struct clock_ymdhms dt; + int century; + int s; + + /* + * We might have been called by boot() due to a crash early + * on. Don't reset the clock chip in this case. + */ + if (!timeset) + return; + + s = splclock(); + if (rtcget(&rtclk)) + memset(&rtclk, 0, sizeof(rtclk)); + splx(s); + + clock_secs_to_ymdhms(time.tv_sec, &dt); + + rtclk[MC_SEC] = bintobcd(dt.dt_sec); + rtclk[MC_MIN] = bintobcd(dt.dt_min); + rtclk[MC_HOUR] = bintobcd(dt.dt_hour); + rtclk[MC_DOW] = dt.dt_wday + 1; + rtclk[MC_YEAR] = bintobcd(dt.dt_year % 100); + rtclk[MC_MONTH] = bintobcd(dt.dt_mon); + rtclk[MC_DOM] = bintobcd(dt.dt_day); + +#ifdef DEBUG_CLOCK + printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH], + rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); +#endif + s = splclock(); + rtcput(&rtclk); + if (rtc_update_century > 0) { + century = bintobcd(dt.dt_year / 100); + mc146818_write(NULL, centb, century); /* XXX softc */ + } + splx(s); +} + +void +setstatclockrate(arg) + int arg; +{ + if (arg == stathz) + mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); + else + mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz); +} diff --git a/sys/arch/amd64/isa/isa_machdep.c b/sys/arch/amd64/isa/isa_machdep.c new file mode 100644 index 00000000000..f86a49a00ed --- /dev/null +++ b/sys/arch/amd64/isa/isa_machdep.c @@ -0,0 +1,1026 @@ +/* $OpenBSD: isa_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: isa_machdep.c,v 1.22 1997/06/12 23:57:32 thorpej Exp $ */ + +#define ISA_DMA_STATS + +/*- + * Copyright (c) 1996, 1997 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. + * + * 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) 1996, 1997 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. + * + * 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) 1993, 1994, 1996, 1997 + * Charles M. Hannum. All rights reserved. + * Copyright (c) 1991 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. + * + * @(#)isa.c 7.2 (Berkeley) 5/13/91 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/syslog.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/proc.h> + +#include <uvm/uvm_extern.h> + +#define _I386_BUS_DMA_PRIVATE +#include <machine/bus.h> + +#include <machine/intr.h> +#include <machine/pio.h> +#include <machine/cpufunc.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#if 0 +#include <dev/isa/isadmavar.h> +#endif +#include <i386/isa/isa_machdep.h> +#include <i386/isa/icu.h> + +#include "isadma.h" + +/* + * ISA can only DMA to 0-16M. + */ +#define ISA_DMA_BOUNCE_THRESHOLD 0x00ffffff + +extern paddr_t avail_end; + +#define IDTVEC(name) __CONCAT(X,name) +/* default interrupt vector table entries */ +typedef int (*vector)(void); +extern vector IDTVEC(intr)[]; +void isa_strayintr(int); +int fakeintr(void *); + +#if NISADMA > 0 +int _isa_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, + bus_size_t, bus_size_t, int, bus_dmamap_t *); +void _isa_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); +int _isa_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int); +int _isa_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, + struct mbuf *, int); +int _isa_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, + struct uio *, int); +int _isa_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); +void _isa_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); +void _isa_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, + bus_addr_t, bus_size_t, int); + +int _isa_bus_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, + bus_size_t, bus_dma_segment_t *, int, int *, int); +void _isa_bus_dmamem_free(bus_dma_tag_t, + bus_dma_segment_t *, int); +int _isa_bus_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, + int, size_t, caddr_t *, int); +void _isa_bus_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t); +paddr_t _isa_bus_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, + int, off_t, int, int); + +int _isa_dma_check_buffer(void *, bus_size_t, int, bus_size_t, + struct proc *); +int _isa_dma_alloc_bouncebuf(bus_dma_tag_t, bus_dmamap_t, + bus_size_t, int); +void _isa_dma_free_bouncebuf(bus_dma_tag_t, bus_dmamap_t); + +/* + * Entry points for ISA DMA. These are mostly wrappers around + * the generic functions that understand how to deal with bounce + * buffers, if necessary. + */ +struct i386_bus_dma_tag isa_bus_dma_tag = { + NULL, /* _cookie */ + _isa_bus_dmamap_create, + _isa_bus_dmamap_destroy, + _isa_bus_dmamap_load, + _isa_bus_dmamap_load_mbuf, + _isa_bus_dmamap_load_uio, + _isa_bus_dmamap_load_raw, + _isa_bus_dmamap_unload, + _isa_bus_dmamap_sync, + _isa_bus_dmamem_alloc, + _isa_bus_dmamem_free, + _isa_bus_dmamem_map, + _isa_bus_dmamem_unmap, + _isa_bus_dmamem_mmap, +}; +#endif /* NISADMA > 0 */ + +#define GICODE_SEL 10 + +u_long intrstray[ICU_LEN]; + +/* + * Caught a stray interrupt, notify + */ +void +isa_strayintr(irq) + int irq; +{ + /* + * Stray interrupts on irq 7 occur when an interrupt line is raised + * and then lowered before the CPU acknowledges it. This generally + * means either the device is screwed or something is cli'ing too + * long and it's timing out. + */ + if (++intrstray[irq] <= 5) + log(LOG_ERR, "stray interrupt %d%s\n", irq, + intrstray[irq] >= 5 ? "; stopped logging" : ""); +} + +int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN]; +int iminlevel[ICU_LEN], imaxlevel[ICU_LEN]; +struct intrhand *intrhand[ICU_LEN]; + +int +fakeintr(arg) + void *arg; +{ + return 0; +} + +#define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2) + +int +isa_intr_alloc(ic, mask, type, irq) + isa_chipset_tag_t ic; + int mask; + int type; + int *irq; +{ + int i, bestirq, count; + int tmp; + struct intrhand **p, *q; + + if (type == IST_NONE) + panic("intr_alloc: bogus type"); + + bestirq = -1; + count = -1; + + /* some interrupts should never be dynamically allocated */ + mask &= 0xdef8; + + /* + * XXX some interrupts will be used later (6 for fdc, 12 for pms). + * the right answer is to do "breadth-first" searching of devices. + */ + mask &= 0xefbf; + + for (i = 0; i < ICU_LEN; i++) { + if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0) + continue; + + switch(intrtype[i]) { + case IST_NONE: + /* + * if nothing's using the irq, just return it + */ + *irq = i; + return (0); + + case IST_EDGE: + case IST_LEVEL: + if (type != intrtype[i]) + continue; + /* + * if the irq is shareable, count the number of other + * handlers, and if it's smaller than the last irq like + * this, remember it + * + * XXX We should probably also consider the + * interrupt level and stick IPL_TTY with other + * IPL_TTY, etc. + */ + for (p = &intrhand[i], tmp = 0; (q = *p) != NULL; + p = &q->ih_next, tmp++) + ; + if ((bestirq == -1) || (count > tmp)) { + bestirq = i; + count = tmp; + } + break; + + case IST_PULSE: + /* this just isn't shareable */ + continue; + } + } + + if (bestirq == -1) + return (1); + + *irq = bestirq; + + return (0); +} + +/* + * Just check to see if an IRQ is available/can be shared. + * 0 = interrupt not available + * 1 = interrupt shareable + * 2 = interrupt all to ourself + */ +int +isa_intr_check(ic, irq, type) + isa_chipset_tag_t ic; /* Not used. */ + int irq; + int type; +{ + if (!LEGAL_IRQ(irq) || type == IST_NONE) + return (0); + + switch (intrtype[irq]) { + case IST_NONE: + return (2); + break; + case IST_LEVEL: + if (type != intrtype[irq]) + return (0); + return (1); + break; + case IST_EDGE: + case IST_PULSE: + if (type != IST_NONE) + return (0); + } + return (1); +} + +/* + * Set up an interrupt handler to start being called. + * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM. + */ +void * +isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg, ih_what) + isa_chipset_tag_t ic; + int irq; + int type; + int level; + int (*ih_fun)(void *); + void *ih_arg; + char *ih_what; +{ + struct intrhand **p, *q, *ih; + static struct intrhand fakehand = {fakeintr}; + + return intr_establish(irq, &i8259_pic, irq, type, level, ih_fun, ih_arg); + + /* no point in sleeping unless someone can free memory. */ + ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) { + printf("%s: isa_intr_establish: can't malloc handler info\n", + ih_what); + return NULL; + } + + if (!LEGAL_IRQ(irq) || type == IST_NONE) { + printf("%s: intr_establish: bogus irq or type\n", ih_what); + return NULL; + } + switch (intrtype[irq]) { + case IST_NONE: + intrtype[irq] = type; + break; + case IST_EDGE: + case IST_LEVEL: + if (type == intrtype[irq]) + break; + case IST_PULSE: + if (type != IST_NONE) { + /*printf("%s: intr_establish: can't share %s with %s, irq %d\n", + ih_what, isa_intr_typename(intrtype[irq]), + isa_intr_typename(type), irq);*/ + return NULL; + } + break; + } + + /* + * Figure out where to put the handler. + * This is O(N^2), but we want to preserve the order, and N is + * generally small. + */ + for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next) + ; + + /* + * Actually install a fake handler momentarily, since we might be doing + * this with interrupts enabled and don't want the real routine called + * until masking is set up. + */ + fakehand.ih_level = level; + *p = &fakehand; + + /* + * Poke the real handler in now. + */ + ih->ih_fun = ih_fun; + ih->ih_arg = ih_arg; + ih->ih_next = NULL; + ih->ih_level = level; + ih->ih_irq = irq; + ih->ih_what = ih_what; + *p = ih; + + return (ih); +} + +/* + * Deregister an interrupt handler. + */ +void +isa_intr_disestablish(ic, arg) + isa_chipset_tag_t ic; + void *arg; +{ + struct intrhand *ih = arg; + int irq = ih->ih_irq; + struct intrhand **p, *q; + + intr_disestablish(arg); + return; + + if (!LEGAL_IRQ(irq)) + panic("intr_disestablish: bogus irq"); + + /* + * Remove the handler from the chain. + * This is O(n^2), too. + */ + for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next) + ; + if (q) + *p = q->ih_next; + else + panic("intr_disestablish: handler not registered"); + free(ih, M_DEVBUF); + + if (intrhand[irq] == NULL) + intrtype[irq] = IST_NONE; +} + +void +isa_attach_hook(parent, self, iba) + struct device *parent, *self; + struct isabus_attach_args *iba; +{ + extern int isa_has_been_seen; + + /* + * Notify others that might need to know that the ISA bus + * has now been attached. + */ + if (isa_has_been_seen) + panic("isaattach: ISA bus already seen!"); + isa_has_been_seen = 1; +} + +#if NISADMA > 0 +/********************************************************************** + * bus.h dma interface entry points + **********************************************************************/ + +#ifdef ISA_DMA_STATS +#define STAT_INCR(v) (v)++ +#define STAT_DECR(v) do { \ + if ((v) == 0) \ + printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \ + else \ + (v)--; \ + } while (0) +u_long isa_dma_stats_loads; +u_long isa_dma_stats_bounces; +u_long isa_dma_stats_nbouncebufs; +#else +#define STAT_INCR(v) +#define STAT_DECR(v) +#endif + +/* + * Create an ISA DMA map. + */ +int +_isa_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp) + bus_dma_tag_t t; + bus_size_t size; + int nsegments; + bus_size_t maxsegsz; + bus_size_t boundary; + int flags; + bus_dmamap_t *dmamp; +{ + struct i386_isa_dma_cookie *cookie; + bus_dmamap_t map; + int error, cookieflags; + void *cookiestore; + size_t cookiesize; + + /* Call common function to create the basic map. */ + error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, + flags, dmamp); + if (error) + return (error); + + map = *dmamp; + map->_dm_cookie = NULL; + + cookiesize = sizeof(struct i386_isa_dma_cookie); + + /* + * ISA only has 24-bits of address space. This means + * we can't DMA to pages over 16M. In order to DMA to + * arbitrary buffers, we use "bounce buffers" - pages + * in memory below the 16M boundary. On DMA reads, + * DMA happens to the bounce buffers, and is copied into + * the caller's buffer. On writes, data is copied into + * but bounce buffer, and the DMA happens from those + * pages. To software using the DMA mapping interface, + * this looks simply like a data cache. + * + * If we have more than 16M of RAM in the system, we may + * need bounce buffers. We check and remember that here. + * + * There are exceptions, however. VLB devices can do + * 32-bit DMA, and indicate that here. + * + * ...or, there is an opposite case. The most segments + * a transfer will require is (maxxfer / NBPG) + 1. If + * the caller can't handle that many segments (e.g. the + * ISA DMA controller), we may have to bounce it as well. + */ + cookieflags = 0; + if ((avail_end > ISA_DMA_BOUNCE_THRESHOLD && + (flags & ISABUS_DMA_32BIT) == 0) || + ((map->_dm_size / NBPG) + 1) > map->_dm_segcnt) { + cookieflags |= ID_MIGHT_NEED_BOUNCE; + cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt); + } + + /* + * Allocate our cookie. + */ + if ((cookiestore = malloc(cookiesize, M_DEVBUF, + (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) { + error = ENOMEM; + goto out; + } + bzero(cookiestore, cookiesize); + cookie = (struct i386_isa_dma_cookie *)cookiestore; + cookie->id_flags = cookieflags; + map->_dm_cookie = cookie; + + if (cookieflags & ID_MIGHT_NEED_BOUNCE) { + /* + * Allocate the bounce pages now if the caller + * wishes us to do so. + */ + if ((flags & BUS_DMA_ALLOCNOW) == 0) + goto out; + + error = _isa_dma_alloc_bouncebuf(t, map, size, flags); + } + + out: + if (error) { + if (map->_dm_cookie != NULL) + free(map->_dm_cookie, M_DEVBUF); + _bus_dmamap_destroy(t, map); + } + return (error); +} + +/* + * Destroy an ISA DMA map. + */ +void +_isa_bus_dmamap_destroy(t, map) + bus_dma_tag_t t; + bus_dmamap_t map; +{ + struct i386_isa_dma_cookie *cookie = map->_dm_cookie; + + /* + * Free any bounce pages this map might hold. + */ + if (cookie->id_flags & ID_HAS_BOUNCE) + _isa_dma_free_bouncebuf(t, map); + + free(cookie, M_DEVBUF); + _bus_dmamap_destroy(t, map); +} + +/* + * Load an ISA DMA map with a linear buffer. + */ +int +_isa_bus_dmamap_load(t, map, buf, buflen, p, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + void *buf; + bus_size_t buflen; + struct proc *p; + int flags; +{ + struct i386_isa_dma_cookie *cookie = map->_dm_cookie; + int error; + + STAT_INCR(isa_dma_stats_loads); + + /* + * Check to see if we might need to bounce the transfer. + */ + if (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) { + /* + * Check if all pages are below the bounce + * threshold. If they are, don't bother bouncing. + */ + if (_isa_dma_check_buffer(buf, buflen, + map->_dm_segcnt, map->_dm_boundary, p) == 0) + return (_bus_dmamap_load(t, map, buf, buflen, + p, flags)); + + STAT_INCR(isa_dma_stats_bounces); + + /* + * Allocate bounce pages, if necessary. + */ + if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { + error = _isa_dma_alloc_bouncebuf(t, map, buflen, + flags); + if (error) + return (error); + } + + /* + * Cache a pointer to the caller's buffer and + * load the DMA map with the bounce buffer. + */ + cookie->id_origbuf = buf; + cookie->id_origbuflen = buflen; + error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, + buflen, p, flags); + + if (error) { + /* + * Free the bounce pages, unless our resources + * are reserved for our exclusive use. + */ + if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) + _isa_dma_free_bouncebuf(t, map); + } + + /* ...so _isa_bus_dmamap_sync() knows we're bouncing */ + cookie->id_flags |= ID_IS_BOUNCING; + } else { + /* + * Just use the generic load function. + */ + error = _bus_dmamap_load(t, map, buf, buflen, p, flags); + } + + return (error); +} + +/* + * Like _isa_bus_dmamap_load(), but for mbufs. + */ +int +_isa_bus_dmamap_load_mbuf(t, map, m, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + struct mbuf *m; + int flags; +{ + + panic("_isa_bus_dmamap_load_mbuf: not implemented"); +} + +/* + * Like _isa_bus_dmamap_load(), but for uios. + */ +int +_isa_bus_dmamap_load_uio(t, map, uio, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + struct uio *uio; + int flags; +{ + + panic("_isa_bus_dmamap_load_uio: not implemented"); +} + +/* + * Like _isa_bus_dmamap_load(), but for raw memory allocated with + * bus_dmamem_alloc(). + */ +int +_isa_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + bus_dma_segment_t *segs; + int nsegs; + bus_size_t size; + int flags; +{ + + panic("_isa_bus_dmamap_load_raw: not implemented"); +} + +/* + * Unload an ISA DMA map. + */ +void +_isa_bus_dmamap_unload(t, map) + bus_dma_tag_t t; + bus_dmamap_t map; +{ + struct i386_isa_dma_cookie *cookie = map->_dm_cookie; + + /* + * If we have bounce pages, free them, unless they're + * reserved for our exclusive use. + */ + if ((cookie->id_flags & ID_HAS_BOUNCE) && + (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) + _isa_dma_free_bouncebuf(t, map); + + cookie->id_flags &= ~ID_IS_BOUNCING; + + /* + * Do the generic bits of the unload. + */ + _bus_dmamap_unload(t, map); +} + +/* + * Synchronize an ISA DMA map. + */ +void +_isa_bus_dmamap_sync(t, map, offset, len, op) + bus_dma_tag_t t; + bus_dmamap_t map; + bus_addr_t offset; + bus_size_t len; + int op; +{ + struct i386_isa_dma_cookie *cookie = map->_dm_cookie; + +#ifdef DEBUG + if ((op & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) { + if (offset >= map->dm_mapsize) + panic("_isa_bus_dmamap_sync: bad offset"); + if (len == 0 || (offset + len) > map->dm_mapsize) + panic("_isa_bus_dmamap_sync: bad length"); + } +#endif + + switch (op) { + case BUS_DMASYNC_PREREAD: + /* + * Nothing to do for pre-read. + */ + break; + + case BUS_DMASYNC_PREWRITE: + /* + * If we're bouncing this transfer, copy the + * caller's buffer to the bounce buffer. + */ + if (cookie->id_flags & ID_IS_BOUNCING) + bcopy(cookie->id_origbuf + offset, + cookie->id_bouncebuf + offset, + len); + break; + + case BUS_DMASYNC_POSTREAD: + /* + * If we're bouncing this transfer, copy the + * bounce buffer to the caller's buffer. + */ + if (cookie->id_flags & ID_IS_BOUNCING) + bcopy(cookie->id_bouncebuf + offset, + cookie->id_origbuf + offset, + len); + break; + + case BUS_DMASYNC_POSTWRITE: + /* + * Nothing to do for post-write. + */ + break; + } + +#if 0 + /* This is a noop anyhow, so why bother calling it? */ + _bus_dmamap_sync(t, map, op); +#endif +} + +/* + * Allocate memory safe for ISA DMA. + */ +int +_isa_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags) + bus_dma_tag_t t; + bus_size_t size, alignment, boundary; + bus_dma_segment_t *segs; + int nsegs; + int *rsegs; + int flags; +{ + paddr_t high; + + if (avail_end > ISA_DMA_BOUNCE_THRESHOLD) + high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD); + else + high = trunc_page(avail_end); + + return (_bus_dmamem_alloc_range(t, size, alignment, boundary, + segs, nsegs, rsegs, flags, 0, high)); +} + +/* + * Free memory safe for ISA DMA. + */ +void +_isa_bus_dmamem_free(t, segs, nsegs) + bus_dma_tag_t t; + bus_dma_segment_t *segs; + int nsegs; +{ + + _bus_dmamem_free(t, segs, nsegs); +} + +/* + * Map ISA DMA-safe memory into kernel virtual address space. + */ +int +_isa_bus_dmamem_map(t, segs, nsegs, size, kvap, flags) + bus_dma_tag_t t; + bus_dma_segment_t *segs; + int nsegs; + size_t size; + caddr_t *kvap; + int flags; +{ + + return (_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)); +} + +/* + * Unmap ISA DMA-safe memory from kernel virtual address space. + */ +void +_isa_bus_dmamem_unmap(t, kva, size) + bus_dma_tag_t t; + caddr_t kva; + size_t size; +{ + + _bus_dmamem_unmap(t, kva, size); +} + +/* + * mmap(2) ISA DMA-safe memory. + */ +paddr_t +_isa_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags) + bus_dma_tag_t t; + bus_dma_segment_t *segs; + int nsegs; + off_t off; + int prot, flags; +{ + + return (_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)); +} + +/********************************************************************** + * ISA DMA utility functions + **********************************************************************/ + +/* + * Return 0 if all pages in the passed buffer lie within the DMA'able + * range RAM. + */ +int +_isa_dma_check_buffer(buf, buflen, segcnt, boundary, p) + void *buf; + bus_size_t buflen; + int segcnt; + bus_size_t boundary; + struct proc *p; +{ + vaddr_t vaddr = (vaddr_t)buf; + vaddr_t endva; + paddr_t pa, lastpa; + u_long pagemask = ~(boundary - 1); + pmap_t pmap; + int nsegs; + + endva = round_page(vaddr + buflen); + + nsegs = 1; + lastpa = 0; + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + for (; vaddr < endva; vaddr += NBPG) { + /* + * Get physical address for this segment. + */ + pmap_extract(pmap, (vaddr_t)vaddr, &pa); + pa = trunc_page(pa); + + /* + * Is it below the DMA'able threshold? + */ + if (pa > ISA_DMA_BOUNCE_THRESHOLD) + return (EINVAL); + + if (lastpa) { + /* + * Check excessive segment count. + */ + if (lastpa + NBPG != pa) { + if (++nsegs > segcnt) + return (EFBIG); + } + + /* + * Check boundary restriction. + */ + if (boundary) { + if ((lastpa ^ pa) & pagemask) + return (EINVAL); + } + } + lastpa = pa; + } + + return (0); +} + +int +_isa_dma_alloc_bouncebuf(t, map, size, flags) + bus_dma_tag_t t; + bus_dmamap_t map; + bus_size_t size; + int flags; +{ + struct i386_isa_dma_cookie *cookie = map->_dm_cookie; + int error = 0; + + cookie->id_bouncebuflen = round_page(size); + error = _isa_bus_dmamem_alloc(t, cookie->id_bouncebuflen, + NBPG, map->_dm_boundary, cookie->id_bouncesegs, + map->_dm_segcnt, &cookie->id_nbouncesegs, flags); + if (error) + goto out; + error = _isa_bus_dmamem_map(t, cookie->id_bouncesegs, + cookie->id_nbouncesegs, cookie->id_bouncebuflen, + (caddr_t *)&cookie->id_bouncebuf, flags); + + out: + if (error) { + _isa_bus_dmamem_free(t, cookie->id_bouncesegs, + cookie->id_nbouncesegs); + cookie->id_bouncebuflen = 0; + cookie->id_nbouncesegs = 0; + } else { + cookie->id_flags |= ID_HAS_BOUNCE; + STAT_INCR(isa_dma_stats_nbouncebufs); + } + + return (error); +} + +void +_isa_dma_free_bouncebuf(t, map) + bus_dma_tag_t t; + bus_dmamap_t map; +{ + struct i386_isa_dma_cookie *cookie = map->_dm_cookie; + + STAT_DECR(isa_dma_stats_nbouncebufs); + + _isa_bus_dmamem_unmap(t, cookie->id_bouncebuf, + cookie->id_bouncebuflen); + _isa_bus_dmamem_free(t, cookie->id_bouncesegs, + cookie->id_nbouncesegs); + cookie->id_bouncebuflen = 0; + cookie->id_nbouncesegs = 0; + cookie->id_flags &= ~ID_HAS_BOUNCE; +} +#endif /* NISADMA > 0 */ diff --git a/sys/arch/amd64/pci/pchb.c b/sys/arch/amd64/pci/pchb.c new file mode 100644 index 00000000000..4d1b614d7b3 --- /dev/null +++ b/sys/arch/amd64/pci/pchb.c @@ -0,0 +1,130 @@ +/* $OpenBSD: pchb.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pchb.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ + +/*- + * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> + +#include <dev/pci/pcidevs.h> + +#include <arch/amd64/pci/pchbvar.h> + +#define PCISET_BRIDGETYPE_MASK 0x3 +#define PCISET_TYPE_COMPAT 0x1 +#define PCISET_TYPE_AUX 0x2 + +#define PCISET_BUSCONFIG_REG 0x48 +#define PCISET_BRIDGE_NUMBER(reg) (((reg) >> 8) & 0xff) +#define PCISET_PCI_BUS_NUMBER(reg) (((reg) >> 16) & 0xff) + +/* XXX should be in dev/ic/i82443reg.h */ +#define I82443BX_SDRAMC_REG 0x76 + +/* XXX should be in dev/ic/i82424{reg.var}.h */ +#define I82424_CPU_BCTL_REG 0x53 +#define I82424_PCI_BCTL_REG 0x54 + +#define I82424_BCTL_CPUMEM_POSTEN 0x01 +#define I82424_BCTL_CPUPCI_POSTEN 0x02 +#define I82424_BCTL_PCIMEM_BURSTEN 0x01 +#define I82424_BCTL_PCI_BURSTEN 0x02 + +int pchbmatch __P((struct device *, void *, void *)); +void pchbattach __P((struct device *, struct device *, void *)); + +int pchb_print __P((void *, const char *)); + +struct cfattach pchb_ca = { + sizeof(struct pchb_softc), pchbmatch, pchbattach, +}; + +struct cfdriver pchb_cd = { + NULL, "pchb", DV_DULL +}; + +int +pchbmatch(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct pci_attach_args *pa = aux; + + if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && + PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST) { + return (1); + } + + return (0); +} + +void +pchbattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct pci_attach_args *pa = aux; + + printf("\n"); + + switch (PCI_VENDOR(pa->pa_id)) { + /* Nothing yet */ + default: + break; + } + +} + +int +pchb_print(aux, pnp) + void *aux; + const char *pnp; +{ + struct pcibus_attach_args *pba = aux; + + if (pnp) + printf("%s at %s", pba->pba_busname, pnp); + printf(" bus %d", pba->pba_bus); + return (UNCONF); +} diff --git a/sys/arch/amd64/pci/pchbvar.h b/sys/arch/amd64/pci/pchbvar.h new file mode 100644 index 00000000000..9e573bb97e3 --- /dev/null +++ b/sys/arch/amd64/pci/pchbvar.h @@ -0,0 +1,61 @@ +/* $NetBSD: pchbvar.h,v 1.1 2003/04/26 18:39:51 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + */ + +#ifndef _I386_PCI_PCHBVAR_H_ +#define _I386_PCI_PCHBVAR_H_ + +#include <sys/timeout.h> + +struct pchb_softc { + struct device sc_dev; + + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + +#if 0 + struct callout sc_rnd_ch; + rndsource_element_t sc_rnd_source; +#endif + + int sc_rnd_i; + u_int32_t sc_rnd_ax; +}; + +void pchb_attach_rnd(struct pchb_softc *, struct pci_attach_args *); + +#endif /* _I386_PCI_PCHBVAR_H_ */ diff --git a/sys/arch/amd64/pci/pci_machdep.c b/sys/arch/amd64/pci/pci_machdep.c new file mode 100644 index 00000000000..138afc1ba23 --- /dev/null +++ b/sys/arch/amd64/pci/pci_machdep.c @@ -0,0 +1,693 @@ +/* $OpenBSD: pci_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */ + +/*- + * Copyright (c) 1997, 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. + * + * 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) 1996 Christopher G. Demetriou. All rights reserved. + * Copyright (c) 1994 Charles M. Hannum. 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +/* + * Machine-specific functions for PCI autoconfiguration. + * + * On PCs, there are two methods of generating PCI configuration cycles. + * We try to detect the appropriate mechanism for this machine and set + * up a few function pointers to access the correct method directly. + * + * The configuration method can be hard-coded in the config file by + * using `options PCI_CONF_MODE=N', where `N' is the configuration mode + * as defined section 3.6.4.1, `Generating Configuration Cycles'. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/device.h> +#include <sys/lock.h> + +#include <uvm/uvm_extern.h> + +#define _X86_BUS_DMA_PRIVATE +#include <machine/bus.h> + +#include <machine/pio.h> +#include <machine/intr.h> + +#include <dev/isa/isareg.h> +#include <dev/isa/isavar.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> + +#include "ioapic.h" + +#if NIOAPIC > 0 +#include <machine/i82093var.h> +#include <machine/mpbiosvar.h> +#endif + +int pci_mode = -1; + +#ifdef MULTIPROCESSOR +struct simplelock pci_conf_slock = SIMPLELOCK_INITIALIZER; +#else +struct simplelock pci_conf_slock = { 0 }; +#endif + +#define PCI_CONF_LOCK(s) \ +do { \ + (s) = splhigh(); \ + simple_lock(&pci_conf_slock); \ +} while (0) + +#define PCI_CONF_UNLOCK(s) \ +do { \ + simple_unlock(&pci_conf_slock); \ + splx((s)); \ +} while (0) + +#define PCI_MODE1_ENABLE 0x80000000UL +#define PCI_MODE1_ADDRESS_REG 0x0cf8 +#define PCI_MODE1_DATA_REG 0x0cfc + +#define PCI_MODE2_ENABLE_REG 0x0cf8 +#define PCI_MODE2_FORWARD_REG 0x0cfa + +#define PCI_ID_CODE(vid,pid) \ + ((((vid) & PCI_VENDOR_MASK) << PCI_VENDOR_SHIFT) | \ + (((pid) & PCI_PRODUCT_MASK) << PCI_PRODUCT_SHIFT)) \ + +#define _m1tag(b, d, f) \ + (PCI_MODE1_ENABLE | ((b) << 16) | ((d) << 11) | ((f) << 8)) +#define _qe(bus, dev, fcn, vend, prod) \ + {_m1tag(bus, dev, fcn), PCI_ID_CODE(vend, prod)} +struct { + u_int32_t tag; + pcireg_t id; +} pcim1_quirk_tbl[] = { + _qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX1), + /* XXX Triflex2 not tested */ + _qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX2), + _qe(0, 0, 0, PCI_VENDOR_COMPAQ, PCI_PRODUCT_COMPAQ_TRIFLEX4), + /* Triton needed for Connectix Virtual PC */ + _qe(0, 0, 0, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82437FX), + /* Connectix Virtual PC 5 has a 440BX */ + _qe(0, 0, 0, PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82443BX_NOAGP), + {0, 0xffffffff} /* patchable */ +}; +#undef _m1tag +#undef _id +#undef _qe + +/* + * PCI doesn't have any special needs; just use the generic versions + * of these functions. + */ +struct x86_bus_dma_tag pci_bus_dma_tag = { + NULL, /* _may_bounce */ + _bus_dmamap_create, + _bus_dmamap_destroy, + _bus_dmamap_load, + _bus_dmamap_load_mbuf, + _bus_dmamap_load_uio, + _bus_dmamap_load_raw, + _bus_dmamap_unload, + NULL, + _bus_dmamem_alloc, + _bus_dmamem_free, + _bus_dmamem_map, + _bus_dmamem_unmap, + _bus_dmamem_mmap, +}; + +void +pci_attach_hook(parent, self, pba) + struct device *parent, *self; + struct pcibus_attach_args *pba; +{ + + if (pba->pba_bus == 0) + printf(": configuration mode %d", pci_mode); +} + +int +pci_bus_maxdevs(pc, busno) + pci_chipset_tag_t pc; + int busno; +{ + + /* + * Bus number is irrelevant. If Configuration Mechanism 2 is in + * use, can only have devices 0-15 on any bus. If Configuration + * Mechanism 1 is in use, can have devices 0-32 (i.e. the `normal' + * range). + */ + if (pci_mode == 2) + return (16); + else + return (32); +} + +pcitag_t +pci_make_tag(pc, bus, device, function) + pci_chipset_tag_t pc; + int bus, device, function; +{ + pcitag_t tag; + +#ifndef PCI_CONF_MODE + switch (pci_mode) { + case 1: + goto mode1; + case 2: + goto mode2; + default: + panic("pci_make_tag: mode not configured"); + } +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1) +#ifndef PCI_CONF_MODE +mode1: +#endif + if (bus >= 256 || device >= 32 || function >= 8) + panic("pci_make_tag: bad request"); + + tag.mode1 = PCI_MODE1_ENABLE | + (bus << 16) | (device << 11) | (function << 8); + return tag; +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2) +#ifndef PCI_CONF_MODE +mode2: +#endif + if (bus >= 256 || device >= 16 || function >= 8) + panic("pci_make_tag: bad request"); + + tag.mode2.port = 0xc000 | (device << 8); + tag.mode2.enable = 0xf0 | (function << 1); + tag.mode2.forward = bus; + return tag; +#endif +} + +void +pci_decompose_tag(pc, tag, bp, dp, fp) + pci_chipset_tag_t pc; + pcitag_t tag; + int *bp, *dp, *fp; +{ + +#ifndef PCI_CONF_MODE + switch (pci_mode) { + case 1: + goto mode1; + case 2: + goto mode2; + default: + panic("pci_decompose_tag: mode not configured"); + } +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1) +#ifndef PCI_CONF_MODE +mode1: +#endif + if (bp != NULL) + *bp = (tag.mode1 >> 16) & 0xff; + if (dp != NULL) + *dp = (tag.mode1 >> 11) & 0x1f; + if (fp != NULL) + *fp = (tag.mode1 >> 8) & 0x7; + return; +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2) +#ifndef PCI_CONF_MODE +mode2: +#endif + if (bp != NULL) + *bp = tag.mode2.forward & 0xff; + if (dp != NULL) + *dp = (tag.mode2.port >> 8) & 0xf; + if (fp != NULL) + *fp = (tag.mode2.enable >> 1) & 0x7; +#endif +} + +pcireg_t +pci_conf_read(pc, tag, reg) + pci_chipset_tag_t pc; + pcitag_t tag; + int reg; +{ + pcireg_t data; + int s; + +#ifndef PCI_CONF_MODE + switch (pci_mode) { + case 1: + goto mode1; + case 2: + goto mode2; + default: + panic("pci_conf_read: mode not configured"); + } +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1) +#ifndef PCI_CONF_MODE +mode1: +#endif + PCI_CONF_LOCK(s); + outl(PCI_MODE1_ADDRESS_REG, tag.mode1 | reg); + data = inl(PCI_MODE1_DATA_REG); + outl(PCI_MODE1_ADDRESS_REG, 0); + PCI_CONF_UNLOCK(s); + return data; +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2) +#ifndef PCI_CONF_MODE +mode2: +#endif + PCI_CONF_LOCK(s); + outb(PCI_MODE2_ENABLE_REG, tag.mode2.enable); + outb(PCI_MODE2_FORWARD_REG, tag.mode2.forward); + data = inl(tag.mode2.port | reg); + outb(PCI_MODE2_ENABLE_REG, 0); + PCI_CONF_UNLOCK(s); + return data; +#endif +} + +void +pci_conf_write(pc, tag, reg, data) + pci_chipset_tag_t pc; + pcitag_t tag; + int reg; + pcireg_t data; +{ + int s; + +#ifndef PCI_CONF_MODE + switch (pci_mode) { + case 1: + goto mode1; + case 2: + goto mode2; + default: + panic("pci_conf_write: mode not configured"); + } +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 1) +#ifndef PCI_CONF_MODE +mode1: +#endif + PCI_CONF_LOCK(s); + outl(PCI_MODE1_ADDRESS_REG, tag.mode1 | reg); + outl(PCI_MODE1_DATA_REG, data); + outl(PCI_MODE1_ADDRESS_REG, 0); + PCI_CONF_UNLOCK(s); + return; +#endif + +#if !defined(PCI_CONF_MODE) || (PCI_CONF_MODE == 2) +#ifndef PCI_CONF_MODE +mode2: +#endif + PCI_CONF_LOCK(s); + outb(PCI_MODE2_ENABLE_REG, tag.mode2.enable); + outb(PCI_MODE2_FORWARD_REG, tag.mode2.forward); + outl(tag.mode2.port | reg, data); + outb(PCI_MODE2_ENABLE_REG, 0); + PCI_CONF_UNLOCK(s); +#endif +} + +int +pci_mode_detect() +{ + +#ifdef PCI_CONF_MODE +#if (PCI_CONF_MODE == 1) || (PCI_CONF_MODE == 2) + return (pci_mode = PCI_CONF_MODE); +#else +#error Invalid PCI configuration mode. +#endif +#else + u_int32_t sav, val; + int i; + pcireg_t idreg; + + if (pci_mode != -1) + return pci_mode; + + /* + * We try to divine which configuration mode the host bridge wants. + */ + + sav = inl(PCI_MODE1_ADDRESS_REG); + + pci_mode = 1; /* assume this for now */ + /* + * catch some known buggy implementations of mode 1 + */ + for (i = 0; i < sizeof(pcim1_quirk_tbl) / sizeof(pcim1_quirk_tbl[0]); + i++) { + pcitag_t t; + + if (!pcim1_quirk_tbl[i].tag) + break; + t.mode1 = pcim1_quirk_tbl[i].tag; + idreg = pci_conf_read(0, t, PCI_ID_REG); /* needs "pci_mode" */ + if (idreg == pcim1_quirk_tbl[i].id) { +#ifdef DEBUG + printf("known mode 1 PCI chipset (%08x)\n", + idreg); +#endif + return (pci_mode); + } + } + + /* + * Strong check for standard compliant mode 1: + * 1. bit 31 ("enable") can be set + * 2. byte/word access does not affect register + */ + outl(PCI_MODE1_ADDRESS_REG, PCI_MODE1_ENABLE); + outb(PCI_MODE1_ADDRESS_REG + 3, 0); + outw(PCI_MODE1_ADDRESS_REG + 2, 0); + val = inl(PCI_MODE1_ADDRESS_REG); + if ((val & 0x80fffffc) != PCI_MODE1_ENABLE) { +#ifdef DEBUG + printf("pci_mode_detect: mode 1 enable failed (%x)\n", + val); +#endif + goto not1; + } + outl(PCI_MODE1_ADDRESS_REG, 0); + val = inl(PCI_MODE1_ADDRESS_REG); + if ((val & 0x80fffffc) != 0) + goto not1; + return (pci_mode); +not1: + outl(PCI_MODE1_ADDRESS_REG, sav); + + /* + * This mode 2 check is quite weak (and known to give false + * positives on some Compaq machines). + * However, this doesn't matter, because this is the + * last test, and simply no PCI devices will be found if + * this happens. + */ + outb(PCI_MODE2_ENABLE_REG, 0); + outb(PCI_MODE2_FORWARD_REG, 0); + if (inb(PCI_MODE2_ENABLE_REG) != 0 || + inb(PCI_MODE2_FORWARD_REG) != 0) + goto not2; + return (pci_mode = 2); +not2: + + return (pci_mode = 0); +#endif +} + +int +pci_intr_map(pa, ihp) + struct pci_attach_args *pa; + pci_intr_handle_t *ihp; +{ + int pin = pa->pa_intrpin; + int line = pa->pa_intrline; +#if NIOAPIC > 0 + int rawpin = pa->pa_rawintrpin; + pci_chipset_tag_t pc = pa->pa_pc; + int bus, dev, func; +#endif + + if (pin == 0) { + /* No IRQ used. */ + goto bad; + } + + if (pin > PCI_INTERRUPT_PIN_MAX) { + printf("pci_intr_map: bad interrupt pin %d\n", pin); + goto bad; + } + +#if NIOAPIC > 0 + pci_decompose_tag(pc, pa->pa_tag, &bus, &dev, &func); + if (mp_busses != NULL) { + if (intr_find_mpmapping(bus, (dev<<2)|(rawpin-1), ihp) == 0) { + *ihp |= line; + return 0; + } + /* + * No explicit PCI mapping found. This is not fatal, + * we'll try the ISA (or possibly EISA) mappings next. + */ + } +#endif + + /* + * Section 6.2.4, `Miscellaneous Functions', says that 255 means + * `unknown' or `no connection' on a PC. We assume that a device with + * `no connection' either doesn't have an interrupt (in which case the + * pin number should be 0, and would have been noticed above), or + * wasn't configured by the BIOS (in which case we punt, since there's + * no real way we can know how the interrupt lines are mapped in the + * hardware). + * + * XXX + * Since IRQ 0 is only used by the clock, and we can't actually be sure + * that the BIOS did its job, we also recognize that as meaning that + * the BIOS has not configured the device. + */ + if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION) { + printf("pci_intr_map: no mapping for pin %c (line=%02x)\n", + '@' + pin, line); + goto bad; + } else { + if (line >= NUM_LEGACY_IRQS) { + printf("pci_intr_map: bad interrupt line %d\n", line); + goto bad; + } + if (line == 2) { + printf("pci_intr_map: changed line 2 to line 9\n"); + line = 9; + } + } +#if NIOAPIC > 0 + if (mp_busses != NULL) { + if (intr_find_mpmapping(mp_isa_bus, line, ihp) == 0) { + *ihp |= line; + return 0; + } +#if NEISA > 0 + if (intr_find_mpmapping(mp_eisa_bus, line, ihp) == 0) { + *ihp |= line; + return 0; + } +#endif + printf("pci_intr_map: bus %d dev %d func %d pin %d; line %d\n", + bus, dev, func, pin, line); + printf("pci_intr_map: no MP mapping found\n"); + } +#endif + + *ihp = line; + return 0; + +bad: + *ihp = -1; + return 1; +} + +const char * +pci_intr_string(pc, ih) + pci_chipset_tag_t pc; + pci_intr_handle_t ih; +{ + static char irqstr[64]; + + if (ih == 0) + panic("pci_intr_string: bogus handle 0x%x", ih); + + +#if NIOAPIC > 0 + if (ih & APIC_INT_VIA_APIC) + snprintf(irqstr, sizeof(irqstr), "apic %d int %d (irq %d)", + APIC_IRQ_APIC(ih), + APIC_IRQ_PIN(ih), + ih&0xff); + else + snprintf(irqstr, sizeof(irqstr), "irq %d", ih&0xff); +#else + + snprintf(irqstr, sizeof(irqstr), "irq %d", ih&0xff); +#endif + return (irqstr); + +} + +const struct evcnt * +pci_intr_evcnt(pc, ih) + pci_chipset_tag_t pc; + pci_intr_handle_t ih; +{ + + /* XXX for now, no evcnt parent reported */ + return NULL; +} + +void * +pci_intr_establish(pc, ih, level, func, arg, what) + pci_chipset_tag_t pc; + pci_intr_handle_t ih; + int level, (*func)(void *); + void *arg; + char *what; +{ + int pin, irq; + struct pic *pic; + + pic = &i8259_pic; + pin = irq = ih; + +#if NIOAPIC > 0 + if (ih & APIC_INT_VIA_APIC) { + pic = (struct pic *)ioapic_find(APIC_IRQ_APIC(ih)); + if (pic == NULL) { + printf("pci_intr_establish: bad ioapic %d\n", + APIC_IRQ_APIC(ih)); + return NULL; + } + pin = APIC_IRQ_PIN(ih); + irq = APIC_IRQ_LEGACY_IRQ(ih); + if (irq < 0 || irq >= NUM_LEGACY_IRQS) + irq = -1; + } +#endif + + return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg); +} + +void +pci_intr_disestablish(pc, cookie) + pci_chipset_tag_t pc; + void *cookie; +{ + + intr_disestablish(cookie); +} + +/* + * Determine which flags should be passed to the primary PCI bus's + * autoconfiguration node. We use this to detect broken chipsets + * which cannot safely use memory-mapped device access. + */ +int +pci_bus_flags() +{ + int rval = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED; + int device, maxndevs; + pcitag_t tag; + pcireg_t id; + + maxndevs = pci_bus_maxdevs(NULL, 0); + + for (device = 0; device < maxndevs; device++) { + tag = pci_make_tag(NULL, 0, device, 0); + id = pci_conf_read(NULL, tag, PCI_ID_REG); + + /* Invalid vendor ID value? */ + if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) + continue; + /* XXX Not invalid, but we've done this ~forever. */ + if (PCI_VENDOR(id) == 0) + continue; + + switch (PCI_VENDOR(id)) { + case PCI_VENDOR_SIS: + switch (PCI_PRODUCT(id)) { + case PCI_PRODUCT_SIS_85C496: + goto disable_mem; + } + break; + } + } + + return (rval); + + disable_mem: + printf("Warning: broken PCI-Host bridge detected; " + "disabling memory-mapped access\n"); + rval &= ~(PCI_FLAGS_MEM_ENABLED); + return (rval); +} diff --git a/sys/arch/amd64/pci/pciide_machdep.c b/sys/arch/amd64/pci/pciide_machdep.c new file mode 100644 index 00000000000..9b24cf40032 --- /dev/null +++ b/sys/arch/amd64/pci/pciide_machdep.c @@ -0,0 +1,76 @@ +/* $OpenBSD: pciide_machdep.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $NetBSD: pciide_machdep.c,v 1.2 1999/02/19 18:01:27 mycroft Exp $ */ + +/* + * Copyright (c) 1998 Christopher G. Demetriou. 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 Christopher G. Demetriou + * for the NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +/* + * PCI IDE controller driver (i386 machine-dependent portion). + * + * Author: Christopher G. Demetriou, March 2, 1998 (derived from NetBSD + * sys/dev/pci/ppb.c, revision 1.16). + * + * See "PCI IDE Controller Specification, Revision 1.0 3/4/94" from the + * PCI SIG. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pciidereg.h> +#include <dev/pci/pciidevar.h> + +#include <dev/isa/isavar.h> + +void * +pciide_machdep_compat_intr_establish(dev, pa, chan, func, arg) + struct device *dev; + struct pci_attach_args *pa; + int chan; + int (*func)(void *); + void *arg; +{ + int irq; + void *cookie; + + irq = PCIIDE_COMPAT_IRQ(chan); + cookie = isa_intr_establish(NULL, irq, IST_EDGE, IPL_BIO, func, arg, dev->dv_xname); + + return (cookie); +} + +void +pciide_machdep_compat_intr_disestablish(pci_chipset_tag_t pc, void *cookie) +{ + isa_intr_disestablish(NULL, cookie); +} diff --git a/sys/compat/common/Makefile b/sys/compat/common/Makefile index 49e3098dc34..2fdb75cea90 100644 --- a/sys/compat/common/Makefile +++ b/sys/compat/common/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.14 2003/06/24 22:45:33 espie Exp $ +# $OpenBSD: Makefile,v 1.15 2004/01/28 01:39:39 mickey Exp $ # $NetBSD: Makefile,v 1.8 1996/05/18 15:52:19 christos Exp $ LIB= compat @@ -15,7 +15,8 @@ SRCS= compat_exec.c compat_util.c compat_dir.c compat_vm.c \ vfs_syscalls_25.c vfs_syscalls_43.c vm_43.c # really, all machines where sizeof(int) != sizeof(long) -.if (${MACHINE_ARCH} != "alpha") && (${MACHINE_ARCH} != "sparc64") +.if (${MACHINE_ARCH} != "alpha") && (${MACHINE_ARCH} != "x86_64") && \ + (${MACHINE_ARCH} != "sparc64") SRCS+= kern_ipc_10.c .endif diff --git a/sys/dev/isa/isavar.h b/sys/dev/isa/isavar.h index 2289499bdb2..107ee3c3e35 100644 --- a/sys/dev/isa/isavar.h +++ b/sys/dev/isa/isavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: isavar.h,v 1.47 2004/01/15 17:51:42 miod Exp $ */ +/* $OpenBSD: isavar.h,v 1.48 2004/01/28 01:39:39 mickey Exp $ */ /* $NetBSD: isavar.h,v 1.26 1997/06/06 23:43:57 thorpej Exp $ */ /*- @@ -122,7 +122,7 @@ */ struct isabus_attach_args; -#if (__alpha__ + amiga + __i386__ + arc + __wgrisc__ + __powerpc__ + __hppa__ != 1) +#if (__alpha__ + amiga + __i386__ + arc + __wgrisc__ + __powerpc__ + __hppa__ + __amd64__ != 1) #error "COMPILING ISA FOR UNSUPPORTED MACHINE, OR MORE THAN ONE." #endif #ifdef __alpha__ @@ -150,6 +150,9 @@ struct isabus_attach_args; #ifdef __hppa__ #include <hppa/include/isa_machdep.h> #endif +#ifdef __amd64__ +#include <amd64/include/isa_machdep.h> +#endif #include "isapnp.h" diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index 7148650ffad..29cda47f461 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcivar.h,v 1.33 2003/12/12 22:56:46 hshoexer Exp $ */ +/* $OpenBSD: pcivar.h,v 1.34 2004/01/28 01:39:40 mickey Exp $ */ /* $NetBSD: pcivar.h,v 1.23 1997/06/06 23:48:05 thorpej Exp $ */ /* @@ -54,7 +54,7 @@ struct pcibus_attach_args; /* * Machine-dependent definitions. */ -#if (__alpha__ + __atari__ + __i386__ + __arc__ + __powerpc__ + __galileo__ + __sparc64__ + __hppa__ != 1) +#if (__alpha__ + __atari__ + __i386__ + __arc__ + __powerpc__ + __galileo__ + __sparc64__ + __hppa__ +__amd64__ != 1) #error COMPILING FOR UNSUPPORTED MACHINE, OR MORE THAN ONE. #endif #if __alpha__ @@ -81,6 +81,9 @@ struct pcibus_attach_args; #if __sparc64__ #include <sparc64/include/pci_machdep.h> #endif +#if __amd64__ +#include <amd64/include/pci_machdep.h> +#endif /* * PCI bus attach arguments. diff --git a/sys/lib/libkern/arch/amd64/Makefile.inc b/sys/lib/libkern/arch/amd64/Makefile.inc new file mode 100644 index 00000000000..ed61f7015e9 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/Makefile.inc @@ -0,0 +1,14 @@ +# $NetBSD: Makefile.inc,v 1.2 2002/11/25 00:55:22 fvdl Exp $ + +SRCS+= imax.c imin.c lmax.c lmin.c max.c min.c ulmax.c ulmin.c \ + byte_swap_2.S byte_swap_4.S \ + bcmp.S bcopy.S bzero.S ffs.S \ + memchr.S memcmp.S memcpy.S memmove.S memset.S \ + ovbcopy.S \ + strcat.S strchr.S strcmp.S \ + strcpy.S strlcpy.c strlcat.c strlen.S \ + strncasecmp.c strncmp.c strncpy.c strrchr.S \ + scanc.S skpc.S random.c +# bswap64.c strcasecmp.c strncasecmp.c \ strtoul.c \ + +CFLAGS+=-mcmodel=kernel diff --git a/sys/lib/libkern/arch/amd64/bcmp.S b/sys/lib/libkern/arch/amd64/bcmp.S new file mode 100644 index 00000000000..5cee3afe74b --- /dev/null +++ b/sys/lib/libkern/arch/amd64/bcmp.S @@ -0,0 +1,24 @@ +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bcmp.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +ENTRY(bcmp) + xorl %eax,%eax /* clear return value */ + cld /* set compare direction forward */ + + movq %rdx,%rcx /* compare by words */ + shrq $3,%rcx + repe + cmpsq + jne L1 + + movq %rdx,%rcx /* compare remainder by bytes */ + andq $7,%rcx + repe + cmpsb + je L2 + +L1: incl %eax +L2: ret diff --git a/sys/lib/libkern/arch/amd64/bcopy.S b/sys/lib/libkern/arch/amd64/bcopy.S new file mode 100644 index 00000000000..c741cd66ca1 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/bcopy.S @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from locore.s. + * + * 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. + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bcopy.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + + /* + * (ov)bcopy (src,dst,cnt) + * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 + */ + +#ifdef MEMCOPY +ENTRY(memcpy) +#else +#ifdef MEMMOVE +ENTRY(memmove) +#else +#ifdef OVBCOPY +ENTRY(ovbcopy) +#else +ENTRY(bcopy) +#endif +#endif +#endif +#if defined(MEMCOPY) || defined(MEMMOVE) + movq %rdi,%r11 /* save dest */ +#else + xchgq %rdi,%rsi +#endif + movq %rdx,%rcx + movq %rdi,%rax + subq %rsi,%rax + cmpq %rcx,%rax /* overlapping? */ + jb 1f + cld /* nope, copy forwards. */ + shrq $3,%rcx /* copy by words */ + rep + movsq + movq %rdx,%rcx + andq $7,%rcx /* any bytes left? */ + rep + movsb +#if defined(MEMCOPY) || defined(MEMMOVE) + movq %r11,%rax +#endif + ret +1: + addq %rcx,%rdi /* copy backwards. */ + addq %rcx,%rsi + std + andq $7,%rcx /* any fractional bytes? */ + decq %rdi + decq %rsi + rep + movsb + movq %rdx,%rcx /* copy remainder by words */ + shrq $3,%rcx + subq $7,%rsi + subq $7,%rdi + rep + movsq +#if defined(MEMCOPY) || defined(MEMMOVE) + movq %r11,%rax +#endif + cld + ret diff --git a/sys/lib/libkern/arch/amd64/byte_swap_2.S b/sys/lib/libkern/arch/amd64/byte_swap_2.S new file mode 100644 index 00000000000..19ed5e27812 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/byte_swap_2.S @@ -0,0 +1,52 @@ +/* $NetBSD: byte_swap_2.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $ */ + +/*- + * Copyright (c) 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: @(#)htons.s 5.2 (Berkeley) 12/17/90 + */ + +#include <machine/asm.h> +#if defined(LIBC_SCCS) + RCSID("$NetBSD: byte_swap_2.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +_ENTRY(_C_LABEL(bswap16)) +_ENTRY(_C_LABEL(ntohs)) +_ENTRY(_C_LABEL(htons)) +_PROF_PROLOGUE + movl %edi,%eax + xchgb %ah,%al + ret diff --git a/sys/lib/libkern/arch/amd64/byte_swap_4.S b/sys/lib/libkern/arch/amd64/byte_swap_4.S new file mode 100644 index 00000000000..f6a961e38f5 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/byte_swap_4.S @@ -0,0 +1,52 @@ +/* $NetBSD: byte_swap_4.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $ */ + +/*- + * Copyright (c) 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: @(#)htonl.s 5.3 (Berkeley) 12/17/90 + */ + +#include <machine/asm.h> +#if defined(LIBC_SCCS) + RCSID("$NetBSD: byte_swap_4.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +_ENTRY(_C_LABEL(bswap32)) +_ENTRY(_C_LABEL(ntohl)) +_ENTRY(_C_LABEL(htonl)) +_PROF_PROLOGUE + movl %edi,%eax + bswap %eax + ret diff --git a/sys/lib/libkern/arch/amd64/bzero.S b/sys/lib/libkern/arch/amd64/bzero.S new file mode 100644 index 00000000000..6e4fe834d1a --- /dev/null +++ b/sys/lib/libkern/arch/amd64/bzero.S @@ -0,0 +1,44 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bzero.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +ENTRY(bzero) + movq %rsi,%rdx + + cld /* set fill direction forward */ + xorq %rax,%rax /* set fill data to 0 */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpq $16,%rdx + jb L1 + + movq %rdi,%rcx /* compute misalignment */ + negq %rcx + andq $7,%rcx + subq %rcx,%rdx + rep /* zero until word aligned */ + stosb + + movq %rdx,%rcx /* zero by words */ + shrq $3,%rcx + andq $7,%rdx + rep + stosq + +L1: movq %rdx,%rcx /* zero remainder by bytes */ + rep + stosb + + ret diff --git a/sys/lib/libkern/arch/amd64/ffs.S b/sys/lib/libkern/arch/amd64/ffs.S new file mode 100644 index 00000000000..c74c7010f54 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/ffs.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: ffs.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(ffs) + bsfl %edi,%eax + jz L1 /* ZF is set if all bits are 0 */ + incl %eax /* bits numbered from 1, not 0 */ + ret + + _ALIGN_TEXT +L1: xorl %eax,%eax /* clear result */ + ret diff --git a/sys/lib/libkern/arch/amd64/index.S b/sys/lib/libkern/arch/amd64/index.S new file mode 100644 index 00000000000..60754f266f0 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/index.S @@ -0,0 +1,29 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: index.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +#ifdef STRCHR +ENTRY(strchr) +#else +ENTRY(index) +#endif + movq %rdi,%rax + movb %sil,%cl +L1: + movb (%rax),%dl + cmpb %dl,%cl /* found char? */ + je L2 + incq %rax + testb %dl,%dl /* null terminator? */ + jnz L1 + xorq %rax,%rax +L2: + ret diff --git a/sys/lib/libkern/arch/amd64/memchr.S b/sys/lib/libkern/arch/amd64/memchr.S new file mode 100644 index 00000000000..f978e760220 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/memchr.S @@ -0,0 +1,25 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: memchr.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(memchr) + movb %sil,%al /* set character to search for */ + movq %rdx,%rcx /* set length of search */ + testq %rcx,%rcx /* test for len == 0 */ + jz L1 + cld /* set search forward */ + repne /* search! */ + scasb + jne L1 /* scan failed, return null */ + leaq -1(%rdi),%rax /* adjust result of scan */ + ret +L1: xorq %rax,%rax + ret diff --git a/sys/lib/libkern/arch/amd64/memcmp.S b/sys/lib/libkern/arch/amd64/memcmp.S new file mode 100644 index 00000000000..722a2a2c304 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/memcmp.S @@ -0,0 +1,40 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: memcmp.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(memcmp) + cld /* set compare direction forward */ + movq %rdx,%rcx /* compare by longs */ + shrq $3,%rcx + repe + cmpsq + jne L5 /* do we match so far? */ + + movq %rdx,%rcx /* compare remainder by bytes */ + andq $7,%rcx + repe + cmpsb + jne L6 /* do we match? */ + + xorl %eax,%eax /* we match, return zero */ + ret + +L5: movl $8,%ecx /* We know that one of the next */ + subq %rcx,%rdi /* eight pairs of bytes do not */ + subq %rcx,%rsi /* match. */ + repe + cmpsb +L6: xorl %eax,%eax /* Perform unsigned comparison */ + movb -1(%rdi),%al + xorl %edx,%edx + movb -1(%rsi),%dl + subl %edx,%eax + ret diff --git a/sys/lib/libkern/arch/amd64/memcpy.S b/sys/lib/libkern/arch/amd64/memcpy.S new file mode 100644 index 00000000000..c39caa328a3 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/memcpy.S @@ -0,0 +1,4 @@ +/* $NetBSD: memcpy.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $ */ + +#define MEMCOPY +#include "bcopy.S" diff --git a/sys/lib/libkern/arch/amd64/memmove.S b/sys/lib/libkern/arch/amd64/memmove.S new file mode 100644 index 00000000000..f5b81357afa --- /dev/null +++ b/sys/lib/libkern/arch/amd64/memmove.S @@ -0,0 +1,4 @@ +/* $NetBSD: memmove.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $ */ + +#define MEMMOVE +#include "bcopy.S" diff --git a/sys/lib/libkern/arch/amd64/memset.S b/sys/lib/libkern/arch/amd64/memset.S new file mode 100644 index 00000000000..2d92dc66534 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/memset.S @@ -0,0 +1,58 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: memset.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(memset) + movq %rsi,%rax + movq %rdx,%rcx + movq %rdi,%r11 + + cld /* set fill direction forward */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpq $0x0f,%rcx + jle L1 + + movb %al,%ah /* copy char to all bytes in word */ + movl %eax,%edx + sall $16,%eax + orl %edx,%eax + + movl %eax,%edx + salq $32,%rax + orq %rdx,%rax + + movq %rdi,%rdx /* compute misalignment */ + negq %rdx + andq $7,%rdx + movq %rcx,%r8 + subq %rdx,%r8 + + movq %rdx,%rcx /* set until word aligned */ + rep + stosb + + movq %r8,%rcx + shrq $3,%rcx /* set by words */ + rep + stosq + + movq %r8,%rcx /* set remainder by bytes */ + andq $7,%rcx +L1: rep + stosb + movq %r11,%rax + + ret diff --git a/sys/lib/libkern/arch/amd64/ovbcopy.S b/sys/lib/libkern/arch/amd64/ovbcopy.S new file mode 100644 index 00000000000..71f2c9c8ddc --- /dev/null +++ b/sys/lib/libkern/arch/amd64/ovbcopy.S @@ -0,0 +1,4 @@ +/* $NetBSD: memmove.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $ */ + +#define OVBCOPY +#include "bcopy.S" diff --git a/sys/lib/libkern/arch/amd64/rindex.S b/sys/lib/libkern/arch/amd64/rindex.S new file mode 100644 index 00000000000..6ba7c52a11f --- /dev/null +++ b/sys/lib/libkern/arch/amd64/rindex.S @@ -0,0 +1,29 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: rindex.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +#ifdef STRRCHR +ENTRY(strrchr) +#else +ENTRY(rindex) +#endif + movb %sil,%cl + xorq %rax,%rax /* init pointer to null */ +L1: + movb (%rdi),%dl + cmpb %dl,%cl + jne L2 + movq %rdi,%rax +L2: + incq %rdi + testb %dl,%dl /* null terminator??? */ + jnz L1 + ret diff --git a/sys/lib/libkern/arch/amd64/scanc.S b/sys/lib/libkern/arch/amd64/scanc.S new file mode 100644 index 00000000000..fd4fd31e129 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/scanc.S @@ -0,0 +1,62 @@ +/* $NetBSD: scanc.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +/* + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +ENTRY(scanc) + movq %rdx,%r11 + movb %cl,%dl + movl %edi,%ecx + testl %ecx,%ecx + jz 2f + movq %r11,%rdi + xorq %rax,%rax + cld +1: + lodsb + testb %dl,(%rax,%rdi) + jnz 2f + decl %ecx + jnz 1b +2: + movl %ecx,%eax + ret diff --git a/sys/lib/libkern/arch/amd64/skpc.S b/sys/lib/libkern/arch/amd64/skpc.S new file mode 100644 index 00000000000..f037d98b66a --- /dev/null +++ b/sys/lib/libkern/arch/amd64/skpc.S @@ -0,0 +1,56 @@ +/* $NetBSD: skpc.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +/* + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +ENTRY(skpc) + movl %edi,%eax + movq %rsi,%rcx + movq %rdx,%rdi + cld + repe + scasb + je 1f + incq %rcx +1: + movl %ecx,%eax + ret diff --git a/sys/lib/libkern/arch/amd64/strcat.S b/sys/lib/libkern/arch/amd64/strcat.S new file mode 100644 index 00000000000..7dc71244312 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/strcat.S @@ -0,0 +1,65 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strcat.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcat) + movq %rdi,%r11 + + cld /* set search forward */ + xorl %eax,%eax /* set search for null terminator */ + movq $-1,%rcx /* set search for lots of characters */ + repne /* search! */ + scasb + + decq %rdi + +L1: movb (%rsi),%al /* unroll loop, but not too much */ + movb %al,(%rdi) + testb %al,%al + jz L2 + movb 1(%rsi),%al + movb %al,1(%rdi) + testb %al,%al + jz L2 + movb 2(%rsi),%al + movb %al,2(%rdi) + testb %al,%al + jz L2 + movb 3(%rsi),%al + movb %al,3(%rdi) + testb %al,%al + jz L2 + movb 4(%rsi),%al + movb %al,4(%rdi) + testb %al,%al + jz L2 + movb 5(%rsi),%al + movb %al,5(%rdi) + testb %al,%al + jz L2 + movb 6(%rsi),%al + movb %al,6(%rdi) + testb %al,%al + jz L2 + movb 7(%rsi),%al + movb %al,7(%rdi) + addq $8,%rsi + addq $8,%rdi + testb %al,%al + jnz L1 +L2: movq %r11,%rax + ret diff --git a/sys/lib/libkern/arch/amd64/strchr.S b/sys/lib/libkern/arch/amd64/strchr.S new file mode 100644 index 00000000000..91fd708891f --- /dev/null +++ b/sys/lib/libkern/arch/amd64/strchr.S @@ -0,0 +1,4 @@ +/* $NetBSD: strchr.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +#define STRCHR +#include "index.S" diff --git a/sys/lib/libkern/arch/amd64/strcmp.S b/sys/lib/libkern/arch/amd64/strcmp.S new file mode 100644 index 00000000000..559563666d4 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/strcmp.S @@ -0,0 +1,88 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strcmp.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcmp) + jmp L2 /* Jump into the loop. */ + +L1: incq %rdi + incq %rsi +L2: movb (%rdi),%cl + testb %cl,%cl /* null terminator */ + jz L3 + cmpb %cl,(%rsi) /* chars match */ + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + je L1 +L3: movzbl (%rdi),%eax /* unsigned comparison */ + movzbl (%rsi),%edx + subl %edx,%eax + ret diff --git a/sys/lib/libkern/arch/amd64/strcpy.S b/sys/lib/libkern/arch/amd64/strcpy.S new file mode 100644 index 00000000000..924dfffd5be --- /dev/null +++ b/sys/lib/libkern/arch/amd64/strcpy.S @@ -0,0 +1,57 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strcpy.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcpy) + movq %rdi,%r11 + +L1: movb (%rsi),%al /* unroll loop, but not too much */ + movb %al,(%rdi) + testb %al,%al + jz L2 + movb 1(%rsi),%al + movb %al,1(%rdi) + testb %al,%al + jz L2 + movb 2(%rsi),%al + movb %al,2(%rdi) + testb %al,%al + jz L2 + movb 3(%rsi),%al + movb %al,3(%rdi) + testb %al,%al + jz L2 + movb 4(%rsi),%al + movb %al,4(%rdi) + testb %al,%al + jz L2 + movb 5(%rsi),%al + movb %al,5(%rdi) + testb %al,%al + jz L2 + movb 6(%rsi),%al + movb %al,6(%rdi) + testb %al,%al + jz L2 + movb 7(%rsi),%al + movb %al,7(%rdi) + addq $8,%rsi + addq $8,%rdi + testb %al,%al + jnz L1 +L2: movq %r11,%rax + ret diff --git a/sys/lib/libkern/arch/amd64/strlen.S b/sys/lib/libkern/arch/amd64/strlen.S new file mode 100644 index 00000000000..3c85659391a --- /dev/null +++ b/sys/lib/libkern/arch/amd64/strlen.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strlen.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +ENTRY(strlen) + cld /* set search forward */ + xorl %eax,%eax /* set search for null terminator */ + movq $-1,%rcx /* set search for lots of characters */ + repne /* search! */ + scasb + notq %rcx /* get length by taking complement */ + leaq -1(%rcx),%rax /* and subtracting one */ + ret diff --git a/sys/lib/libkern/arch/amd64/strrchr.S b/sys/lib/libkern/arch/amd64/strrchr.S new file mode 100644 index 00000000000..9b23edfb435 --- /dev/null +++ b/sys/lib/libkern/arch/amd64/strrchr.S @@ -0,0 +1,4 @@ +/* $NetBSD: strrchr.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +#define STRRCHR +#include "rindex.S" diff --git a/sys/lib/libkern/arch/x86_64/Makefile.inc b/sys/lib/libkern/arch/x86_64/Makefile.inc new file mode 100644 index 00000000000..ed61f7015e9 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/Makefile.inc @@ -0,0 +1,14 @@ +# $NetBSD: Makefile.inc,v 1.2 2002/11/25 00:55:22 fvdl Exp $ + +SRCS+= imax.c imin.c lmax.c lmin.c max.c min.c ulmax.c ulmin.c \ + byte_swap_2.S byte_swap_4.S \ + bcmp.S bcopy.S bzero.S ffs.S \ + memchr.S memcmp.S memcpy.S memmove.S memset.S \ + ovbcopy.S \ + strcat.S strchr.S strcmp.S \ + strcpy.S strlcpy.c strlcat.c strlen.S \ + strncasecmp.c strncmp.c strncpy.c strrchr.S \ + scanc.S skpc.S random.c +# bswap64.c strcasecmp.c strncasecmp.c \ strtoul.c \ + +CFLAGS+=-mcmodel=kernel diff --git a/sys/lib/libkern/arch/x86_64/bcmp.S b/sys/lib/libkern/arch/x86_64/bcmp.S new file mode 100644 index 00000000000..5cee3afe74b --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/bcmp.S @@ -0,0 +1,24 @@ +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bcmp.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +ENTRY(bcmp) + xorl %eax,%eax /* clear return value */ + cld /* set compare direction forward */ + + movq %rdx,%rcx /* compare by words */ + shrq $3,%rcx + repe + cmpsq + jne L1 + + movq %rdx,%rcx /* compare remainder by bytes */ + andq $7,%rcx + repe + cmpsb + je L2 + +L1: incl %eax +L2: ret diff --git a/sys/lib/libkern/arch/x86_64/bcopy.S b/sys/lib/libkern/arch/x86_64/bcopy.S new file mode 100644 index 00000000000..c741cd66ca1 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/bcopy.S @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from locore.s. + * + * 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. + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bcopy.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + + /* + * (ov)bcopy (src,dst,cnt) + * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800 + */ + +#ifdef MEMCOPY +ENTRY(memcpy) +#else +#ifdef MEMMOVE +ENTRY(memmove) +#else +#ifdef OVBCOPY +ENTRY(ovbcopy) +#else +ENTRY(bcopy) +#endif +#endif +#endif +#if defined(MEMCOPY) || defined(MEMMOVE) + movq %rdi,%r11 /* save dest */ +#else + xchgq %rdi,%rsi +#endif + movq %rdx,%rcx + movq %rdi,%rax + subq %rsi,%rax + cmpq %rcx,%rax /* overlapping? */ + jb 1f + cld /* nope, copy forwards. */ + shrq $3,%rcx /* copy by words */ + rep + movsq + movq %rdx,%rcx + andq $7,%rcx /* any bytes left? */ + rep + movsb +#if defined(MEMCOPY) || defined(MEMMOVE) + movq %r11,%rax +#endif + ret +1: + addq %rcx,%rdi /* copy backwards. */ + addq %rcx,%rsi + std + andq $7,%rcx /* any fractional bytes? */ + decq %rdi + decq %rsi + rep + movsb + movq %rdx,%rcx /* copy remainder by words */ + shrq $3,%rcx + subq $7,%rsi + subq $7,%rdi + rep + movsq +#if defined(MEMCOPY) || defined(MEMMOVE) + movq %r11,%rax +#endif + cld + ret diff --git a/sys/lib/libkern/arch/x86_64/byte_swap_2.S b/sys/lib/libkern/arch/x86_64/byte_swap_2.S new file mode 100644 index 00000000000..19ed5e27812 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/byte_swap_2.S @@ -0,0 +1,52 @@ +/* $NetBSD: byte_swap_2.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $ */ + +/*- + * Copyright (c) 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: @(#)htons.s 5.2 (Berkeley) 12/17/90 + */ + +#include <machine/asm.h> +#if defined(LIBC_SCCS) + RCSID("$NetBSD: byte_swap_2.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +_ENTRY(_C_LABEL(bswap16)) +_ENTRY(_C_LABEL(ntohs)) +_ENTRY(_C_LABEL(htons)) +_PROF_PROLOGUE + movl %edi,%eax + xchgb %ah,%al + ret diff --git a/sys/lib/libkern/arch/x86_64/byte_swap_4.S b/sys/lib/libkern/arch/x86_64/byte_swap_4.S new file mode 100644 index 00000000000..f6a961e38f5 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/byte_swap_4.S @@ -0,0 +1,52 @@ +/* $NetBSD: byte_swap_4.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $ */ + +/*- + * Copyright (c) 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: @(#)htonl.s 5.3 (Berkeley) 12/17/90 + */ + +#include <machine/asm.h> +#if defined(LIBC_SCCS) + RCSID("$NetBSD: byte_swap_4.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +_ENTRY(_C_LABEL(bswap32)) +_ENTRY(_C_LABEL(ntohl)) +_ENTRY(_C_LABEL(htonl)) +_PROF_PROLOGUE + movl %edi,%eax + bswap %eax + ret diff --git a/sys/lib/libkern/arch/x86_64/bzero.S b/sys/lib/libkern/arch/x86_64/bzero.S new file mode 100644 index 00000000000..6e4fe834d1a --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/bzero.S @@ -0,0 +1,44 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: bzero.S,v 1.1 2001/06/19 00:22:45 fvdl Exp $") +#endif + +ENTRY(bzero) + movq %rsi,%rdx + + cld /* set fill direction forward */ + xorq %rax,%rax /* set fill data to 0 */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpq $16,%rdx + jb L1 + + movq %rdi,%rcx /* compute misalignment */ + negq %rcx + andq $7,%rcx + subq %rcx,%rdx + rep /* zero until word aligned */ + stosb + + movq %rdx,%rcx /* zero by words */ + shrq $3,%rcx + andq $7,%rdx + rep + stosq + +L1: movq %rdx,%rcx /* zero remainder by bytes */ + rep + stosb + + ret diff --git a/sys/lib/libkern/arch/x86_64/ffs.S b/sys/lib/libkern/arch/x86_64/ffs.S new file mode 100644 index 00000000000..c74c7010f54 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/ffs.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: ffs.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(ffs) + bsfl %edi,%eax + jz L1 /* ZF is set if all bits are 0 */ + incl %eax /* bits numbered from 1, not 0 */ + ret + + _ALIGN_TEXT +L1: xorl %eax,%eax /* clear result */ + ret diff --git a/sys/lib/libkern/arch/x86_64/index.S b/sys/lib/libkern/arch/x86_64/index.S new file mode 100644 index 00000000000..60754f266f0 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/index.S @@ -0,0 +1,29 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: index.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +#ifdef STRCHR +ENTRY(strchr) +#else +ENTRY(index) +#endif + movq %rdi,%rax + movb %sil,%cl +L1: + movb (%rax),%dl + cmpb %dl,%cl /* found char? */ + je L2 + incq %rax + testb %dl,%dl /* null terminator? */ + jnz L1 + xorq %rax,%rax +L2: + ret diff --git a/sys/lib/libkern/arch/x86_64/memchr.S b/sys/lib/libkern/arch/x86_64/memchr.S new file mode 100644 index 00000000000..f978e760220 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/memchr.S @@ -0,0 +1,25 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: memchr.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(memchr) + movb %sil,%al /* set character to search for */ + movq %rdx,%rcx /* set length of search */ + testq %rcx,%rcx /* test for len == 0 */ + jz L1 + cld /* set search forward */ + repne /* search! */ + scasb + jne L1 /* scan failed, return null */ + leaq -1(%rdi),%rax /* adjust result of scan */ + ret +L1: xorq %rax,%rax + ret diff --git a/sys/lib/libkern/arch/x86_64/memcmp.S b/sys/lib/libkern/arch/x86_64/memcmp.S new file mode 100644 index 00000000000..722a2a2c304 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/memcmp.S @@ -0,0 +1,40 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: memcmp.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(memcmp) + cld /* set compare direction forward */ + movq %rdx,%rcx /* compare by longs */ + shrq $3,%rcx + repe + cmpsq + jne L5 /* do we match so far? */ + + movq %rdx,%rcx /* compare remainder by bytes */ + andq $7,%rcx + repe + cmpsb + jne L6 /* do we match? */ + + xorl %eax,%eax /* we match, return zero */ + ret + +L5: movl $8,%ecx /* We know that one of the next */ + subq %rcx,%rdi /* eight pairs of bytes do not */ + subq %rcx,%rsi /* match. */ + repe + cmpsb +L6: xorl %eax,%eax /* Perform unsigned comparison */ + movb -1(%rdi),%al + xorl %edx,%edx + movb -1(%rsi),%dl + subl %edx,%eax + ret diff --git a/sys/lib/libkern/arch/x86_64/memcpy.S b/sys/lib/libkern/arch/x86_64/memcpy.S new file mode 100644 index 00000000000..c39caa328a3 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/memcpy.S @@ -0,0 +1,4 @@ +/* $NetBSD: memcpy.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $ */ + +#define MEMCOPY +#include "bcopy.S" diff --git a/sys/lib/libkern/arch/x86_64/memmove.S b/sys/lib/libkern/arch/x86_64/memmove.S new file mode 100644 index 00000000000..f5b81357afa --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/memmove.S @@ -0,0 +1,4 @@ +/* $NetBSD: memmove.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $ */ + +#define MEMMOVE +#include "bcopy.S" diff --git a/sys/lib/libkern/arch/x86_64/memset.S b/sys/lib/libkern/arch/x86_64/memset.S new file mode 100644 index 00000000000..2d92dc66534 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/memset.S @@ -0,0 +1,58 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: memset.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $") +#endif + +ENTRY(memset) + movq %rsi,%rax + movq %rdx,%rcx + movq %rdi,%r11 + + cld /* set fill direction forward */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpq $0x0f,%rcx + jle L1 + + movb %al,%ah /* copy char to all bytes in word */ + movl %eax,%edx + sall $16,%eax + orl %edx,%eax + + movl %eax,%edx + salq $32,%rax + orq %rdx,%rax + + movq %rdi,%rdx /* compute misalignment */ + negq %rdx + andq $7,%rdx + movq %rcx,%r8 + subq %rdx,%r8 + + movq %rdx,%rcx /* set until word aligned */ + rep + stosb + + movq %r8,%rcx + shrq $3,%rcx /* set by words */ + rep + stosq + + movq %r8,%rcx /* set remainder by bytes */ + andq $7,%rcx +L1: rep + stosb + movq %r11,%rax + + ret diff --git a/sys/lib/libkern/arch/x86_64/ovbcopy.S b/sys/lib/libkern/arch/x86_64/ovbcopy.S new file mode 100644 index 00000000000..71f2c9c8ddc --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/ovbcopy.S @@ -0,0 +1,4 @@ +/* $NetBSD: memmove.S,v 1.1 2001/06/19 00:22:46 fvdl Exp $ */ + +#define OVBCOPY +#include "bcopy.S" diff --git a/sys/lib/libkern/arch/x86_64/rindex.S b/sys/lib/libkern/arch/x86_64/rindex.S new file mode 100644 index 00000000000..6ba7c52a11f --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/rindex.S @@ -0,0 +1,29 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: rindex.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +#ifdef STRRCHR +ENTRY(strrchr) +#else +ENTRY(rindex) +#endif + movb %sil,%cl + xorq %rax,%rax /* init pointer to null */ +L1: + movb (%rdi),%dl + cmpb %dl,%cl + jne L2 + movq %rdi,%rax +L2: + incq %rdi + testb %dl,%dl /* null terminator??? */ + jnz L1 + ret diff --git a/sys/lib/libkern/arch/x86_64/scanc.S b/sys/lib/libkern/arch/x86_64/scanc.S new file mode 100644 index 00000000000..fd4fd31e129 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/scanc.S @@ -0,0 +1,62 @@ +/* $NetBSD: scanc.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +/* + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +ENTRY(scanc) + movq %rdx,%r11 + movb %cl,%dl + movl %edi,%ecx + testl %ecx,%ecx + jz 2f + movq %r11,%rdi + xorq %rax,%rax + cld +1: + lodsb + testb %dl,(%rax,%rdi) + jnz 2f + decl %ecx + jnz 1b +2: + movl %ecx,%eax + ret diff --git a/sys/lib/libkern/arch/x86_64/skpc.S b/sys/lib/libkern/arch/x86_64/skpc.S new file mode 100644 index 00000000000..f037d98b66a --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/skpc.S @@ -0,0 +1,56 @@ +/* $NetBSD: skpc.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +/* + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +ENTRY(skpc) + movl %edi,%eax + movq %rsi,%rcx + movq %rdx,%rdi + cld + repe + scasb + je 1f + incq %rcx +1: + movl %ecx,%eax + ret diff --git a/sys/lib/libkern/arch/x86_64/strcat.S b/sys/lib/libkern/arch/x86_64/strcat.S new file mode 100644 index 00000000000..7dc71244312 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/strcat.S @@ -0,0 +1,65 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strcat.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcat) + movq %rdi,%r11 + + cld /* set search forward */ + xorl %eax,%eax /* set search for null terminator */ + movq $-1,%rcx /* set search for lots of characters */ + repne /* search! */ + scasb + + decq %rdi + +L1: movb (%rsi),%al /* unroll loop, but not too much */ + movb %al,(%rdi) + testb %al,%al + jz L2 + movb 1(%rsi),%al + movb %al,1(%rdi) + testb %al,%al + jz L2 + movb 2(%rsi),%al + movb %al,2(%rdi) + testb %al,%al + jz L2 + movb 3(%rsi),%al + movb %al,3(%rdi) + testb %al,%al + jz L2 + movb 4(%rsi),%al + movb %al,4(%rdi) + testb %al,%al + jz L2 + movb 5(%rsi),%al + movb %al,5(%rdi) + testb %al,%al + jz L2 + movb 6(%rsi),%al + movb %al,6(%rdi) + testb %al,%al + jz L2 + movb 7(%rsi),%al + movb %al,7(%rdi) + addq $8,%rsi + addq $8,%rdi + testb %al,%al + jnz L1 +L2: movq %r11,%rax + ret diff --git a/sys/lib/libkern/arch/x86_64/strchr.S b/sys/lib/libkern/arch/x86_64/strchr.S new file mode 100644 index 00000000000..91fd708891f --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/strchr.S @@ -0,0 +1,4 @@ +/* $NetBSD: strchr.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +#define STRCHR +#include "index.S" diff --git a/sys/lib/libkern/arch/x86_64/strcmp.S b/sys/lib/libkern/arch/x86_64/strcmp.S new file mode 100644 index 00000000000..559563666d4 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/strcmp.S @@ -0,0 +1,88 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strcmp.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcmp) + jmp L2 /* Jump into the loop. */ + +L1: incq %rdi + incq %rsi +L2: movb (%rdi),%cl + testb %cl,%cl /* null terminator */ + jz L3 + cmpb %cl,(%rsi) /* chars match */ + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + jne L3 + + incq %rdi + incq %rsi + movb (%rdi),%cl + testb %cl,%cl + jz L3 + cmpb %cl,(%rsi) + je L1 +L3: movzbl (%rdi),%eax /* unsigned comparison */ + movzbl (%rsi),%edx + subl %edx,%eax + ret diff --git a/sys/lib/libkern/arch/x86_64/strcpy.S b/sys/lib/libkern/arch/x86_64/strcpy.S new file mode 100644 index 00000000000..924dfffd5be --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/strcpy.S @@ -0,0 +1,57 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strcpy.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +/* + * NOTE: I've unrolled the loop eight times: large enough to make a + * significant difference, and small enough not to totally trash the + * cache. + */ + +ENTRY(strcpy) + movq %rdi,%r11 + +L1: movb (%rsi),%al /* unroll loop, but not too much */ + movb %al,(%rdi) + testb %al,%al + jz L2 + movb 1(%rsi),%al + movb %al,1(%rdi) + testb %al,%al + jz L2 + movb 2(%rsi),%al + movb %al,2(%rdi) + testb %al,%al + jz L2 + movb 3(%rsi),%al + movb %al,3(%rdi) + testb %al,%al + jz L2 + movb 4(%rsi),%al + movb %al,4(%rdi) + testb %al,%al + jz L2 + movb 5(%rsi),%al + movb %al,5(%rdi) + testb %al,%al + jz L2 + movb 6(%rsi),%al + movb %al,6(%rdi) + testb %al,%al + jz L2 + movb 7(%rsi),%al + movb %al,7(%rdi) + addq $8,%rsi + addq $8,%rdi + testb %al,%al + jnz L1 +L2: movq %r11,%rax + ret diff --git a/sys/lib/libkern/arch/x86_64/strlen.S b/sys/lib/libkern/arch/x86_64/strlen.S new file mode 100644 index 00000000000..3c85659391a --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/strlen.S @@ -0,0 +1,21 @@ +/* + * Written by J.T. Conklin <jtc@netbsd.org>. + * Public domain. + * Adapted for NetBSD/x86_64 by Frank van der Linden <fvdl@wasabisystems.com> + */ + +#include <machine/asm.h> + +#if defined(LIBC_SCCS) + RCSID("$NetBSD: strlen.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $") +#endif + +ENTRY(strlen) + cld /* set search forward */ + xorl %eax,%eax /* set search for null terminator */ + movq $-1,%rcx /* set search for lots of characters */ + repne /* search! */ + scasb + notq %rcx /* get length by taking complement */ + leaq -1(%rcx),%rax /* and subtracting one */ + ret diff --git a/sys/lib/libkern/arch/x86_64/strrchr.S b/sys/lib/libkern/arch/x86_64/strrchr.S new file mode 100644 index 00000000000..9b23edfb435 --- /dev/null +++ b/sys/lib/libkern/arch/x86_64/strrchr.S @@ -0,0 +1,4 @@ +/* $NetBSD: strrchr.S,v 1.1 2001/06/19 00:22:47 fvdl Exp $ */ + +#define STRRCHR +#include "rindex.S" diff --git a/sys/sys/exec_aout.h b/sys/sys/exec_aout.h index 6bddccd3216..11d7d079dac 100644 --- a/sys/sys/exec_aout.h +++ b/sys/sys/exec_aout.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_aout.h,v 1.16 2002/03/28 07:02:03 deraadt Exp $ */ +/* $OpenBSD: exec_aout.h,v 1.17 2004/01/28 01:39:40 mickey Exp $ */ /* $NetBSD: exec_aout.h,v 1.15 1996/05/18 17:20:54 christos Exp $ */ /* @@ -79,6 +79,7 @@ struct exec { #define MID_POWERPC 149 /* big-endian PowerPC */ #define MID_VAX 150 /* vax */ #define MID_SPARC64 151 /* LP64 sparc */ +#define MID_X86_64 152 /* AMD x86-64 */ #define MID_M88K 153 /* m88k BSD binary */ #define MID_HPPA 154 /* hppa */ #define MID_HP200 200 /* hp200 (68010) BSD binary */ diff --git a/sys/sys/exec_elf.h b/sys/sys/exec_elf.h index 8b8685033a5..2bb7f8323ea 100644 --- a/sys/sys/exec_elf.h +++ b/sys/sys/exec_elf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_elf.h,v 1.36 2003/09/18 09:58:13 jmc Exp $ */ +/* $OpenBSD: exec_elf.h,v 1.37 2004/01/28 01:39:40 mickey Exp $ */ /* * Copyright (c) 1995, 1996 Erik Theisen. All rights reserved. * @@ -190,6 +190,7 @@ typedef struct { #define EM_ALPHA 41 /* DEC ALPHA */ #define EM_SPARCV9 43 /* SPARC version 9 */ #define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ +#define EM_X86_64 62 /* AMD x86-64 architecture */ #define EM_VAX 75 /* DEC VAX */ #define EM_NUM 15 /* number of machine types */ |