Add platform vkernel64.
authorJordan Gordeev <jgordeev@dir.bg>
Mon, 17 Aug 2009 20:44:39 +0000 (23:44 +0300)
committerSascha Wildner <saw@online.de>
Sun, 21 Mar 2010 08:16:43 +0000 (09:16 +0100)
55 files changed:
sys/config/VKERNEL64 [new file with mode: 0644]
sys/platform/vkernel64/amd64/autoconf.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/cpu_regs.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/db_interface.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/db_trace.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/exception.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/fork_tramp.s [new file with mode: 0644]
sys/platform/vkernel64/amd64/genassym.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/global.s [new file with mode: 0644]
sys/platform/vkernel64/amd64/locore.s [new file with mode: 0644]
sys/platform/vkernel64/amd64/mp.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/mplock.s [new file with mode: 0644]
sys/platform/vkernel64/amd64/npx.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/procfs_machdep.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/swtch.s [new file with mode: 0644]
sys/platform/vkernel64/amd64/tls.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/trap.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/userldt.c [new file with mode: 0644]
sys/platform/vkernel64/amd64/vm_machdep.c [new file with mode: 0644]
sys/platform/vkernel64/conf/Makefile [new file with mode: 0644]
sys/platform/vkernel64/conf/files [new file with mode: 0644]
sys/platform/vkernel64/conf/kern.mk [new file with mode: 0644]
sys/platform/vkernel64/conf/ldscript.amd64 [new file with mode: 0644]
sys/platform/vkernel64/conf/options [new file with mode: 0644]
sys/platform/vkernel64/include/clock.h [new file with mode: 0644]
sys/platform/vkernel64/include/cothread.h [new file with mode: 0644]
sys/platform/vkernel64/include/cpu.h [new file with mode: 0644]
sys/platform/vkernel64/include/cpufunc.h [new file with mode: 0644]
sys/platform/vkernel64/include/globaldata.h [new file with mode: 0644]
sys/platform/vkernel64/include/lock.h [new file with mode: 0644]
sys/platform/vkernel64/include/md_var.h [new file with mode: 0644]
sys/platform/vkernel64/include/param.h [new file with mode: 0644]
sys/platform/vkernel64/include/pcb.h [new file with mode: 0644]
sys/platform/vkernel64/include/pcb_ext.h [new file with mode: 0644]
sys/platform/vkernel64/include/pmap.h [new file with mode: 0644]
sys/platform/vkernel64/include/pmap_inval.h [new file with mode: 0644]
sys/platform/vkernel64/include/proc.h [new file with mode: 0644]
sys/platform/vkernel64/include/ptrace.h [new file with mode: 0644]
sys/platform/vkernel64/include/smp.h [new file with mode: 0644]
sys/platform/vkernel64/include/thread.h [new file with mode: 0644]
sys/platform/vkernel64/include/vmparam.h [new file with mode: 0644]
sys/platform/vkernel64/platform/busdma_machdep.c [new file with mode: 0644]
sys/platform/vkernel64/platform/console.c [new file with mode: 0644]
sys/platform/vkernel64/platform/copyio.c [new file with mode: 0644]
sys/platform/vkernel64/platform/cothread.c [new file with mode: 0644]
sys/platform/vkernel64/platform/globaldata.c [new file with mode: 0644]
sys/platform/vkernel64/platform/init.c [new file with mode: 0644]
sys/platform/vkernel64/platform/ipl_funcs.c [new file with mode: 0644]
sys/platform/vkernel64/platform/kqueue.c [new file with mode: 0644]
sys/platform/vkernel64/platform/machintr.c [new file with mode: 0644]
sys/platform/vkernel64/platform/pmap.c [new file with mode: 0644]
sys/platform/vkernel64/platform/pmap_inval.c [new file with mode: 0644]
sys/platform/vkernel64/platform/shutdown.c [new file with mode: 0644]
sys/platform/vkernel64/platform/sysarch.c [new file with mode: 0644]
sys/platform/vkernel64/platform/systimer.c [new file with mode: 0644]

diff --git a/sys/config/VKERNEL64 b/sys/config/VKERNEL64
new file mode 100644 (file)
index 0000000..34916f2
--- /dev/null
@@ -0,0 +1,110 @@
+# VKERNEL - configuration for a virtual kernel
+#
+# $DragonFly: src/sys/config/VKERNEL,v 1.14 2008/11/09 18:57:17 dillon Exp $
+
+platform       vkernel64       # platform architecture (i386, vkernel, etc)
+machine                amd64
+machine_arch   amd64           # cpu architecture (i386, etc)
+ident          VKERNEL64
+maxusers       0
+
+makeoptions    DEBUG=-g
+
+cpu            HAMMER_CPU
+
+options                DEBUG_PCTRACK
+
+##options              KTR
+##options              KTR_GIANT_CONTENTION
+##options              KTR_SPIN_CONTENTION
+#options       DEBUG_CRIT_SECTIONS
+
+options                QUOTA
+options                DUMMYNET
+options         IPFIREWALL              #firewall
+options                IPFIREWALL_FORWARD      #enable transparent proxy support
+options                IPFIREWALL_DEFAULT_TO_ACCEPT    #allow everything by default
+
+# ALTQ
+options         ALTQ            #alternate queueing
+options         ALTQ_CBQ        #class based queueing
+options         ALTQ_RED        #random early detection
+options         ALTQ_RIO        #triple red for diffserv (needs RED)
+options         ALTQ_HFSC       #hierarchical fair service curve
+options         ALTQ_PRIQ       #priority queue
+options                ALTQ_FAIRQ      #fair queue
+#options        ALTQ_NOPCC      #don't use processor cycle counter
+options         ALTQ_DEBUG      #for debugging
+
+##options              IPSEC                   #IP security
+##options              IPSEC_ESP               #IP security (crypto; define w/ IPSEC)
+##options              IPSEC_DEBUG             #debug for IP security
+
+options                HAMMER
+options                EXT2FS
+options        INET                    #InterNETworking
+options        INET6                   #IPv6 communications protocols
+options        FFS                     #Berkeley Fast Filesystem
+options        FFS_ROOT                #FFS usable as root device [keep this!]
+options        SOFTUPDATES             #Enable FFS soft updates support
+options        UFS_DIRHASH             #Improve performance on big directories
+options        MFS                     #Memory Filesystem
+options        MD_ROOT                 #MD is a potential root device
+options        NFS                     #Network Filesystem
+options        NFS_ROOT                #NFS usable as root device, NFS required
+options        MSDOSFS                 #MSDOS Filesystem
+options        CD9660                  #ISO 9660 Filesystem
+options        PROCFS                  #Process filesystem
+options        COMPAT_43               #Compatible with BSD 4.3 [KEEP THIS!]
+options                COMPAT_DF12             #Compatible with DragonFly 1.2 and earlier
+options                DEVICE_POLLING          # Support mixed interrupt-polling
+                                       # handling of network device drivers
+options        UCONSOLE                #Allow users to grab the console
+options        KTRACE                  #ktrace(1) support
+options        SYSVSHM                 #SYSV-style shared memory
+options        SYSVMSG                 #SYSV-style message queues
+options        SYSVSEM                 #SYSV-style semaphores
+options        P1003_1B                #Posix P1003_1B real-time extensions
+options        _KPOSIX_PRIORITY_SCHEDULING
+options        ICMP_BANDLIM            #Rate limit bad replies
+
+options        SMP                     # Symmetric MultiProcessor Kernel
+
+# Debugging for Development
+options        DDB
+options        DDB_TRACE
+options        INVARIANTS
+
+#options       CARP
+
+# Pseudo devices - the number indicates how many units to allocate.
+pseudo-device  loop            # Network loopback
+pseudo-device  ether           # Ethernet support
+pseudo-device  sl      1       # Kernel SLIP
+pseudo-device  ppp     1       # Kernel PPP
+pseudo-device  tun             # Packet tunnel.
+pseudo-device  pty             # Pseudo-ttys (telnet etc)
+pseudo-device  md              # Memory "disks"
+pseudo-device  gif             # IPv6 and IPv4 tunneling
+pseudo-device  faith   1       # IPv6-to-IPv4 relaying (translation)
+
+#pseudo-device carp
+
+# SCSI peripherals
+device          scbus           # SCSI bus (required)
+device          da              # Direct Access (disks)
+device          sa              # Sequential Access (tape etc)
+device          cd              # CD
+device          pass            # Passthrough device (direct SCSI access)
+
+# The `bpf' pseudo-device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+pseudo-device  bpf             #Berkeley packet filter
+
+# VIRTUAL DEVICES
+#
+device         vn
+device         vkd
+device         vke
+
+device         vcd
diff --git a/sys/platform/vkernel64/amd64/autoconf.c b/sys/platform/vkernel64/amd64/autoconf.c
new file mode 100644 (file)
index 0000000..208af00
--- /dev/null
@@ -0,0 +1,555 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 2008 The DragonFly Project.
+ * 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: @(#)autoconf.c    7.1 (Berkeley) 5/9/91
+ * $FreeBSD: src/sys/i386/i386/autoconf.c,v 1.146.2.2 2001/06/07 06:05:58 dd Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/autoconf.c,v 1.3 2008/08/29 17:07:10 dillon Exp $
+ */
+
+/*
+ * 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 "opt_bootp.h"
+#include "opt_ffs.h"
+#include "opt_cd9660.h"
+#include "opt_nfs.h"
+#include "opt_nfsroot.h"
+#include "opt_bus.h"
+#include "opt_rootdevname.h"
+
+#include "use_isa.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bootmaj.h>
+#include <sys/bus.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/diskslice.h>
+#include <sys/reboot.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/cons.h>
+#include <sys/thread.h>
+#include <sys/device.h>
+#include <sys/machintr.h>
+
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_pager.h>
+
+#if 0
+#include <machine/pcb.h>
+#include <machine/pcb_ext.h>
+#endif
+#include <machine/smp.h>
+#include <machine/globaldata.h>
+#include <machine/md_var.h>
+
+#if NISA > 0
+#include <bus/isa/isavar.h>
+
+device_t isa_bus_device = 0;
+#endif
+
+static void cpu_startup (void *);
+static void configure_first (void *);
+static void configure (void *);
+static void configure_final (void *);
+
+#if defined(FFS) && defined(FFS_ROOT)
+static void    setroot (void);
+#endif
+
+#if defined(NFS) && defined(NFS_ROOT)
+#if !defined(BOOTP_NFSROOT)
+static void    pxe_setup_nfsdiskless(void);
+#endif
+#endif
+
+SYSINIT(cpu, SI_BOOT2_SMP, SI_ORDER_FIRST, cpu_startup, NULL);
+SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL);
+/* SI_ORDER_SECOND is hookable */
+SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);
+/* SI_ORDER_MIDDLE is hookable */
+SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL);
+
+cdev_t rootdev = NULL;
+cdev_t dumpdev = NULL;
+
+/*
+ *
+ */
+static void
+cpu_startup(void *dummy)
+{
+       vm_offset_t buffer_sva;
+       vm_offset_t buffer_eva;
+       vm_offset_t pager_sva;
+       vm_offset_t pager_eva;
+
+       kprintf("%s", version);
+       kprintf("real memory = %llu (%lluK bytes)\n",
+               ptoa(Maxmem), ptoa(Maxmem) / 1024);
+
+       if (nbuf == 0) {
+               int factor = 4 * BKVASIZE / 1024;
+               int kbytes = Maxmem * (PAGE_SIZE / 1024);
+
+               nbuf = 50;
+               if (kbytes > 4096)
+                       nbuf += min((kbytes - 4096) / factor, 65536 / factor);
+               if (kbytes > 65536)
+                       nbuf += (kbytes - 65536) * 2 / (factor * 5);
+               if (maxbcache && nbuf > maxbcache / BKVASIZE)
+                       nbuf = maxbcache / BKVASIZE;
+       }
+       if (nbuf > (virtual_end - virtual_start) / (BKVASIZE * 2)) {
+               nbuf = (virtual_end - virtual_start) / (BKVASIZE * 2);
+               kprintf("Warning: nbufs capped at %d\n", nbuf);
+       }
+
+       nswbuf = max(min(nbuf/4, 256), 16);
+#ifdef NSWBUF_MIN
+       if (nswbuf < NSWBUF_MIN)
+               nswbuf = NSWBUF_MIN;
+#endif
+
+       /*
+        * Allocate memory for the buffer cache
+        */
+       buf = (void *)kmem_alloc(&kernel_map, nbuf * sizeof(struct buf));
+       swbuf = (void *)kmem_alloc(&kernel_map, nswbuf * sizeof(struct buf));
+
+
+#ifdef DIRECTIO
+        ffs_rawread_setup();
+#endif
+       kmem_suballoc(&kernel_map, &clean_map, &clean_sva, &clean_eva,
+                     (nbuf*BKVASIZE) + (nswbuf*MAXPHYS) + pager_map_size);
+       kmem_suballoc(&clean_map, &buffer_map, &buffer_sva, &buffer_eva,
+                     (nbuf*BKVASIZE));
+       buffer_map.system_map = 1;
+       kmem_suballoc(&clean_map, &pager_map, &pager_sva, &pager_eva,
+                     (nswbuf*MAXPHYS) + pager_map_size);
+       pager_map.system_map = 1;
+#if defined(USERCONFIG)
+        userconfig();
+       cninit();               /* the preferred console may have changed */
+#endif
+       kprintf("avail memory = %lu (%luK bytes)\n", ptoa(vmstats.v_free_count),
+               ptoa(vmstats.v_free_count) / 1024);
+       bufinit();
+       vm_pager_bufferinit();
+#ifdef SMP
+       mp_start();
+       mp_announce();
+#endif
+       cpu_setregs();
+}
+
+/*
+ * Determine i/o configuration for a machine.
+ */
+static void
+configure_first(void *dummy)
+{
+}
+
+static void
+configure(void *dummy)
+{
+        /*
+        * Final interrupt support acviation, then enable hardware interrupts.
+        */
+       MachIntrABI.finalize();
+       cpu_enable_intr();
+
+       /*
+        * This will configure all devices, generally starting with the
+        * nexus (i386/i386/nexus.c).  The nexus ISA code explicitly
+        * dummies up the attach in order to delay legacy initialization
+        * until after all other busses/subsystems have had a chance
+        * at those resources.
+        */
+       root_bus_configure();
+
+#if NISA > 0
+       /*
+        * Explicitly probe and attach ISA last.  The isa bus saves
+        * it's device node at attach time for us here.
+        */
+       if (isa_bus_device)
+               isa_probe_children(isa_bus_device);
+#endif
+
+       /*
+        * Allow lowering of the ipl to the lowest kernel level if we
+        * panic (or call tsleep() before clearing `cold').  No level is
+        * completely safe (since a panic may occur in a critical region
+        * at splhigh()), but we want at least bio interrupts to work.
+        */
+       safepri = TDPRI_KERN_USER;
+}
+
+static void
+configure_final(void *dummy)
+{
+       cninit_finish();
+
+       if (bootverbose)
+               kprintf("Device configuration finished.\n");
+}
+
+#ifdef BOOTP
+void bootpc_init(void);
+#endif
+/*
+ * Do legacy root filesystem discovery.
+ */
+void
+cpu_rootconf(void)
+{
+#ifdef BOOTP
+        bootpc_init();
+#endif
+#if defined(NFS) && defined(NFS_ROOT)
+#if !defined(BOOTP_NFSROOT)
+       pxe_setup_nfsdiskless();
+       if (nfs_diskless_valid)
+#endif
+               rootdevnames[0] = "nfs:";
+#endif
+#if defined(FFS) && defined(FFS_ROOT)
+        if (!rootdevnames[0])
+                setroot();
+#endif
+}
+SYSINIT(cpu_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, cpu_rootconf, NULL)
+
+u_long bootdev = 0;            /* not a cdev_t - encoding is different */
+
+#if defined(FFS) && defined(FFS_ROOT)
+
+/*
+ * The boot code uses old block device major numbers to pass bootdev to
+ * us.  We have to translate these to character device majors because
+ * we don't have block devices any more.
+ */
+static int
+boot_translate_majdev(int bmajor)
+{
+       static int conv[] = { BOOTMAJOR_CONVARY };
+
+       if (bmajor >= 0 && bmajor < sizeof(conv)/sizeof(conv[0]))
+               return(conv[bmajor]);
+       return(-1);
+}
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * set rootdevs[] and rootdevnames[] to correspond to the
+ * boot device(s).
+ *
+ * This code survives in order to allow the system to be
+ * booted from legacy environments that do not correctly
+ * populate the kernel environment. There are significant
+ * restrictions on the bootability of the system in this
+ * situation; it can only be mounting root from a 'da'
+ * 'wd' or 'fd' device, and the root filesystem must be ufs.
+ */
+static void
+setroot(void)
+{
+       int majdev, mindev, unit, slice, part;
+       cdev_t newrootdev, dev;
+       char partname[2];
+       char *sname;
+
+       if ((bootdev & B_MAGICMASK) != B_DEVMAGIC) {
+               kprintf("no B_DEVMAGIC (bootdev=%#lx)\n", bootdev);
+               return;
+       }
+       majdev = boot_translate_majdev(B_TYPE(bootdev));
+       if (bootverbose) {
+               kprintf("bootdev: %08lx type=%ld unit=%ld "
+                       "slice=%ld part=%ld major=%d\n",
+                       bootdev, B_TYPE(bootdev), B_UNIT(bootdev),
+                       B_SLICE(bootdev), B_PARTITION(bootdev), majdev);
+       }
+       dev = udev2dev(makeudev(majdev, 0), 0);
+       if (!dev_is_good(dev))
+               return;
+       unit = B_UNIT(bootdev);
+       slice = B_SLICE(bootdev);
+       if (slice == WHOLE_DISK_SLICE)
+               slice = COMPATIBILITY_SLICE;
+       if (slice < 0 || slice >= MAX_SLICES) {
+               kprintf("bad slice\n");
+               return;
+       }
+
+       part = B_PARTITION(bootdev);
+       mindev = dkmakeminor(unit, slice, part);
+       newrootdev = udev2dev(makeudev(majdev, mindev), 0);
+       if (!dev_is_good(newrootdev))
+               return;
+       sname = dsname(newrootdev, unit, slice, part, partname);
+       rootdevnames[0] = kmalloc(strlen(sname) + 6, M_DEVBUF, M_WAITOK);
+       ksprintf(rootdevnames[0], "ufs:%s%s", sname, partname);
+
+       /*
+        * For properly dangerously dedicated disks (ones with a historical
+        * bogus partition table), the boot blocks will give slice = 4, but
+        * the kernel will only provide the compatibility slice since it
+        * knows that slice 4 is not a real slice.  Arrange to try mounting
+        * the compatibility slice as root if mounting the slice passed by
+        * the boot blocks fails.  This handles the dangerously dedicated
+        * case and perhaps others.
+        */
+       if (slice == COMPATIBILITY_SLICE)
+               return;
+       slice = COMPATIBILITY_SLICE;
+       sname = dsname(newrootdev, unit, slice, part, partname);
+       rootdevnames[1] = kmalloc(strlen(sname) + 6, M_DEVBUF, M_WAITOK);
+       ksprintf(rootdevnames[1], "ufs:%s%s", sname, partname);
+}
+#endif
+
+#if defined(NFS) && defined(NFS_ROOT)
+#if !defined(BOOTP_NFSROOT)
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <vfs/nfs/rpcv2.h>
+#include <vfs/nfs/nfsproto.h>
+#include <vfs/nfs/nfs.h>
+#include <vfs/nfs/nfsdiskless.h>
+
+extern struct nfs_diskless     nfs_diskless;
+
+/*
+ * Convert a kenv variable to a sockaddr.  If the kenv variable does not
+ * exist the sockaddr will remain zerod out (callers typically just check
+ * sin_len).  A network address of 0.0.0.0 is equivalent to failure.
+ */
+static int
+inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa)
+{
+       u_int32_t       a[4];
+       char            *cp;
+
+       bzero(sa, sizeof(*sa));
+
+       if ((cp = kgetenv(ev)) == NULL)
+               return(1);
+       if (ksscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]) != 4)
+               return(1);
+       if (a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0)
+               return(1);
+       /* XXX is this ordering correct? */
+       sa->sin_addr.s_addr = (a[3] << 24) + (a[2] << 16) + (a[1] << 8) + a[0];
+       sa->sin_len = sizeof(*sa);
+       sa->sin_family = AF_INET;
+       return(0);
+}
+
+static int
+hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
+{
+       char            *cp;
+       u_int32_t       a[6];
+
+       bzero(sa, sizeof(*sa));
+       sa->sdl_len = sizeof(*sa);
+       sa->sdl_family = AF_LINK;
+       sa->sdl_type = IFT_ETHER;
+       sa->sdl_alen = ETHER_ADDR_LEN;
+       if ((cp = kgetenv(ev)) == NULL)
+               return(1);
+       if (ksscanf(cp, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]) != 6)
+               return(1);
+       sa->sdl_data[0] = a[0];
+       sa->sdl_data[1] = a[1];
+       sa->sdl_data[2] = a[2];
+       sa->sdl_data[3] = a[3];
+       sa->sdl_data[4] = a[4];
+       sa->sdl_data[5] = a[5];
+       return(0);
+}
+
+static int
+decode_nfshandle(char *ev, u_char *fh)
+{
+       u_char  *cp;
+       int     len, val;
+
+       if (((cp = kgetenv(ev)) == NULL) || (strlen(cp) < 2) || (*cp != 'X'))
+               return(0);
+       len = 0;
+       cp++;
+       for (;;) {
+               if (*cp == 'X')
+                       return(len);
+               if ((ksscanf(cp, "%2x", &val) != 1) || (val > 0xff))
+                       return(0);
+               *(fh++) = val;
+               len++;
+               cp += 2;
+               if (len > NFSX_V2FH)
+                   return(0);
+       }
+}
+
+/*
+ * Populate the essential fields in the nfsv3_diskless structure.
+ *
+ * The loader is expected to export the following environment variables:
+ *
+ * boot.netif.ip               IP address on boot interface
+ * boot.netif.netmask          netmask on boot interface
+ * boot.netif.gateway          default gateway (optional)
+ * boot.netif.hwaddr           hardware address of boot interface
+ * boot.netif.name             name of boot interface (instead of hw addr)
+ * boot.nfsroot.server         IP address of root filesystem server
+ * boot.nfsroot.path           path of the root filesystem on server
+ * boot.nfsroot.nfshandle      NFS handle for root filesystem on server
+ */
+static void
+pxe_setup_nfsdiskless(void)
+{
+       struct nfs_diskless     *nd = &nfs_diskless;
+       struct ifnet            *ifp;
+       struct ifaddr           *ifa;
+       struct sockaddr_dl      *sdl, ourdl;
+       struct sockaddr_in      myaddr, netmask;
+       char                    *cp;
+
+       /* set up interface */
+       if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
+               return;
+       if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
+               kprintf("PXE: no netmask\n");
+               return;
+       }
+       bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
+       bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
+       ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
+               myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
+       bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
+
+       if ((cp = kgetenv("boot.netif.name")) != NULL) {
+               TAILQ_FOREACH(ifp, &ifnet, if_link) {
+                       if (strcmp(cp, ifp->if_xname) == 0)
+                               break;
+               }
+               if (ifp)
+                       goto match_done;
+               kprintf("PXE: cannot find interface %s\n", cp);
+               return;
+       }
+
+       if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
+               kprintf("PXE: no hardware address\n");
+               return;
+       }
+       ifa = NULL;
+       ifp = TAILQ_FIRST(&ifnet);
+       TAILQ_FOREACH(ifp, &ifnet, if_link) {
+               struct ifaddr_container *ifac;
+
+               TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
+                       ifa = ifac->ifa;
+
+                       if ((ifa->ifa_addr->sa_family == AF_LINK) &&
+                           (sdl = ((struct sockaddr_dl *)ifa->ifa_addr))) {
+                               if ((sdl->sdl_type == ourdl.sdl_type) &&
+                                   (sdl->sdl_alen == ourdl.sdl_alen) &&
+                                   !bcmp(sdl->sdl_data + sdl->sdl_nlen,
+                                         ourdl.sdl_data + ourdl.sdl_nlen,
+                                         sdl->sdl_alen))
+                                   goto match_done;
+                       }
+               }
+       }
+       kprintf("PXE: no interface\n");
+       return; /* no matching interface */
+match_done:
+       strlcpy(nd->myif.ifra_name, ifp->if_xname, sizeof(nd->myif.ifra_name));
+
+       /* set up gateway */
+       inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
+
+       /* XXX set up swap? */
+
+       /* set up root mount */
+       nd->root_args.rsize = 8192;             /* XXX tunable? */
+       nd->root_args.wsize = 8192;
+       nd->root_args.sotype = SOCK_STREAM;
+       nd->root_args.flags = NFSMNT_WSIZE | NFSMNT_RSIZE | NFSMNT_RESVPORT;
+       if (inaddr_to_sockaddr("boot.nfsroot.server", &nd->root_saddr)) {
+               kprintf("PXE: no server\n");
+               return;
+       }
+       nd->root_saddr.sin_port = htons(NFS_PORT);
+
+       /*
+        * A tftp-only loader may pass NFS path information without a
+        * root handle.  Generate a warning but continue configuring.
+        */
+       if (decode_nfshandle("boot.nfsroot.nfshandle", &nd->root_fh[0]) == 0) {
+               kprintf("PXE: Warning, no NFS handle passed from loader\n");
+       }
+       if ((cp = kgetenv("boot.nfsroot.path")) != NULL)
+               strncpy(nd->root_hostnam, cp, MNAMELEN - 1);
+
+       nfs_diskless_valid = 1;
+}
+
+#endif
+#endif
diff --git a/sys/platform/vkernel64/amd64/cpu_regs.c b/sys/platform/vkernel64/amd64/cpu_regs.c
new file mode 100644 (file)
index 0000000..d4ea2a1
--- /dev/null
@@ -0,0 +1,1155 @@
+/*-
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (C) 1994, David Greenman
+ * Copyright (c) 1982, 1987, 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     from: @(#)machdep.c     7.4 (Berkeley) 6/3/91
+ * $FreeBSD: src/sys/i386/i386/machdep.c,v 1.385.2.30 2003/05/31 08:48:05 alc Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/cpu_regs.c,v 1.29 2008/06/06 13:19:25 swildner Exp $
+ */
+
+#include "use_ether.h"
+#include "use_isa.h"
+#include "opt_atalk.h"
+#include "opt_compat.h"
+#include "opt_ddb.h"
+#include "opt_directio.h"
+#include "opt_inet.h"
+#include "opt_ipx.h"
+#include "opt_msgbuf.h"
+#include "opt_swap.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/reboot.h>
+#include <sys/mbuf.h>
+#include <sys/msgbuf.h>
+#include <sys/sysent.h>
+#include <sys/sysctl.h>
+#include <sys/vmmeter.h>
+#include <sys/bus.h>
+#include <sys/upcall.h>
+#include <sys/usched.h>
+#include <sys/reg.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <sys/lock.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_extern.h>
+
+#include <sys/thread2.h>
+
+#include <sys/user.h>
+#include <sys/exec.h>
+#include <sys/cons.h>
+
+#include <ddb/ddb.h>
+
+#include <machine/cpu.h>
+#include <machine/clock.h>
+#include <machine/specialreg.h>
+#include <machine/md_var.h>
+#include <machine/pcb_ext.h>           /* pcb.h included via sys/user.h */
+#include <machine/globaldata.h>                /* CPU_prvspace */
+#include <machine/smp.h>
+#ifdef PERFMON
+#include <machine/perfmon.h>
+#endif
+#include <machine/cputypes.h>
+
+#include <bus/isa/rtc.h>
+#include <sys/random.h>
+#include <sys/ptrace.h>
+#include <machine/sigframe.h>
+#include <unistd.h>            /* umtx_* functions */
+
+extern void dblfault_handler (void);
+
+#ifndef CPU_DISABLE_SSE
+static void set_fpregs_xmm (struct save87 *, struct savexmm *);
+static void fill_fpregs_xmm (struct savexmm *, struct save87 *);
+#endif /* CPU_DISABLE_SSE */
+#ifdef DIRECTIO
+extern void ffs_rawread_setup(void);
+#endif /* DIRECTIO */
+
+#ifdef SMP
+int64_t tsc_offsets[MAXCPU];
+#else
+int64_t tsc_offsets[1];
+#endif
+
+#if defined(SWTCH_OPTIM_STATS)
+extern int swtch_optim_stats;
+SYSCTL_INT(_debug, OID_AUTO, swtch_optim_stats,
+       CTLFLAG_RD, &swtch_optim_stats, 0, "");
+SYSCTL_INT(_debug, OID_AUTO, tlb_flush_count,
+       CTLFLAG_RD, &tlb_flush_count, 0, "");
+#endif
+
+static int
+sysctl_hw_physmem(SYSCTL_HANDLER_ARGS)
+{
+       /* JG */
+       int error = sysctl_handle_int(oidp, 0, ctob((int)Maxmem), req);
+       return (error);
+}
+
+SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_INT|CTLFLAG_RD,
+       0, 0, sysctl_hw_physmem, "IU", "");
+
+static int
+sysctl_hw_usermem(SYSCTL_HANDLER_ARGS)
+{
+       /* JG */
+       int error = sysctl_handle_int(oidp, 0,
+               ctob((int)Maxmem - vmstats.v_wire_count), req);
+       return (error);
+}
+
+SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_INT|CTLFLAG_RD,
+       0, 0, sysctl_hw_usermem, "IU", "");
+
+SYSCTL_ULONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &Maxmem, 0, "");
+
+#if 0
+
+static int
+sysctl_machdep_msgbuf(SYSCTL_HANDLER_ARGS)
+{
+       int error;
+
+       /* Unwind the buffer, so that it's linear (possibly starting with
+        * some initial nulls).
+        */
+       error=sysctl_handle_opaque(oidp,msgbufp->msg_ptr+msgbufp->msg_bufr,
+               msgbufp->msg_size-msgbufp->msg_bufr,req);
+       if(error) return(error);
+       if(msgbufp->msg_bufr>0) {
+               error=sysctl_handle_opaque(oidp,msgbufp->msg_ptr,
+                       msgbufp->msg_bufr,req);
+       }
+       return(error);
+}
+
+SYSCTL_PROC(_machdep, OID_AUTO, msgbuf, CTLTYPE_STRING|CTLFLAG_RD,
+       0, 0, sysctl_machdep_msgbuf, "A","Contents of kernel message buffer");
+
+static int msgbuf_clear;
+
+static int
+sysctl_machdep_msgbuf_clear(SYSCTL_HANDLER_ARGS)
+{
+       int error;
+       error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,
+               req);
+       if (!error && req->newptr) {
+               /* Clear the buffer and reset write pointer */
+               bzero(msgbufp->msg_ptr,msgbufp->msg_size);
+               msgbufp->msg_bufr=msgbufp->msg_bufx=0;
+               msgbuf_clear=0;
+       }
+       return (error);
+}
+
+SYSCTL_PROC(_machdep, OID_AUTO, msgbuf_clear, CTLTYPE_INT|CTLFLAG_RW,
+       &msgbuf_clear, 0, sysctl_machdep_msgbuf_clear, "I",
+       "Clear kernel message buffer");
+
+#endif
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * at top to call routine, followed by kcall
+ * to sigreturn routine below.  After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+void
+sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code)
+{
+       struct lwp *lp = curthread->td_lwp;
+       struct proc *p = lp->lwp_proc;
+       struct trapframe *regs;
+       struct sigacts *psp = p->p_sigacts;
+       struct sigframe sf, *sfp;
+       int oonstack;
+       char *sp;
+
+       regs = lp->lwp_md.md_regs;
+       oonstack = (lp->lwp_sigstk.ss_flags & SS_ONSTACK) ? 1 : 0;
+
+       /* Save user context */
+       bzero(&sf, sizeof(struct sigframe));
+       sf.sf_uc.uc_sigmask = *mask;
+       sf.sf_uc.uc_stack = lp->lwp_sigstk;
+       sf.sf_uc.uc_mcontext.mc_onstack = oonstack;
+       KKASSERT(__offsetof(struct trapframe, tf_rdi) == 0);
+       bcopy(regs, &sf.sf_uc.uc_mcontext.mc_rdi, sizeof(struct trapframe));
+
+       /* Make the size of the saved context visible to userland */
+       sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext);
+
+       /* Save mailbox pending state for syscall interlock semantics */
+       if (p->p_flag & P_MAILBOX)
+               sf.sf_uc.uc_mcontext.mc_xflags |= PGEX_MAILBOX;
+
+       /* Allocate and validate space for the signal handler context. */
+        if ((lp->lwp_flag & LWP_ALTSTACK) != 0 && !oonstack &&
+           SIGISMEMBER(psp->ps_sigonstack, sig)) {
+               sp = (char *)(lp->lwp_sigstk.ss_sp + lp->lwp_sigstk.ss_size -
+                             sizeof(struct sigframe));
+               lp->lwp_sigstk.ss_flags |= SS_ONSTACK;
+       } else {
+               /* We take red zone into account */
+               sp = (char *)regs->tf_rsp - sizeof(struct sigframe) - 128;
+       }
+
+       /* Align to 16 bytes */
+       sfp = (struct sigframe *)((intptr_t)sp & ~0xFUL);
+
+       /* Translate the signal is appropriate */
+       if (p->p_sysent->sv_sigtbl) {
+               if (sig <= p->p_sysent->sv_sigsize)
+                       sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)];
+       }
+
+       /*
+        * Build the argument list for the signal handler.
+        *
+        * Arguments are in registers (%rdi, %rsi, %rdx, %rcx)
+        */
+       regs->tf_rdi = sig;                             /* argument 1 */
+       regs->tf_rdx = (register_t)&sfp->sf_uc;         /* argument 3 */
+
+       if (SIGISMEMBER(psp->ps_siginfo, sig)) {
+               /*
+                * Signal handler installed with SA_SIGINFO.
+                *
+                * action(signo, siginfo, ucontext)
+                */
+               regs->tf_rsi = (register_t)&sfp->sf_si; /* argument 2 */
+               regs->tf_rcx = (register_t)regs->tf_err; /* argument 4 */
+               sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher;
+
+               /* fill siginfo structure */
+               sf.sf_si.si_signo = sig;
+               sf.sf_si.si_code = code;
+               sf.sf_si.si_addr = (void *)regs->tf_err;
+       } else {
+               /*
+                * Old FreeBSD-style arguments.
+                *
+                * handler (signo, code, [uc], addr)
+                */
+               regs->tf_rsi = (register_t)code;        /* argument 2 */
+               regs->tf_rcx = (register_t)regs->tf_err; /* argument 4 */
+               sf.sf_ahu.sf_handler = catcher;
+       }
+
+#if 0
+       /*
+        * If we're a vm86 process, we want to save the segment registers.
+        * We also change eflags to be our emulated eflags, not the actual
+        * eflags.
+        */
+       if (regs->tf_eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86 = &lp->lwp_thread->td_pcb->pcb_ext->ext_vm86;
+
+               sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs;
+               sf.sf_uc.uc_mcontext.mc_fs = tf->tf_vm86_fs;
+               sf.sf_uc.uc_mcontext.mc_es = tf->tf_vm86_es;
+               sf.sf_uc.uc_mcontext.mc_ds = tf->tf_vm86_ds;
+
+               if (vm86->vm86_has_vme == 0)
+                       sf.sf_uc.uc_mcontext.mc_eflags =
+                           (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) |
+                           (vm86->vm86_eflags & (PSL_VIF | PSL_VIP));
+
+               /*
+                * Clear PSL_NT to inhibit T_TSSFLT faults on return from
+                * syscalls made by the signal handler.  This just avoids
+                * wasting time for our lazy fixup of such faults.  PSL_NT
+                * does nothing in vm86 mode, but vm86 programs can set it
+                * almost legitimately in probes for old cpu types.
+                */
+               tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_VIF | PSL_VIP);
+       }
+#endif
+
+       /*
+        * Save the FPU state and reinit the FP unit
+        */
+       npxpush(&sf.sf_uc.uc_mcontext);
+
+       /*
+        * Copy the sigframe out to the user's stack.
+        */
+       if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) {
+               /*
+                * Something is wrong with the stack pointer.
+                * ...Kill the process.
+                */
+               sigexit(lp, SIGILL);
+       }
+
+       regs->tf_rsp = (register_t)sfp;
+       regs->tf_rip = PS_STRINGS - *(p->p_sysent->sv_szsigcode);
+
+       /*
+        * i386 abi specifies that the direction flag must be cleared
+        * on function entry
+        */
+       regs->tf_rflags &= ~(PSL_T|PSL_D);
+
+       /*
+        * 64 bit mode has a code and stack selector but
+        * no data or extra selector.  %fs and %gs are not
+        * stored in-context.
+        */
+       regs->tf_cs = _ucodesel;
+       regs->tf_ss = _udatasel;
+}
+
+/*
+ * Sanitize the trapframe for a virtual kernel passing control to a custom
+ * VM context.  Remove any items that would otherwise create a privilage
+ * issue.
+ *
+ * XXX at the moment we allow userland to set the resume flag.  Is this a
+ * bad idea?
+ */
+int
+cpu_sanitize_frame(struct trapframe *frame)
+{
+       frame->tf_cs = _ucodesel;
+       frame->tf_ss = _udatasel;
+       /* XXX VM (8086) mode not supported? */
+       frame->tf_rflags &= (PSL_RF | PSL_USERCHANGE | PSL_VM_UNSUPP);
+       frame->tf_rflags |= PSL_RESERVED_DEFAULT | PSL_I;
+
+       return(0);
+}
+
+/*
+ * Sanitize the tls so loading the descriptor does not blow up
+ * on us.  For AMD64 we don't have to do anything.
+ */
+int
+cpu_sanitize_tls(struct savetls *tls)
+{
+       return(0);
+}
+
+/*
+ * sigreturn(ucontext_t *sigcntxp)
+ *
+ * System call to cleanup state after a signal
+ * has been taken.  Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * state to gain improper privileges.
+ */
+#define        EFL_SECURE(ef, oef)     ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)
+#define        CS_SECURE(cs)           (ISPL(cs) == SEL_UPL)
+
+int
+sys_sigreturn(struct sigreturn_args *uap)
+{
+       struct lwp *lp = curthread->td_lwp;
+       struct proc *p = lp->lwp_proc;
+       struct trapframe *regs;
+       ucontext_t uc;
+       ucontext_t *ucp;
+       register_t rflags;
+       int cs;
+       int error;
+
+       /*
+        * We have to copy the information into kernel space so userland
+        * can't modify it while we are sniffing it.
+        */
+       regs = lp->lwp_md.md_regs;
+       error = copyin(uap->sigcntxp, &uc, sizeof(uc));
+       if (error)
+               return (error);
+       ucp = &uc;
+       rflags = ucp->uc_mcontext.mc_rflags;
+
+       /* VM (8086) mode not supported */
+       rflags &= ~PSL_VM_UNSUPP;
+
+#if 0
+       if (eflags & PSL_VM) {
+               struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs;
+               struct vm86_kernel *vm86;
+
+               /*
+                * if pcb_ext == 0 or vm86_inited == 0, the user hasn't
+                * set up the vm86 area, and we can't enter vm86 mode.
+                */
+               if (lp->lwp_thread->td_pcb->pcb_ext == 0)
+                       return (EINVAL);
+               vm86 = &lp->lwp_thread->td_pcb->pcb_ext->ext_vm86;
+               if (vm86->vm86_inited == 0)
+                       return (EINVAL);
+
+               /* go back to user mode if both flags are set */
+               if ((eflags & PSL_VIP) && (eflags & PSL_VIF))
+                       trapsignal(lp->lwp_proc, SIGBUS, 0);
+
+               if (vm86->vm86_has_vme) {
+                       eflags = (tf->tf_eflags & ~VME_USERCHANGE) |
+                           (eflags & VME_USERCHANGE) | PSL_VM;
+               } else {
+                       vm86->vm86_eflags = eflags;     /* save VIF, VIP */
+                       eflags = (tf->tf_eflags & ~VM_USERCHANGE) |                                         (eflags & VM_USERCHANGE) | PSL_VM;
+               }
+               bcopy(&ucp.uc_mcontext.mc_gs, tf, sizeof(struct trapframe));
+               tf->tf_eflags = eflags;
+               tf->tf_vm86_ds = tf->tf_ds;
+               tf->tf_vm86_es = tf->tf_es;
+               tf->tf_vm86_fs = tf->tf_fs;
+               tf->tf_vm86_gs = tf->tf_gs;
+               tf->tf_ds = _udatasel;
+               tf->tf_es = _udatasel;
+#if 0
+               tf->tf_fs = _udatasel;
+               tf->tf_gs = _udatasel;
+#endif
+       } else
+#endif
+       {
+               /*
+                * Don't allow users to change privileged or reserved flags.
+                */
+               /*
+                * XXX do allow users to change the privileged flag PSL_RF.
+                * The cpu sets PSL_RF in tf_eflags for faults.  Debuggers
+                * should sometimes set it there too.  tf_eflags is kept in
+                * the signal context during signal handling and there is no
+                * other place to remember it, so the PSL_RF bit may be
+                * corrupted by the signal handler without us knowing.
+                * Corruption of the PSL_RF bit at worst causes one more or
+                * one less debugger trap, so allowing it is fairly harmless.
+                */
+               if (!EFL_SECURE(rflags & ~PSL_RF, regs->tf_rflags & ~PSL_RF)) {
+                       kprintf("sigreturn: rflags = 0x%lx\n", (long)rflags);
+                       return(EINVAL);
+               }
+
+               /*
+                * Don't allow users to load a valid privileged %cs.  Let the
+                * hardware check for invalid selectors, excess privilege in
+                * other selectors, invalid %eip's and invalid %esp's.
+                */
+               cs = ucp->uc_mcontext.mc_cs;
+               if (!CS_SECURE(cs)) {
+                       kprintf("sigreturn: cs = 0x%x\n", cs);
+                       trapsignal(lp, SIGBUS, T_PROTFLT);
+                       return(EINVAL);
+               }
+               bcopy(&ucp->uc_mcontext.mc_rdi, regs, sizeof(struct trapframe));
+       }
+
+       /*
+        * Restore the FPU state from the frame
+        */
+       npxpop(&ucp->uc_mcontext);
+
+       /*
+        * Merge saved signal mailbox pending flag to maintain interlock
+        * semantics against system calls.
+        */
+       if (ucp->uc_mcontext.mc_xflags & PGEX_MAILBOX)
+               p->p_flag |= P_MAILBOX;
+
+       if (ucp->uc_mcontext.mc_onstack & 1)
+               lp->lwp_sigstk.ss_flags |= SS_ONSTACK;
+       else
+               lp->lwp_sigstk.ss_flags &= ~SS_ONSTACK;
+
+       lp->lwp_sigmask = ucp->uc_sigmask;
+       SIG_CANTMASK(lp->lwp_sigmask);
+       return(EJUSTRETURN);
+}
+
+/*
+ * Stack frame on entry to function.  %rax will contain the function vector,
+ * %rcx will contain the function data.  flags, rcx, and rax will have
+ * already been pushed on the stack.
+ */
+struct upc_frame {
+       register_t      rax;
+       register_t      rcx;
+       register_t      rdx;
+       register_t      flags;
+       register_t      oldip;
+};
+
+void
+sendupcall(struct vmupcall *vu, int morepending)
+{
+       struct lwp *lp = curthread->td_lwp;
+       struct trapframe *regs;
+       struct upcall upcall;
+       struct upc_frame upc_frame;
+       int     crit_count = 0;
+
+       /*
+        * If we are a virtual kernel running an emulated user process
+        * context, switch back to the virtual kernel context before
+        * trying to post the signal.
+        */
+       if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
+               lp->lwp_md.md_regs->tf_trapno = 0;
+               vkernel_trap(lp, lp->lwp_md.md_regs);
+       }
+
+       /*
+        * Get the upcall data structure
+        */
+       if (copyin(lp->lwp_upcall, &upcall, sizeof(upcall)) ||
+           copyin((char *)upcall.upc_uthread + upcall.upc_critoff, &crit_count, sizeof(int))
+       ) {
+               vu->vu_pending = 0;
+               kprintf("bad upcall address\n");
+               return;
+       }
+
+       /*
+        * If the data structure is already marked pending or has a critical
+        * section count, mark the data structure as pending and return
+        * without doing an upcall.  vu_pending is left set.
+        */
+       if (upcall.upc_pending || crit_count >= vu->vu_pending) {
+               if (upcall.upc_pending < vu->vu_pending) {
+                       upcall.upc_pending = vu->vu_pending;
+                       copyout(&upcall.upc_pending, &lp->lwp_upcall->upc_pending,
+                               sizeof(upcall.upc_pending));
+               }
+               return;
+       }
+
+       /*
+        * We can run this upcall now, clear vu_pending.
+        *
+        * Bump our critical section count and set or clear the
+        * user pending flag depending on whether more upcalls are
+        * pending.  The user will be responsible for calling
+        * upc_dispatch(-1) to process remaining upcalls.
+        */
+       vu->vu_pending = 0;
+       upcall.upc_pending = morepending;
+       crit_count += TDPRI_CRIT;
+       copyout(&upcall.upc_pending, &lp->lwp_upcall->upc_pending,
+               sizeof(upcall.upc_pending));
+       copyout(&crit_count, (char *)upcall.upc_uthread + upcall.upc_critoff,
+               sizeof(int));
+
+       /*
+        * Construct a stack frame and issue the upcall
+        */
+       regs = lp->lwp_md.md_regs;
+       upc_frame.rax = regs->tf_rax;
+       upc_frame.rcx = regs->tf_rcx;
+       upc_frame.rdx = regs->tf_rdx;
+       upc_frame.flags = regs->tf_rflags;
+       upc_frame.oldip = regs->tf_rip;
+       if (copyout(&upc_frame, (void *)(regs->tf_rsp - sizeof(upc_frame)),
+           sizeof(upc_frame)) != 0) {
+               kprintf("bad stack on upcall\n");
+       } else {
+               regs->tf_rax = (register_t)vu->vu_func;
+               regs->tf_rcx = (register_t)vu->vu_data;
+               regs->tf_rdx = (register_t)lp->lwp_upcall;
+               regs->tf_rip = (register_t)vu->vu_ctx;
+               regs->tf_rsp -= sizeof(upc_frame);
+       }
+}
+
+/*
+ * fetchupcall occurs in the context of a system call, which means that
+ * we have to return EJUSTRETURN in order to prevent eax and edx from
+ * being overwritten by the syscall return value.
+ *
+ * if vu is not NULL we return the new context in %edx, the new data in %ecx,
+ * and the function pointer in %eax.
+ */
+int
+fetchupcall(struct vmupcall *vu, int morepending, void *rsp)
+{
+       struct upc_frame upc_frame;
+       struct lwp *lp = curthread->td_lwp;
+       struct trapframe *regs;
+       int error;
+       struct upcall upcall;
+       int crit_count;
+
+       regs = lp->lwp_md.md_regs;
+
+       error = copyout(&morepending, &lp->lwp_upcall->upc_pending, sizeof(int));
+       if (error == 0) {
+           if (vu) {
+               /*
+                * This jumps us to the next ready context.
+                */
+               vu->vu_pending = 0;
+               error = copyin(lp->lwp_upcall, &upcall, sizeof(upcall));
+               crit_count = 0;
+               if (error == 0)
+                       error = copyin((char *)upcall.upc_uthread + upcall.upc_critoff, &crit_count, sizeof(int));
+               crit_count += TDPRI_CRIT;
+               if (error == 0)
+                       error = copyout(&crit_count, (char *)upcall.upc_uthread + upcall.upc_critoff, sizeof(int));
+               regs->tf_rax = (register_t)vu->vu_func;
+               regs->tf_rcx = (register_t)vu->vu_data;
+               regs->tf_rdx = (register_t)lp->lwp_upcall;
+               regs->tf_rip = (register_t)vu->vu_ctx;
+               regs->tf_rsp = (register_t)rsp;
+           } else {
+               /*
+                * This returns us to the originally interrupted code.
+                */
+               error = copyin(rsp, &upc_frame, sizeof(upc_frame));
+               regs->tf_rax = upc_frame.rax;
+               regs->tf_rcx = upc_frame.rcx;
+               regs->tf_rdx = upc_frame.rdx;
+               regs->tf_rflags = (regs->tf_rflags & ~PSL_USERCHANGE) |
+                               (upc_frame.flags & PSL_USERCHANGE);
+               regs->tf_rip = upc_frame.oldip;
+               regs->tf_rsp = (register_t)((char *)rsp + sizeof(upc_frame));
+           }
+       }
+       if (error == 0)
+               error = EJUSTRETURN;
+       return(error);
+}
+
+/*
+ * cpu_idle() represents the idle LWKT.  You cannot return from this function
+ * (unless you want to blow things up!).  Instead we look for runnable threads
+ * and loop or halt as appropriate.  Giant is not held on entry to the thread.
+ *
+ * The main loop is entered with a critical section held, we must release
+ * the critical section before doing anything else.  lwkt_switch() will
+ * check for pending interrupts due to entering and exiting its own
+ * critical section.
+ *
+ * Note on cpu_idle_hlt:  On an SMP system we rely on a scheduler IPI
+ * to wake a HLTed cpu up.  However, there are cases where the idlethread
+ * will be entered with the possibility that no IPI will occur and in such
+ * cases lwkt_switch() sets TDF_IDLE_NOHLT.
+ */
+static int     cpu_idle_hlt = 1;
+static int     cpu_idle_hltcnt;
+static int     cpu_idle_spincnt;
+SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW,
+    &cpu_idle_hlt, 0, "Idle loop HLT enable");
+SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hltcnt, CTLFLAG_RW,
+    &cpu_idle_hltcnt, 0, "Idle loop entry halts");
+SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_spincnt, CTLFLAG_RW,
+    &cpu_idle_spincnt, 0, "Idle loop entry spins");
+
+void
+cpu_idle(void)
+{
+       struct thread *td = curthread;
+       struct mdglobaldata *gd = mdcpu;
+
+       crit_exit();
+       KKASSERT(td->td_pri < TDPRI_CRIT);
+       cpu_enable_intr();
+       for (;;) {
+               /*
+                * See if there are any LWKTs ready to go.
+                */
+               lwkt_switch();
+
+               /*
+                * The idle loop halts only if no threads are scheduleable
+                * and no signals have occured.
+                */
+               if (cpu_idle_hlt && !lwkt_runnable() &&
+                   (td->td_flags & TDF_IDLE_NOHLT) == 0) {
+                       splz();
+                       if (!lwkt_runnable()) {
+#ifdef DEBUGIDLE
+                               struct timeval tv1, tv2;
+                               gettimeofday(&tv1, NULL);
+#endif
+                               umtx_sleep(&gd->mi.gd_runqmask, 0, 1000000);
+#ifdef DEBUGIDLE
+                               gettimeofday(&tv2, NULL);
+                               if (tv2.tv_usec - tv1.tv_usec +
+                                   (tv2.tv_sec - tv1.tv_sec) * 1000000
+                                   > 500000) {
+                                       kprintf("cpu %d idlelock %08x %08x\n",
+                                               gd->mi.gd_cpuid,
+                                               gd->mi.gd_runqmask,
+                                               gd->gd_fpending);
+                               }
+#endif
+                       }
+#ifdef SMP
+                       else {
+                           __asm __volatile("pause");
+                       }
+#endif
+                       ++cpu_idle_hltcnt;
+               } else {
+                       td->td_flags &= ~TDF_IDLE_NOHLT;
+                       splz();
+#ifdef SMP
+                       /*__asm __volatile("sti; pause");*/
+                       __asm __volatile("pause");
+#else
+                       /*__asm __volatile("sti");*/
+#endif
+                       ++cpu_idle_spincnt;
+               }
+       }
+}
+
+#ifdef SMP
+
+/*
+ * Called by the LWKT switch core with a critical section held if the only
+ * schedulable thread needs the MP lock and we couldn't get it.  On
+ * a real cpu we just spin in the scheduler.  In the virtual kernel
+ * we sleep for a bit.
+ */
+void
+cpu_mplock_contested(void)
+{
+       usleep(1000);
+}
+
+/*
+ * Called by the spinlock code with or without a critical section held
+ * when a spinlock is found to be seriously constested.
+ *
+ * We need to enter a critical section to prevent signals from recursing
+ * into pthreads.
+ */
+void
+cpu_spinlock_contested(void)
+{
+       crit_enter();
+       usleep(1000);
+       crit_exit();
+}
+
+#endif
+
+/*
+ * Clear registers on exec
+ */
+void
+exec_setregs(u_long entry, u_long stack, u_long ps_strings)
+{
+       struct thread *td = curthread;
+       struct lwp *lp = td->td_lwp;
+       struct pcb *pcb = td->td_pcb;
+       struct trapframe *regs = lp->lwp_md.md_regs;
+
+       /* was i386_user_cleanup() in NetBSD */
+       user_ldt_free(pcb);
+
+       bzero((char *)regs, sizeof(struct trapframe));
+       regs->tf_rip = entry;
+       regs->tf_rsp = ((stack - 8) & ~0xFul) + 8; /* align the stack */
+       regs->tf_rdi = stack;           /* argv */
+       regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+       regs->tf_ss = _udatasel;
+       regs->tf_cs = _ucodesel;
+       regs->tf_rbx = ps_strings;
+
+       /*
+        * Reset the hardware debug registers if they were in use.
+        * They won't have any meaning for the newly exec'd process.
+        */
+       if (pcb->pcb_flags & PCB_DBREGS) {
+               pcb->pcb_dr0 = 0;
+               pcb->pcb_dr1 = 0;
+               pcb->pcb_dr2 = 0;
+               pcb->pcb_dr3 = 0;
+               pcb->pcb_dr6 = 0;
+               pcb->pcb_dr7 = 0; /* JG set bit 10? */
+               if (pcb == td->td_pcb) {
+                       /*
+                        * Clear the debug registers on the running
+                        * CPU, otherwise they will end up affecting
+                        * the next process we switch to.
+                        */
+                       reset_dbregs();
+               }
+               pcb->pcb_flags &= ~PCB_DBREGS;
+       }
+
+       /*
+        * Initialize the math emulator (if any) for the current process.
+        * Actually, just clear the bit that says that the emulator has
+        * been initialized.  Initialization is delayed until the process
+        * traps to the emulator (if it is done at all) mainly because
+        * emulators don't provide an entry point for initialization.
+        */
+       pcb->pcb_flags &= ~FP_SOFTFP;
+
+       /*
+        * NOTE: do not set CR0_TS here.  npxinit() must do it after clearing
+        *       gd_npxthread.  Otherwise a preemptive interrupt thread
+        *       may panic in npxdna().
+        */
+       crit_enter();
+#if 0
+       load_cr0(rcr0() | CR0_MP);
+#endif
+
+       /*
+        * NOTE: The MSR values must be correct so we can return to
+        *       userland.  gd_user_fs/gs must be correct so the switch
+        *       code knows what the current MSR values are.
+        */
+       pcb->pcb_fsbase = 0;    /* Values loaded from PCB on switch */
+       pcb->pcb_gsbase = 0;
+       /* Initialize the npx (if any) for the current process. */
+       npxinit(__INITIAL_NPXCW__);
+       crit_exit();
+
+       /*
+        * note: linux emulator needs edx to be 0x0 on entry, which is
+        * handled in execve simply by setting the 64 bit syscall
+        * return value to 0.
+        */
+}
+
+void
+cpu_setregs(void)
+{
+#if 0
+       unsigned int cr0;
+
+       cr0 = rcr0();
+       cr0 |= CR0_NE;                  /* Done by npxinit() */
+       cr0 |= CR0_MP | CR0_TS;         /* Done at every execve() too. */
+       cr0 |= CR0_WP | CR0_AM;
+       load_cr0(cr0);
+       load_gs(_udatasel);
+#endif
+}
+
+static int
+sysctl_machdep_adjkerntz(SYSCTL_HANDLER_ARGS)
+{
+       int error;
+       error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2,
+               req);
+       if (!error && req->newptr)
+               resettodr();
+       return (error);
+}
+
+SYSCTL_PROC(_machdep, CPU_ADJKERNTZ, adjkerntz, CTLTYPE_INT|CTLFLAG_RW,
+       &adjkerntz, 0, sysctl_machdep_adjkerntz, "I", "");
+
+extern u_long bootdev;         /* not a cdev_t - encoding is different */
+SYSCTL_ULONG(_machdep, OID_AUTO, guessed_bootdev,
+       CTLFLAG_RD, &bootdev, 0, "Boot device (not in cdev_t format)");
+
+/*
+ * Initialize 386 and configure to run kernel
+ */
+
+/*
+ * Initialize segments & interrupt table
+ */
+
+extern  struct user *proc0paddr;
+
+#if 0
+
+extern inthand_t
+       IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
+       IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(fpusegm),
+       IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
+       IDTVEC(page), IDTVEC(mchk), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(align),
+       IDTVEC(xmm), IDTVEC(dblfault),
+       IDTVEC(fast_syscall), IDTVEC(fast_syscall32);
+#endif
+
+#ifdef DEBUG_INTERRUPTS
+extern inthand_t *Xrsvdary[256];
+#endif
+
+int
+ptrace_set_pc(struct lwp *lp, unsigned long addr)
+{
+       lp->lwp_md.md_regs->tf_rip = addr;
+       return (0);
+}
+
+int
+ptrace_single_step(struct lwp *lp)
+{
+       lp->lwp_md.md_regs->tf_rflags |= PSL_T;
+       return (0);
+}
+
+int
+fill_regs(struct lwp *lp, struct reg *regs)
+{
+       struct pcb *pcb;
+       struct trapframe *tp;
+
+       tp = lp->lwp_md.md_regs;
+       bcopy(&tp->tf_rdi, &regs->r_rdi, sizeof(*regs));
+
+       pcb = lp->lwp_thread->td_pcb;
+       return (0);
+}
+
+int
+set_regs(struct lwp *lp, struct reg *regs)
+{
+       struct pcb *pcb;
+       struct trapframe *tp;
+
+       tp = lp->lwp_md.md_regs;
+       if (!EFL_SECURE(regs->r_rflags, tp->tf_rflags) ||
+           !CS_SECURE(regs->r_cs))
+               return (EINVAL);
+       bcopy(&regs->r_rdi, &tp->tf_rdi, sizeof(*regs));
+       pcb = lp->lwp_thread->td_pcb;
+       return (0);
+}
+
+#ifndef CPU_DISABLE_SSE
+static void
+fill_fpregs_xmm(struct savexmm *sv_xmm, struct save87 *sv_87)
+{
+       struct env87 *penv_87 = &sv_87->sv_env;
+       struct envxmm *penv_xmm = &sv_xmm->sv_env;
+       int i;
+
+       /* FPU control/status */
+       penv_87->en_cw = penv_xmm->en_cw;
+       penv_87->en_sw = penv_xmm->en_sw;
+       penv_87->en_tw = penv_xmm->en_tw;
+       penv_87->en_fip = penv_xmm->en_fip;
+       penv_87->en_fcs = penv_xmm->en_fcs;
+       penv_87->en_opcode = penv_xmm->en_opcode;
+       penv_87->en_foo = penv_xmm->en_foo;
+       penv_87->en_fos = penv_xmm->en_fos;
+
+       /* FPU registers */
+       for (i = 0; i < 8; ++i)
+               sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc;
+
+       sv_87->sv_ex_sw = sv_xmm->sv_ex_sw;
+}
+
+static void
+set_fpregs_xmm(struct save87 *sv_87, struct savexmm *sv_xmm)
+{
+       struct env87 *penv_87 = &sv_87->sv_env;
+       struct envxmm *penv_xmm = &sv_xmm->sv_env;
+       int i;
+
+       /* FPU control/status */
+       penv_xmm->en_cw = penv_87->en_cw;
+       penv_xmm->en_sw = penv_87->en_sw;
+       penv_xmm->en_tw = penv_87->en_tw;
+       penv_xmm->en_fip = penv_87->en_fip;
+       penv_xmm->en_fcs = penv_87->en_fcs;
+       penv_xmm->en_opcode = penv_87->en_opcode;
+       penv_xmm->en_foo = penv_87->en_foo;
+       penv_xmm->en_fos = penv_87->en_fos;
+
+       /* FPU registers */
+       for (i = 0; i < 8; ++i)
+               sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i];
+
+       sv_xmm->sv_ex_sw = sv_87->sv_ex_sw;
+}
+#endif /* CPU_DISABLE_SSE */
+
+int
+fill_fpregs(struct lwp *lp, struct fpreg *fpregs)
+{
+#ifndef CPU_DISABLE_SSE
+       if (cpu_fxsr) {
+               fill_fpregs_xmm(&lp->lwp_thread->td_pcb->pcb_save.sv_xmm,
+                               (struct save87 *)fpregs);
+               return (0);
+       }
+#endif /* CPU_DISABLE_SSE */
+       bcopy(&lp->lwp_thread->td_pcb->pcb_save.sv_87, fpregs, sizeof *fpregs);
+       return (0);
+}
+
+int
+set_fpregs(struct lwp *lp, struct fpreg *fpregs)
+{
+#ifndef CPU_DISABLE_SSE
+       if (cpu_fxsr) {
+               set_fpregs_xmm((struct save87 *)fpregs,
+                              &lp->lwp_thread->td_pcb->pcb_save.sv_xmm);
+               return (0);
+       }
+#endif /* CPU_DISABLE_SSE */
+       bcopy(fpregs, &lp->lwp_thread->td_pcb->pcb_save.sv_87, sizeof *fpregs);
+       return (0);
+}
+
+int
+fill_dbregs(struct lwp *lp, struct dbreg *dbregs)
+{
+       return (ENOSYS);
+}
+
+int
+set_dbregs(struct lwp *lp, struct dbreg *dbregs)
+{
+       return (ENOSYS);
+}
+
+#if 0
+/*
+ * Return > 0 if a hardware breakpoint has been hit, and the
+ * breakpoint was in user space.  Return 0, otherwise.
+ */
+int
+user_dbreg_trap(void)
+{
+        u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */
+        u_int32_t bp;       /* breakpoint bits extracted from dr6 */
+        int nbp;            /* number of breakpoints that triggered */
+        caddr_t addr[4];    /* breakpoint addresses */
+        int i;
+
+        dr7 = rdr7();
+        if ((dr7 & 0x000000ff) == 0) {
+                /*
+                 * all GE and LE bits in the dr7 register are zero,
+                 * thus the trap couldn't have been caused by the
+                 * hardware debug registers
+                 */
+                return 0;
+        }
+
+        nbp = 0;
+        dr6 = rdr6();
+        bp = dr6 & 0x0000000f;
+
+        if (!bp) {
+                /*
+                 * None of the breakpoint bits are set meaning this
+                 * trap was not caused by any of the debug registers
+                 */
+                return 0;
+        }
+
+        /*
+         * at least one of the breakpoints were hit, check to see
+         * which ones and if any of them are user space addresses
+         */
+
+        if (bp & 0x01) {
+                addr[nbp++] = (caddr_t)rdr0();
+        }
+        if (bp & 0x02) {
+                addr[nbp++] = (caddr_t)rdr1();
+        }
+        if (bp & 0x04) {
+                addr[nbp++] = (caddr_t)rdr2();
+        }
+        if (bp & 0x08) {
+                addr[nbp++] = (caddr_t)rdr3();
+        }
+
+        for (i=0; i<nbp; i++) {
+                if (addr[i] <
+                    (caddr_t)VM_MAX_USER_ADDRESS) {
+                        /*
+                         * addr[i] is in user space
+                         */
+                        return nbp;
+                }
+        }
+
+        /*
+         * None of the breakpoints are in user space.
+         */
+        return 0;
+}
+
+#endif
+
+void
+identcpu(void)
+{
+       int regs[4];
+
+       do_cpuid(1, regs);
+       cpu_feature = regs[3];
+}
+
+
+#ifndef DDB
+void
+Debugger(const char *msg)
+{
+       kprintf("Debugger(\"%s\") called.\n", msg);
+}
+#endif /* no DDB */
diff --git a/sys/platform/vkernel64/amd64/db_interface.c b/sys/platform/vkernel64/amd64/db_interface.c
new file mode 100644 (file)
index 0000000..c4bca1b
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * --
+ *
+ * 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
+ * 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.
+ *
+ * $FreeBSD: src/sys/i386/i386/db_interface.c,v 1.48.2.1 2000/07/07 00:38:46 obrien Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/db_interface.c,v 1.3 2008/08/29 17:07:10 dillon Exp $
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/reboot.h>
+#include <sys/cons.h>
+#include <sys/thread.h>
+
+#include <machine/cpu.h>
+#include <machine/smp.h>
+#include <machine/globaldata.h>
+#include <machine/md_var.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <ddb/ddb.h>
+
+#include <sys/thread2.h>
+
+#include <setjmp.h>
+
+static jmp_buf *db_nofault = 0;
+extern jmp_buf db_jmpbuf;
+
+extern void    gdb_handle_exception (db_regs_t *, int, int);
+
+int    db_active;
+db_regs_t ddb_regs;
+
+static jmp_buf db_global_jmpbuf;
+static int     db_global_jmpbuf_valid;
+
+#ifdef __GNUC__
+#define        rss() ({u_short ss; __asm __volatile("mov %%ss,%0" : "=r" (ss)); ss;})
+#endif
+
+/*
+ *  kdb_trap - field a TRACE or BPT trap
+ */
+int
+kdb_trap(int type, int code, struct amd64_saved_state *regs)
+{
+       volatile int ddb_mode = !(boothowto & RB_GDB);
+
+       /*
+        * XXX try to do nothing if the console is in graphics mode.
+        * Handle trace traps (and hardware breakpoints...) by ignoring
+        * them except for forgetting about them.  Return 0 for other
+        * traps to say that we haven't done anything.  The trap handler
+        * will usually panic.  We should handle breakpoint traps for
+        * our breakpoints by disarming our breakpoints and fixing up
+        * %eip.
+        */
+       if (cons_unavail && ddb_mode) {
+           if (type == T_TRCTRAP) {
+               regs->tf_rflags &= ~PSL_T;
+               return (1);
+           }
+           return (0);
+       }
+
+       switch (type) {
+           case T_BPTFLT:      /* breakpoint */
+           case T_TRCTRAP:     /* debug exception */
+               break;
+
+           default:
+               /*
+                * XXX this is almost useless now.  In most cases,
+                * trap_fatal() has already printed a much more verbose
+                * message.  However, it is dangerous to print things in
+                * trap_fatal() - kprintf() might be reentered and trap.
+                * The debugger should be given control first.
+                */
+               if (ddb_mode)
+                   db_printf("kernel: type %d trap, code=%x\n", type, code);
+
+               if (db_nofault) {
+                   jmp_buf *no_fault = db_nofault;
+                   db_nofault = 0;
+                   longjmp(*no_fault, 1);
+               }
+       }
+
+       /*
+        * This handles unexpected traps in ddb commands, including calls to
+        * non-ddb functions.  db_nofault only applies to memory accesses by
+        * internal ddb commands.
+        */
+       if (db_global_jmpbuf_valid)
+           longjmp(db_global_jmpbuf, 1);
+
+       /*
+        * XXX We really should switch to a local stack here.
+        */
+       ddb_regs = *regs;
+
+       crit_enter();
+#ifdef SMP
+       db_printf("\nCPU%d stopping CPUs: 0x%08x\n",
+           mycpu->gd_cpuid, mycpu->gd_other_cpus);
+
+       /* We stop all CPUs except ourselves (obviously) */
+       stop_cpus(mycpu->gd_other_cpus);
+
+       db_printf(" stopped\n");
+#endif /* SMP */
+
+       setjmp(db_global_jmpbuf);
+       db_global_jmpbuf_valid = TRUE;
+       db_active++;
+       vcons_set_mode(1);
+       if (ddb_mode) {
+           cndbctl(TRUE);
+           db_trap(type, code);
+           cndbctl(FALSE);
+       } else
+           gdb_handle_exception(&ddb_regs, type, code);
+       db_active--;
+       vcons_set_mode(0);
+       db_global_jmpbuf_valid = FALSE;
+
+#ifdef SMP
+       db_printf("\nCPU%d restarting CPUs: 0x%08x\n",
+           mycpu->gd_cpuid, stopped_cpus);
+
+       /* Restart all the CPUs we previously stopped */
+       if (stopped_cpus != mycpu->gd_other_cpus) {
+               db_printf("whoa, other_cpus: 0x%08x, stopped_cpus: 0x%08x\n",
+                         mycpu->gd_other_cpus, stopped_cpus);
+               panic("stop_cpus() failed");
+       }
+       restart_cpus(stopped_cpus);
+
+       db_printf(" restarted\n");
+#endif /* SMP */
+       crit_exit();
+
+       regs->tf_rip    = ddb_regs.tf_rip;
+       regs->tf_rflags = ddb_regs.tf_rflags;
+       regs->tf_rax    = ddb_regs.tf_rax;
+       regs->tf_rcx    = ddb_regs.tf_rcx;
+       regs->tf_rdx    = ddb_regs.tf_rdx;
+       regs->tf_rbx    = ddb_regs.tf_rbx;
+
+       regs->tf_rsp    = ddb_regs.tf_rsp;
+       regs->tf_ss     = ddb_regs.tf_ss & 0xffff;
+
+       regs->tf_rbp    = ddb_regs.tf_rbp;
+       regs->tf_rsi    = ddb_regs.tf_rsi;
+       regs->tf_rdi    = ddb_regs.tf_rdi;
+
+       regs->tf_r8     = ddb_regs.tf_r8;
+       regs->tf_r9     = ddb_regs.tf_r9;
+       regs->tf_r10    = ddb_regs.tf_r10;
+       regs->tf_r11    = ddb_regs.tf_r11;
+       regs->tf_r12    = ddb_regs.tf_r12;
+       regs->tf_r13    = ddb_regs.tf_r13;
+       regs->tf_r14    = ddb_regs.tf_r14;
+       regs->tf_r15    = ddb_regs.tf_r15;
+
+       /* regs->tf_es     = ddb_regs.tf_es & 0xffff; */
+       /* regs->tf_fs     = ddb_regs.tf_fs & 0xffff; */
+       /* regs->tf_gs     = ddb_regs.tf_gs & 0xffff; */
+       regs->tf_cs     = ddb_regs.tf_cs & 0xffff;
+       /* regs->tf_ds     = ddb_regs.tf_ds & 0xffff; */
+       return (1);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+void
+db_read_bytes(vm_offset_t addr, size_t size, char *data)
+{
+       char    *src;
+
+       db_nofault = &db_jmpbuf;
+
+       src = (char *)addr;
+       while (size-- > 0)
+           *data++ = *src++;
+
+       db_nofault = 0;
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(vm_offset_t addr, size_t size, char *data)
+{
+       char    *dst;
+#if 0
+       vpte_t  *ptep0 = NULL;
+       vpte_t  oldmap0 = 0;
+       vm_offset_t     addr1;
+       vpte_t  *ptep1 = NULL;
+       vpte_t  oldmap1 = 0;
+#endif
+
+       db_nofault = &db_jmpbuf;
+#if 0
+       if (addr > trunc_page((vm_offset_t)btext) - size &&
+           addr < round_page((vm_offset_t)etext)) {
+
+           ptep0 = pmap_kpte(addr);
+           oldmap0 = *ptep0;
+           *ptep0 |= VPTE_W;
+
+           /* Map another page if the data crosses a page boundary. */
+           if ((*ptep0 & PG_PS) == 0) {
+               addr1 = trunc_page(addr + size - 1);
+               if (trunc_page(addr) != addr1) {
+                   ptep1 = pmap_kpte(addr1);
+                   oldmap1 = *ptep1;
+                   *ptep1 |= VPTE_W;
+               }
+           } else {
+               addr1 = trunc_4mpage(addr + size - 1);
+               if (trunc_4mpage(addr) != addr1) {
+                   ptep1 = pmap_kpte(addr1);
+                   oldmap1 = *ptep1;
+                   *ptep1 |= VPTE_W;
+               }
+           }
+
+           cpu_invltlb();
+       }
+#endif
+
+       dst = (char *)addr;
+
+       while (size-- > 0)
+           *dst++ = *data++;
+
+       db_nofault = 0;
+
+#if 0
+       if (ptep0) {
+           *ptep0 = oldmap0;
+
+           if (ptep1)
+               *ptep1 = oldmap1;
+
+           cpu_invltlb();
+       }
+#endif
+}
+
+/*
+ * The debugger sometimes needs to know the actual KVM address represented
+ * by the instruction pointer, stack pointer, or base pointer.  Normally
+ * the actual KVM address is simply the contents of the register.  However,
+ * if the debugger is entered from the BIOS or VM86 we need to figure out
+ * the offset from the segment register.
+ */
+db_addr_t
+PC_REGS(db_regs_t *regs)
+{
+    return(regs->tf_rip);
+}
+
+db_addr_t
+SP_REGS(db_regs_t *regs)
+{
+    return(regs->tf_rsp);
+}
+
+db_addr_t
+BP_REGS(db_regs_t *regs)
+{
+    return(regs->tf_rbp);
+}
+
+/*
+ * XXX
+ * Move this to machdep.c and allow it to be called if any debugger is
+ * installed.
+ */
+void
+Debugger(const char *msg)
+{
+       static volatile u_char in_Debugger;
+
+       /*
+        * XXX
+        * Do nothing if the console is in graphics mode.  This is
+        * OK if the call is for the debugger hotkey but not if the call
+        * is a weak form of panicing.
+        */
+       if (cons_unavail && !(boothowto & RB_GDB))
+           return;
+
+       if (!in_Debugger) {
+           in_Debugger = 1;
+           db_printf("Debugger(\"%s\")\n", msg);
+           breakpoint();
+           in_Debugger = 0;
+       }
+}
diff --git a/sys/platform/vkernel64/amd64/db_trace.c b/sys/platform/vkernel64/amd64/db_trace.c
new file mode 100644 (file)
index 0000000..3de9a40
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * --
+ *
+ * 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
+ * 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.
+ *
+ * $FreeBSD: src/sys/i386/i386/db_trace.c,v 1.35.2.3 2002/02/21 22:31:25 silby Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/db_trace.c,v 1.3 2008/08/29 17:07:10 dillon Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/linker_set.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/reg.h>
+
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <ddb/ddb.h>
+#include <dlfcn.h>     /* DLL */
+
+#include <sys/user.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+
+db_varfcn_t db_dr0;
+db_varfcn_t db_dr1;
+db_varfcn_t db_dr2;
+db_varfcn_t db_dr3;
+db_varfcn_t db_dr4;
+db_varfcn_t db_dr5;
+db_varfcn_t db_dr6;
+db_varfcn_t db_dr7;
+
+/*
+ * Machine register set.
+ */
+struct db_variable db_regs[] = {
+       { "cs",         &ddb_regs.tf_cs,     NULL },
+/*     { "ds",         &ddb_regs.tf_ds,     NULL },
+       { "es",         &ddb_regs.tf_es,     NULL },
+       { "fs",         &ddb_regs.tf_fs,     NULL },
+       { "gs",         &ddb_regs.tf_gs,     NULL }, */
+       { "ss",         &ddb_regs.tf_ss,     NULL },
+       { "rax",        &ddb_regs.tf_rax,    NULL },
+       { "rcx",        &ddb_regs.tf_rcx,    NULL },
+       { "rdx",        &ddb_regs.tf_rdx,    NULL },
+       { "rbx",        &ddb_regs.tf_rbx,    NULL },
+       { "rsp",        &ddb_regs.tf_rsp,    NULL },
+       { "rbp",        &ddb_regs.tf_rbp,    NULL },
+       { "rsi",        &ddb_regs.tf_rsi,    NULL },
+       { "rdi",        &ddb_regs.tf_rdi,    NULL },
+       { "rip",        &ddb_regs.tf_rip,    NULL },
+       { "rfl",        &ddb_regs.tf_rflags, NULL },
+       { "r8",         &ddb_regs.tf_r8,     NULL },
+       { "r9",         &ddb_regs.tf_r9,     NULL },
+       { "r10",        &ddb_regs.tf_r10,    NULL },
+       { "r11",        &ddb_regs.tf_r11,    NULL },
+       { "r12",        &ddb_regs.tf_r12,    NULL },
+       { "r13",        &ddb_regs.tf_r13,    NULL },
+       { "r14",        &ddb_regs.tf_r14,    NULL },
+       { "r15",        &ddb_regs.tf_r15,    NULL },
+       { "dr0",        NULL,                db_dr0 },
+       { "dr1",        NULL,                db_dr1 },
+       { "dr2",        NULL,                db_dr2 },
+       { "dr3",        NULL,                db_dr3 },
+       { "dr4",        NULL,                db_dr4 },
+       { "dr5",        NULL,                db_dr5 },
+       { "dr6",        NULL,                db_dr6 },
+       { "dr7",        NULL,                db_dr7 },
+};
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Stack trace.
+ */
+#define        INKERNEL(va)    (((vm_offset_t)(va)) >= USRSTACK)
+
+struct amd64_frame {
+       struct amd64_frame      *f_frame;
+       long                    f_retaddr;
+       long                    f_arg0;
+};
+
+#define NORMAL         0
+#define        TRAP            1
+#define        INTERRUPT       2
+#define        SYSCALL         3
+
+static void    db_nextframe(struct amd64_frame **, db_addr_t *);
+static int     db_numargs(struct amd64_frame *);
+static void    db_print_stack_entry(const char *, int, char **, long *, db_addr_t);
+static void    dl_symbol_values(long callpc, const char **name);
+
+
+static char    *watchtype_str(int type);
+static int     kamd64_set_watch(int watchnum, unsigned int watchaddr,
+                               int size, int access, struct dbreg * d);
+static int     kamd64_clr_watch(int watchnum, struct dbreg * d);
+int            db_md_set_watchpoint(db_expr_t addr, db_expr_t size);
+int            db_md_clr_watchpoint(db_expr_t addr, db_expr_t size);
+void           db_md_list_watchpoints(void);
+
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ */
+static int
+db_numargs(struct amd64_frame *fp)
+{
+#if 1
+       return (0);     /* regparm, needs dwarf2 info */
+#else
+       int     args;
+#if 0
+       int     *argp;
+       int     inst;
+
+       argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
+       /*
+        * XXX etext is wrong for LKMs.  We should attempt to interpret
+        * the instruction at the return address in all cases.  This
+        * may require better fault handling.
+        */
+       if (argp < (int *)btext || argp >= (int *)etext) {
+               args = 5;
+       } else {
+               inst = db_get_value((int)argp, 4, FALSE);
+               if ((inst & 0xff) == 0x59)      /* popl %ecx */
+                       args = 1;
+               else if ((inst & 0xffff) == 0xc483)     /* addl $Ibs, %esp */
+                       args = ((inst >> 16) & 0xff) / 4;
+               else
+                       args = 5;
+       }
+#endif
+       args = 5;
+       return(args);
+#endif
+}
+
+static void
+db_print_stack_entry(const char *name, int narg, char **argnp, long *argp,
+                    db_addr_t callpc)
+{
+       db_printf("%s(", name);
+       while (narg) {
+               if (argnp)
+                       db_printf("%s=", *argnp++);
+               db_printf("%ld", (long)db_get_value((long)argp, 8, FALSE));
+               argp++;
+               if (--narg != 0)
+                       db_printf(",");
+       }
+       db_printf(") at ");
+       db_printsym(callpc, DB_STGY_PROC);
+       db_printf("\n");
+}
+
+/*
+ * Figure out the next frame up in the call stack.
+ */
+static void
+db_nextframe(struct amd64_frame **fp, db_addr_t *ip)
+{
+       struct trapframe *tf;
+       int frame_type;
+       long rip, rsp, rbp;
+       db_expr_t offset;
+       const char *sym, *name;
+
+       if ((unsigned long)*fp < PAGE_SIZE) {
+               *fp = NULL;
+               return;
+       }
+       rip = db_get_value((long) &(*fp)->f_retaddr, 8, FALSE);
+       rbp = db_get_value((long) &(*fp)->f_frame, 8, FALSE);
+
+       /*
+        * Figure out frame type.
+        */
+
+       frame_type = NORMAL;
+
+       sym = db_search_symbol(rip, DB_STGY_ANY, &offset);
+       db_symbol_values(sym, &name, NULL);
+       dl_symbol_values(rip, &name);
+       if (name != NULL) {
+               if (!strcmp(name, "calltrap")) {
+                       frame_type = TRAP;
+               } else if (!strncmp(name, "Xresume", 7)) {
+                       frame_type = INTERRUPT;
+               } else if (!strcmp(name, "_Xsyscall")) {
+                       frame_type = SYSCALL;
+               }
+       }
+
+       /*
+        * Normal frames need no special processing.
+        */
+       if (frame_type == NORMAL) {
+               *ip = (db_addr_t) rip;
+               *fp = (struct amd64_frame *) rbp;
+               return;
+       }
+
+       db_print_stack_entry(name, 0, 0, 0, rip);
+
+       /*
+        * Point to base of trapframe which is just above the
+        * current frame.
+        */
+       tf = (struct trapframe *)((long)*fp + 16);
+
+#if 0
+       rsp = (ISPL(tf->tf_cs) == SEL_UPL) ?  tf->tf_rsp : (long)&tf->tf_rsp;
+#endif
+       rsp = (long)&tf->tf_rsp;
+
+       switch (frame_type) {
+       case TRAP:
+               {
+                       rip = tf->tf_rip;
+                       rbp = tf->tf_rbp;
+                       db_printf(
+           "--- trap %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
+                           tf->tf_trapno, rip, rsp, rbp);
+               }
+               break;
+       case SYSCALL:
+               {
+                       rip = tf->tf_rip;
+                       rbp = tf->tf_rbp;
+                       db_printf(
+       "--- syscall %016lx, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
+                           tf->tf_rax, rip, rsp, rbp);
+               }
+               break;
+       case INTERRUPT:
+               tf = (struct trapframe *)((long)*fp + 16);
+               {
+                       rip = tf->tf_rip;
+                       rbp = tf->tf_rbp;
+                       db_printf(
+           "--- interrupt, rip = %016lx, rsp = %016lx, rbp = %016lx ---\n",
+                           rip, rsp, rbp);
+               }
+               break;
+       default:
+               break;
+       }
+
+       *ip = (db_addr_t) rip;
+       *fp = (struct amd64_frame *) rbp;
+}
+
+void
+db_stack_trace_cmd(db_expr_t addr, boolean_t have_addr, db_expr_t count,
+                  char *modif)
+{
+       struct amd64_frame *frame;
+       long *argp;
+       db_addr_t callpc;
+       boolean_t first;
+       int i;
+
+       if (count == -1)
+               count = 1024;
+
+       if (!have_addr) {
+               frame = (struct amd64_frame *)BP_REGS(&ddb_regs);
+               if (frame == NULL)
+                       frame = (struct amd64_frame *)(SP_REGS(&ddb_regs) - 8);
+               callpc = PC_REGS(&ddb_regs);
+       } else {
+               /*
+                * Look for something that might be a frame pointer, just as
+                * a convenience.
+                */
+               frame = (struct amd64_frame *)addr;
+               for (i = 0; i < 4096; i += 8) {
+                       struct amd64_frame *check;
+
+                       check = (struct amd64_frame *)db_get_value((long)((char *)&frame->f_frame + i), 8, FALSE);
+                       if ((char *)check - (char *)frame >= 0 &&
+                           (char *)check - (char *)frame < 4096
+                       ) {
+                               break;
+                       }
+                       db_printf("%p does not look like a stack frame, skipping\n", (char *)&frame->f_frame + i);
+               }
+               if (i == 4096) {
+                       db_printf("Unable to find anything that looks like a stack frame\n");
+                       return;
+               }
+               frame = (void *)((char *)frame + i);
+               db_printf("Trace beginning at frame %p\n", frame);
+               callpc = (db_addr_t)db_get_value((long)&frame->f_retaddr, 8, FALSE);
+       }
+
+       first = TRUE;
+       while (count--) {
+               struct amd64_frame *actframe;
+               int             narg;
+               const char *    name;
+               db_expr_t       offset;
+               c_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);
+               dl_symbol_values(callpc, &name);
+
+               /*
+                * Attempt to determine a (possibly fake) frame that gives
+                * the caller's pc.  It may differ from `frame' if the
+                * current function never sets up a standard frame or hasn't
+                * set one up yet or has just discarded one.  The last two
+                * cases can be guessed fairly reliably for code generated
+                * by gcc.  The first case is too much trouble to handle in
+                * general because the amount of junk on the stack depends
+                * on the pc (the special handling of "calltrap", etc. in
+                * db_nextframe() works because the `next' pc is special).
+                */
+               actframe = frame;
+               if (first) {
+                       if (!have_addr) {
+                               int instr;
+
+                               instr = db_get_value(callpc, 4, FALSE);
+                               if ((instr & 0xffffffff) == 0xe5894855) {
+                                       /* pushq %rbp; movq %rsp, %rbp */
+                                       actframe = (struct amd64_frame *)
+                                           (SP_REGS(&ddb_regs) - 8);
+                               } else if ((instr & 0xffffff) == 0xe58948) {
+                                       /* movq %rsp, %rbp */
+                                       actframe = (struct amd64_frame *)
+                                           SP_REGS(&ddb_regs);
+                                       if (ddb_regs.tf_rbp == 0) {
+                                               /* Fake caller's frame better. */
+                                               frame = actframe;
+                                       }
+                               } else if ((instr & 0xff) == 0xc3) {
+                                       /* ret */
+                                       actframe = (struct amd64_frame *)
+                                           (SP_REGS(&ddb_regs) - 8);
+                               } else if (offset == 0) {
+                                       /* Probably a symbol in assembler code. */
+                                       actframe = (struct amd64_frame *)
+                                           (SP_REGS(&ddb_regs) - 8);
+                               }
+                       } else if (name != NULL &&
+                                  strcmp(name, "fork_trampoline") == 0) {
+                               /*
+                                * Don't try to walk back on a stack for a
+                                * process that hasn't actually been run yet.
+                                */
+                               db_print_stack_entry(name, 0, 0, 0, callpc);
+                               break;
+                       }
+                       first = FALSE;
+               }
+
+               argp = &actframe->f_arg0;
+               narg = MAXNARG;
+               if (sym != NULL && db_sym_numargs(sym, &narg, argnames)) {
+                       argnp = argnames;
+               } else {
+                       narg = db_numargs(frame);
+               }
+
+               db_print_stack_entry(name, narg, argnp, argp, callpc);
+
+               if (actframe != frame) {
+                       /* `frame' belongs to caller. */
+                       callpc = (db_addr_t)
+                           db_get_value((long)&actframe->f_retaddr, 8, FALSE);
+                       continue;
+               }
+
+               db_nextframe(&frame, &callpc);
+               if (frame == 0)
+                       break;
+       }
+}
+
+void
+print_backtrace(void)
+{
+       register_t  rbp;
+
+       __asm __volatile("movq %%rbp, %0" : "=r" (rbp));
+       db_stack_trace_cmd(rbp, 1, -1, NULL);
+}
+
+#define DB_DRX_FUNC(reg)                                               \
+int                                                                    \
+db_ ## reg (struct db_variable *vp, db_expr_t *valuep, int op)         \
+{                                                                      \
+       if (op == DB_VAR_GET)                                           \
+               *valuep = r ## reg ();                                  \
+       else                                                            \
+               load_ ## reg (*valuep);                                 \
+                                                                       \
+       return(0);                                                      \
+}
+
+DB_DRX_FUNC(dr0)
+DB_DRX_FUNC(dr1)
+DB_DRX_FUNC(dr2)
+DB_DRX_FUNC(dr3)
+DB_DRX_FUNC(dr4)
+DB_DRX_FUNC(dr5)
+DB_DRX_FUNC(dr6)
+DB_DRX_FUNC(dr7)
+
+static int
+kamd64_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
+              struct dbreg *d)
+{
+       int i;
+       unsigned int mask;
+
+       if (watchnum == -1) {
+               for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
+                       if ((d->dr[7] & mask) == 0)
+                               break;
+               if (i < 4)
+                       watchnum = i;
+               else
+                       return(-1);
+       }
+
+       switch (access) {
+       case DBREG_DR7_EXEC:
+               size = 1; /* size must be 1 for an execution breakpoint */
+               /* fall through */
+       case DBREG_DR7_WRONLY:
+       case DBREG_DR7_RDWR:
+               break;
+       default:
+               return(-1);
+       }
+
+       /*
+        * we can watch a 1, 2, 4, or 8 byte sized location
+        */
+       switch (size) {
+       case 1:
+               mask = 0x00;
+               break;
+       case 2:
+               mask = 0x01 << 2;
+               break;
+       case 4:
+               mask = 0x03 << 2;
+       case 8:
+               mask = 0x02 << 2;
+               break;
+       default:
+               return(-1);
+       }
+
+       mask |= access;
+
+       /* clear the bits we are about to affect */
+       d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
+
+       /* set drN register to the address, N=watchnum */
+       DBREG_DRX(d, watchnum) = watchaddr;
+
+       /* enable the watchpoint */
+       d->dr[7] |= (0x2 << (watchnum * 2)) | (mask << (watchnum * 4 + 16));
+
+       return(watchnum);
+}
+
+
+int
+kamd64_clr_watch(int watchnum, struct dbreg *d)
+{
+       if (watchnum < 0 || watchnum >= 4)
+               return(-1);
+
+       d->dr[7] &= ~((0x3 << (watchnum * 2)) | (0x0f << (watchnum * 4 + 16)));
+       DBREG_DRX(d, watchnum) = 0;
+
+       return(0);
+}
+
+
+int
+db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
+{
+       int avail, wsize;
+       int i;
+       struct dbreg d;
+
+       fill_dbregs(NULL, &d);
+
+       avail = 0;
+       for (i = 0; i < 4; i++) {
+               if ((d.dr[7] & (3 << (i * 2))) == 0)
+                       avail++;
+       }
+
+       if (avail * 8 < size)
+               return(-1);
+
+       for (i=0; i < 4 && (size != 0); i++) {
+               if ((d.dr[7] & (3 << (i * 2))) == 0) {
+                       if (size >= 8 || (avail == 1 && size > 4))
+                               wsize = 8;
+                       else if (size > 2)
+                               wsize = 4;
+                       else
+                               wsize = size;
+                       if (wsize == 3)
+                               wsize++;
+                       kamd64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, &d);
+                       addr += wsize;
+                       size -= wsize;
+               }
+       }
+
+       set_dbregs(NULL, &d);
+
+       return(0);
+}
+
+int
+db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
+{
+       struct dbreg d;
+       int i;
+
+       fill_dbregs(NULL, &d);
+
+       for(i = 0; i < 4; i++) {
+               if (d.dr[7] & (3 << (i * 2))) {
+                       if ((DBREG_DRX((&d), i) >= addr) &&
+                           (DBREG_DRX((&d), i) < addr + size))
+                               kamd64_clr_watch(i, &d);
+               }
+       }
+
+       set_dbregs(NULL, &d);
+
+       return(0);
+}
+
+static char *
+watchtype_str(int type)
+{
+       switch (type) {
+       case DBREG_DR7_EXEC:
+               return "execute";
+       case DBREG_DR7_RDWR:
+               return "read/write";
+       case DBREG_DR7_WRONLY:
+               return "write";
+       default:
+               return "invalid";
+       }
+}
+
+void
+db_md_list_watchpoints(void)
+{
+       int i;
+       struct dbreg d;
+
+       fill_dbregs(NULL, &d);
+
+       db_printf("\nhardware watchpoints:\n");
+       db_printf("  watch    status        type  len     address\n"
+                 "  -----  --------  ----------  ---  ----------\n");
+       for (i = 0; i < 4; i++) {
+               if (d.dr[7] & (0x03 << (i * 2))) {
+                       unsigned type, len;
+                       type = (d.dr[7] >> (16 + (i * 4))) & 3;
+                       len =  (d.dr[7] >> (16 + (i * 4) + 2)) & 3;
+                       db_printf("  %-5d  %-8s  %10s  %3d  0x%08lx\n",
+                                 i, "enabled", watchtype_str(type),
+                                 len + 1, DBREG_DRX((&d), i));
+               } else {
+                       db_printf("  %-5d  disabled\n", i);
+               }
+       }
+
+       db_printf("\ndebug register values:\n");
+       for (i = 0; i < 8; i++)
+               db_printf("  dr%d 0x%08lx\n", i, DBREG_DRX((&d),i));
+       db_printf("\n");
+}
+
+/*
+ * See if dladdr() can get the symbol name via the standard dynamic loader.
+ */
+static
+void
+dl_symbol_values(long callpc, const char **name)
+{
+       Dl_info info;
+
+/*
+       if (*name == NULL) {
+               if (dladdr((const void *)callpc, &info) != 0) {
+                       if (info.dli_saddr <= (const void *)callpc)
+                               *name = info.dli_sname;
+               }
+       }
+*/
+}
diff --git a/sys/platform/vkernel64/amd64/exception.c b/sys/platform/vkernel64/amd64/exception.c
new file mode 100644 (file)
index 0000000..edb0306
--- /dev/null
@@ -0,0 +1,203 @@
+
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/i386/exception.c,v 1.11 2008/04/28 07:05:09 dillon Exp $
+ */
+
+#include "opt_ddb.h"
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/reboot.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/reboot.h>
+#include <ddb/ddb.h>
+
+#include <sys/thread2.h>
+
+#include <machine/trap.h>
+#include <machine/md_var.h>
+#include <machine/segments.h>
+#include <machine/cpu.h>
+#include <machine/smp.h>
+
+#include <err.h>
+#include <signal.h>
+#include <unistd.h>
+
+int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
+int _udatasel = GSEL(GUDATA_SEL, SEL_UPL);
+
+static void exc_segfault(int signo, siginfo_t *info, void *ctx);
+#ifdef DDB
+static void exc_debugger(int signo, siginfo_t *info, void *ctx);
+#endif
+
+#ifdef SMP
+
+/*
+ * IPIs are 'fast' interrupts, so we deal with them directly from our
+ * signal handler.
+ *
+ * WARNING: Signals are not physically disabled here so we have to enter
+ * our critical section before bumping gd_intr_nesting_level or another
+ * interrupt can come along and get really confused.
+ */
+static
+void
+ipisig(int nada, siginfo_t *info, void *ctxp)
+{
+       if (curthread->td_pri < TDPRI_CRIT) {
+               curthread->td_pri += TDPRI_CRIT;
+               ++mycpu->gd_intr_nesting_level;
+               lwkt_process_ipiq();
+               --mycpu->gd_intr_nesting_level;
+               curthread->td_pri -= TDPRI_CRIT;
+       } else {
+               need_ipiq();
+       }
+}
+
+/*
+ * Unconditionally stop or restart a cpu.
+ *
+ * Note: cpu_mask_all_signals() masks all signals except SIGXCPU itself.
+ * SIGXCPU itself is blocked on entry to stopsig() by the signal handler
+ * itself.
+ *
+ * WARNING: Signals are not physically disabled here so we have to enter
+ * our critical section before bumping gd_intr_nesting_level or another
+ * interrupt can come along and get really confused.
+ */
+static
+void
+stopsig(int nada, siginfo_t *info, void *ctxp)
+{
+       sigset_t ss;
+
+       sigemptyset(&ss);
+       sigaddset(&ss, SIGALRM);
+       sigaddset(&ss, SIGIO);
+       sigaddset(&ss, SIGQUIT);
+       sigaddset(&ss, SIGUSR1);
+       sigaddset(&ss, SIGUSR2);
+       sigaddset(&ss, SIGTERM);
+       sigaddset(&ss, SIGWINCH);
+
+       curthread->td_pri += TDPRI_CRIT;
+       ++mycpu->gd_intr_nesting_level;
+       while (stopped_cpus & mycpu->gd_cpumask) {
+               sigsuspend(&ss);
+       }
+       --mycpu->gd_intr_nesting_level;
+       curthread->td_pri -= TDPRI_CRIT;
+}
+
+#endif
+
+#if 0
+
+/*
+ * SIGIO is used by cothreads to signal back into the virtual kernel.
+ */
+static
+void
+iosig(int nada, siginfo_t *info, void *ctxp)
+{
+       signalintr(4);
+}
+
+#endif
+
+void
+init_exceptions(void)
+{
+       struct sigaction sa;
+
+       bzero(&sa, sizeof(sa));
+       sa.sa_sigaction = exc_segfault;
+       sa.sa_flags |= SA_SIGINFO | SA_NODEFER;
+       sigemptyset(&sa.sa_mask);
+       sigaction(SIGBUS, &sa, NULL);
+       sigaction(SIGSEGV, &sa, NULL);
+       sigaction(SIGTRAP, &sa, NULL);
+       sigaction(SIGFPE, &sa, NULL);
+
+#ifdef DDB
+       sa.sa_sigaction = exc_debugger;
+       sigaction(SIGQUIT, &sa, NULL);
+#endif
+#ifdef SMP
+       sa.sa_sigaction = ipisig;
+       sigaction(SIGUSR1, &sa, NULL);
+       sa.sa_sigaction = stopsig;
+       sigaction(SIGXCPU, &sa, NULL);
+#endif
+#if 0
+       sa.sa_sigaction = iosig;
+       sigaction(SIGIO, &sa, NULL);
+#endif
+}
+
+/*
+ * This function handles a segmentation fault.
+ *
+ * XXX We assume that trapframe is a subset of ucontext.  It is as of
+ *     this writing.
+ */
+static void
+exc_segfault(int signo, siginfo_t *info, void *ctxp)
+{
+       ucontext_t *ctx = ctxp;
+
+#if 0
+       kprintf("CAUGHT SEGFAULT EIP %08x ERR %08x TRAPNO %d err %d\n",
+               ctx->uc_mcontext.mc_eip,
+               ctx->uc_mcontext.mc_err,
+               ctx->uc_mcontext.mc_trapno & 0xFFFF,
+               ctx->uc_mcontext.mc_trapno >> 16);
+#endif
+       kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi);
+       splz();
+}
+
+#ifdef DDB
+
+static void
+exc_debugger(int signo, siginfo_t *info, void *ctx)
+{
+       Debugger("interrupt from console");
+}
+
+#endif
diff --git a/sys/platform/vkernel64/amd64/fork_tramp.s b/sys/platform/vkernel64/amd64/fork_tramp.s
new file mode 100644 (file)
index 0000000..f5d2f2d
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD: src/sys/i386/i386/exception.s,v 1.65.2.3 2001/08/15 01:23:49 peter Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/fork_tramp.s,v 1.3 2007/01/22 19:37:04 corecode Exp $
+ */
+
+#include <machine/asmacros.h>
+#include <machine/segments.h>
+#include <machine/lock.h>
+#include <machine/psl.h>
+#include <machine/trap.h>
+
+#include "assym.s"
+
+       .text
+
+/*
+ * This function is what cpu_heavy_restore jumps to after a new process
+ * is created.  The LWKT subsystem switches while holding a critical
+ * section and we maintain that abstraction here (e.g. because
+ * cpu_heavy_restore needs it due to PCB_*() manipulation), then get out of
+ * it before calling the initial function (typically fork_return()) and/or
+ * returning to user mode.
+ *
+ * The MP lock is held on entry, but for processes fork_return(esi)
+ * releases it.  'doreti' always runs without the MP lock.
+ */
+ENTRY(fork_trampoline)
+       movq    PCPU(curthread),%rax
+       subl    $TDPRI_CRIT,TD_PRI(%rax)
+
+       /*
+        * cpu_set_fork_handler intercepts this function call to
+        * have this call a non-return function to stay in kernel mode.
+        *
+        * initproc has its own fork handler, start_init(), which DOES
+        * return.
+        *
+        * %rbx - chaining function (typically fork_return)
+        * %r12 -> %rdi (argument)
+        * frame-> %rsi (trap frame)
+        *
+        *   void (func:rbx)(arg:rdi, trapframe:rsi)
+        */
+       movq    %rsp, %rsi              /* pass trapframe by reference */
+       movq    %r12, %rdi              /* arg1 */
+       call    *%rbx                   /* function */
+
+       /* cut from syscall */
+
+       call    splz
+
+#if defined(INVARIANTS) && defined(SMP)
+       movq    PCPU(curthread),%rax
+       cmpl    $0,TD_MPCOUNT(%rax)
+       je      1f
+       movq    $pmsg4, %rdi
+       movl    TD_MPCOUNT(%rax), %esi
+       movq    %rbx, %rdx
+       xorl    %eax, %eax
+       call    panic
+pmsg4:  .asciz "fork_trampoline mpcount %d after calling %p"
+       /* JG what's the purpose of this alignment and is it enough on amd64? */
+       .p2align 2
+1:
+#endif
+       /*
+        * Return via doreti to handle ASTs.
+        *
+        * trapframe is at the top of the stack.
+        */
+       MEXITCOUNT
+       pushq   $0              /* if_vec */
+       movq    %rsp,%rdi       /* pass by reference */
+       call    go_user
+       /* NOT REACHED */
diff --git a/sys/platform/vkernel64/amd64/genassym.c b/sys/platform/vkernel64/amd64/genassym.c
new file mode 100644 (file)
index 0000000..56e34bf
--- /dev/null
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * Copyright (c) 2008 The DragonFly Project.
+ * 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: @(#)genassym.c    5.11 (Berkeley) 5/10/91
+ * $FreeBSD: src/sys/i386/i386/genassym.c,v 1.86.2.3 2002/03/03 05:42:49 nyan Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/genassym.c,v 1.2 2008/08/29 17:07:10 dillon Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/assym.h>
+#include <sys/interrupt.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/lock.h>
+#include <sys/resourcevar.h>
+#include <machine/frame.h>
+/*#include <machine/bootinfo.h>*/
+#include <machine/tss.h>
+#include <sys/vmmeter.h>
+#include <sys/machintr.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <vfs/nfs/nfsv2.h>
+#include <vfs/nfs/rpcv2.h>
+#include <vfs/nfs/nfs.h>
+#include <vfs/nfs/nfsdiskless.h>
+
+#include <machine/segments.h>
+#include <machine/sigframe.h>
+#include <machine/globaldata.h>
+#include <machine/specialreg.h>
+#include <machine/pcb.h>
+#include <machine/smp.h>
+
+ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap));
+ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active));
+
+ASSYM(LWP_VMSPACE, offsetof(struct lwp, lwp_vmspace));
+ASSYM(GD_CURTHREAD, offsetof(struct mdglobaldata, mi.gd_curthread));
+ASSYM(GD_CPUID, offsetof(struct mdglobaldata, mi.gd_cpuid));
+ASSYM(PCB_R15, offsetof(struct pcb, pcb_r15));
+ASSYM(PCB_R14, offsetof(struct pcb, pcb_r14));
+ASSYM(PCB_R13, offsetof(struct pcb, pcb_r13));
+ASSYM(PCB_R12, offsetof(struct pcb, pcb_r12));
+ASSYM(PCB_RBP, offsetof(struct pcb, pcb_rbp));
+ASSYM(PCB_RSP, offsetof(struct pcb, pcb_rsp));
+ASSYM(PCB_RBX, offsetof(struct pcb, pcb_rbx));
+ASSYM(PCB_RIP, offsetof(struct pcb, pcb_rip));
+ASSYM(TSS_RSP0, offsetof(struct amd64tss, tss_rsp0));
+
+ASSYM(PCB_DR0, offsetof(struct pcb, pcb_dr0));
+ASSYM(PCB_DR1, offsetof(struct pcb, pcb_dr1));
+ASSYM(PCB_DR2, offsetof(struct pcb, pcb_dr2));
+ASSYM(PCB_DR3, offsetof(struct pcb, pcb_dr3));
+ASSYM(PCB_DR6, offsetof(struct pcb, pcb_dr6));
+ASSYM(PCB_DR7, offsetof(struct pcb, pcb_dr7));
+ASSYM(PCB_DBREGS, PCB_DBREGS);
+ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
+ASSYM(PCB_FSBASE, offsetof(struct pcb, pcb_fsbase));
+ASSYM(PCB_GSBASE, offsetof(struct pcb, pcb_gsbase));
+ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save));
+
+ASSYM(PCB_SAVEFPU_SIZE, sizeof(union savefpu));
+ASSYM(SIGF_HANDLER, offsetof(struct sigframe, sf_ahu.sf_handler));
+ASSYM(SIGF_UC, offsetof(struct sigframe, sf_uc));
+
+ASSYM(TD_LWP, offsetof(struct thread, td_lwp));
+ASSYM(TD_PCB, offsetof(struct thread, td_pcb));
+ASSYM(TD_SP, offsetof(struct thread, td_sp));
+ASSYM(TD_PRI, offsetof(struct thread, td_pri));
+#ifdef SMP
+ASSYM(TD_MPCOUNT, offsetof(struct thread, td_mpcount));
+#endif
+ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
+ASSYM(TD_SAVEFPU, offsetof(struct thread, td_savefpu));
+ASSYM(TDF_RUNNING, TDF_RUNNING);
+ASSYM(GD_NPXTHREAD, offsetof(struct mdglobaldata, gd_npxthread));
+
+ASSYM(TDPRI_CRIT, TDPRI_CRIT);
diff --git a/sys/platform/vkernel64/amd64/global.s b/sys/platform/vkernel64/amd64/global.s
new file mode 100644 (file)
index 0000000..8f24608
--- /dev/null
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) Peter Wemm <peter@netplex.com.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/i386/globals.s,v 1.13.2.1 2000/05/16 06:58:06 dillon Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/global.s,v 1.2 2007/01/05 22:18:18 dillon Exp $
+ */
+
+#include <machine/asmacros.h>
+#include <machine/pmap.h>
+
+#include "assym.s"
+
+       /*
+        * Define the layout of the per-cpu address space.  This is
+        * "constructed" in locore.s on the BSP and in mp_machdep.c for
+        * each AP.  DO NOT REORDER THESE WITHOUT UPDATING THE REST!
+        *
+        * On UP the per-cpu address space is simply placed in the data
+        * segment.
+        */
+       .data
+
+       .globl  globaldata
+       .set    globaldata,0
+
+       /*
+        * Define layout of the global data.  On SMP this lives in
+        * the per-cpu address space, otherwise it's in the data segment.
+        */
+       .globl  gd_curthread, gd_npxthread, gd_reqflags, gd_common_tss
+       .set    gd_curthread,globaldata + GD_CURTHREAD
+       .set    gd_npxthread,globaldata + GD_NPXTHREAD
+       .set    gd_reqflags,globaldata + GD_REQFLAGS
+       .set    gd_common_tss,globaldata + GD_COMMON_TSS
+
+       .globl  gd_common_tssd, gd_tss_gdt
+       .set    gd_common_tssd,globaldata + GD_COMMON_TSSD
+       .set    gd_tss_gdt,globaldata + GD_TSS_GDT
+
+       .globl  gd_currentldt
+       .set    gd_currentldt,globaldata + GD_CURRENTLDT
+
+       .globl  gd_fpu_lock, gd_savefpu
+       .set    gd_fpu_lock, globaldata + GD_FPU_LOCK
+       .set    gd_savefpu, globaldata + GD_SAVEFPU
+
+       /*
+        * The BSP version of these get setup in locore.s and pmap.c, while
+        * the AP versions are setup in mp_machdep.c.
+        */
+       .globl  gd_cpuid, gd_other_cpus
+       .globl  gd_ss_eflags, gd_intr_nesting_level
+       .globl  gd_CMAP1, gd_CMAP2, gd_CMAP3, gd_PMAP1
+       .globl  gd_CADDR1, gd_CADDR2, gd_CADDR3, gd_PADDR1
+       .globl  gd_spending, gd_ipending, gd_fpending
+       .globl  gd_cnt
+
+       .set    gd_cpuid,globaldata + GD_CPUID
+       .set    gd_other_cpus,globaldata + GD_OTHER_CPUS
+       .set    gd_ss_eflags,globaldata + GD_SS_EFLAGS
+       .set    gd_intr_nesting_level,globaldata + GD_INTR_NESTING_LEVEL
+       .set    gd_CMAP1,globaldata + GD_PRV_CMAP1
+       .set    gd_CMAP2,globaldata + GD_PRV_CMAP2
+       .set    gd_CMAP3,globaldata + GD_PRV_CMAP3
+       .set    gd_PMAP1,globaldata + GD_PRV_PMAP1
+       .set    gd_CADDR1,globaldata + GD_PRV_CADDR1
+       .set    gd_CADDR2,globaldata + GD_PRV_CADDR2
+       .set    gd_CADDR3,globaldata + GD_PRV_CADDR3
+       .set    gd_PADDR1,globaldata + GD_PRV_PADDR1
+       .set    gd_fpending,globaldata + GD_FPENDING
+       .set    gd_ipending,globaldata + GD_IPENDING
+       .set    gd_spending,globaldata + GD_SPENDING
+       .set    gd_cnt,globaldata + GD_CNT
diff --git a/sys/platform/vkernel64/amd64/locore.s b/sys/platform/vkernel64/amd64/locore.s
new file mode 100644 (file)
index 0000000..4bb63e9
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/i386/locore.s,v 1.6 2007/01/08 03:33:43 dillon Exp $
+ */
+
+#include <sys/syscall.h>
+#include <machine/asmacros.h>
+#include <machine/psl.h>
+#include "assym.s"
+
+       /*
+        * The sysinit and sysuninit sections have to be read-write data
+        * sections, not read-only data sections.
+        */
+       .section        set_sysinit_set, "aw"
+       .section        set_sysuninit_set, "aw"
+
+       .data
+       ALIGN_DATA              /* just to be sure */
+
+       /*
+        * Normally the startup code would begin here, but this is a
+        * virtual kernel so we just have a main() in platform/init.c
+        */
+
+       .text
+/**********************************************************************
+ *
+ * Signal trampoline, copied to top of user stack
+ *
+ * arguments: %rdi, %rsi, %rdx, %rcx
+ */
+NON_GPROF_ENTRY(sigcode)
+       call    *SIGF_HANDLER(%rsp)     /* call signal handler */
+       lea     SIGF_UC(%rsp),%rdi      /* get ucontext_t */
+       pushq   $0                      /* junk to fake return addr. */
+       movq    $SYS_sigreturn,%rax
+       syscall                         /* enter kernel with args */
+0:     hlt                             /* trap priviliged instruction */
+       jmp     0b
+
+       ALIGN_TEXT
+esigcode:
+
+/* void reset_dbregs() */
+ENTRY(reset_dbregs)
+       movq    $0x200,%rax   /* the manual says that bit 10 must be set to 1 */
+       movq    %rax,%dr7     /* disable all breapoints first */
+       movq    $0,%rax
+       movq    %rax,%dr0
+       movq    %rax,%dr1
+       movq    %rax,%dr2
+       movq    %rax,%dr3
+       movq    %rax,%dr6
+       ret
+
+       .data
+       .globl  szsigcode
+szsigcode:
+       .long   esigcode - sigcode
diff --git a/sys/platform/vkernel64/amd64/mp.c b/sys/platform/vkernel64/amd64/mp.c
new file mode 100644 (file)
index 0000000..155647f
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/i386/mp.c,v 1.8 2008/05/07 17:19:46 dillon Exp $
+ */
+
+
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/memrange.h>
+#include <sys/tls.h>
+#include <sys/types.h>
+
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/globaldata.h>
+#include <machine/md_var.h>
+#include <machine/pmap.h>
+#include <machine/smp.h>
+#include <machine/tls.h>
+
+#include <unistd.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+
+extern pt_entry_t *KPTphys;
+
+volatile u_int stopped_cpus;
+cpumask_t      smp_active_mask = 1;  /* which cpus are ready for IPIs etc? */
+static int     boot_address;
+static cpumask_t smp_startup_mask = 1;  /* which cpus have been started */
+int            mp_naps;                /* # of Applications processors */
+static int  mp_finish;
+
+/* function prototypes XXX these should go elsewhere */
+void bootstrap_idle(void);
+void single_cpu_ipi(int, int, int);
+void selected_cpu_ipi(u_int, int, int);
+#if 0
+void ipi_handler(int);
+#endif
+
+pt_entry_t *SMPpt;
+
+/* AP uses this during bootstrap.  Do not staticize.  */
+char *bootSTK;
+static int bootAP;
+
+
+/* XXX these need to go into the appropriate header file */
+static int start_all_aps(u_int);
+void init_secondary(void);
+void *start_ap(void *);
+
+/*
+ * Get SMP fully working before we start initializing devices.
+ */
+static
+void
+ap_finish(void)
+{
+       int i;
+       cpumask_t ncpus_mask = 0;
+
+       for (i = 1; i <= ncpus; i++)
+               ncpus_mask |= (1 << i);
+
+        mp_finish = 1;
+        if (bootverbose)
+                kprintf("Finish MP startup\n");
+
+       /* build our map of 'other' CPUs */
+       mycpu->gd_other_cpus = smp_startup_mask & ~(1 << mycpu->gd_cpuid);
+
+       /*
+        * Let the other cpu's finish initializing and build their map
+        * of 'other' CPUs.
+        */
+        rel_mplock();
+        while (smp_active_mask != smp_startup_mask) {
+               DELAY(100000);
+                cpu_lfence();
+       }
+
+        while (try_mplock() == 0)
+               DELAY(100000);
+        if (bootverbose)
+                kprintf("Active CPU Mask: %08x\n", smp_active_mask);
+}
+
+SYSINIT(finishsmp, SI_BOOT2_FINISH_SMP, SI_ORDER_FIRST, ap_finish, NULL)
+
+
+void *
+start_ap(void *arg __unused)
+{
+       init_secondary();
+       setrealcpu();
+       bootstrap_idle();
+
+       return(NULL); /* NOTREACHED */
+}
+
+/* storage for AP thread IDs */
+pthread_t ap_tids[MAXCPU];
+
+void
+mp_start(void)
+{
+       int shift;
+
+       ncpus = optcpus;
+
+       mp_naps = ncpus - 1;
+
+       /* ncpus2 -- ncpus rounded down to the nearest power of 2 */
+       for (shift = 0; (1 << shift) <= ncpus; ++shift)
+               ;
+       --shift;
+       ncpus2_shift = shift;
+       ncpus2 = 1 << shift;
+       ncpus2_mask = ncpus2 - 1;
+
+        /* ncpus_fit -- ncpus rounded up to the nearest power of 2 */
+        if ((1 << shift) < ncpus)
+                ++shift;
+        ncpus_fit = 1 << shift;
+        ncpus_fit_mask = ncpus_fit - 1;
+
+       /*
+        * cpu0 initialization
+        */
+       mycpu->gd_ipiq = (void *)kmem_alloc(&kernel_map,
+                                           sizeof(lwkt_ipiq) * ncpus);
+       bzero(mycpu->gd_ipiq, sizeof(lwkt_ipiq) * ncpus);
+
+       /*
+        * cpu 1-(n-1)
+        */
+       start_all_aps(boot_address);
+
+}
+
+void
+mp_announce(void)
+{
+       int x;
+
+       kprintf("DragonFly/MP: Multiprocessor\n");
+       kprintf(" cpu0 (BSP)\n");
+
+       for (x = 1; x <= mp_naps; ++x)
+               kprintf(" cpu%d (AP)\n", x);
+}
+
+void
+forward_fastint_remote(void *arg)
+{
+       panic("XXX forward_fastint_remote()");
+}
+
+void
+cpu_send_ipiq(int dcpu)
+{
+       if ((1 << dcpu) & smp_active_mask)
+               if (pthread_kill(ap_tids[dcpu], SIGUSR1) != 0)
+                       panic("pthread_kill failed in cpu_send_ipiq");
+#if 0
+       panic("XXX cpu_send_ipiq()");
+#endif
+}
+
+void
+smp_invltlb(void)
+{
+#ifdef SMP
+#endif
+}
+
+void
+single_cpu_ipi(int cpu, int vector, int delivery_mode)
+{
+       kprintf("XXX single_cpu_ipi\n");
+}
+
+void
+selected_cpu_ipi(u_int target, int vector, int delivery_mode)
+{
+       crit_enter();
+       while (target) {
+               int n = bsfl(target);
+               target &= ~(1 << n);
+               single_cpu_ipi(n, vector, delivery_mode);
+       }
+       crit_exit();
+}
+
+int
+stop_cpus(u_int map)
+{
+       map &= smp_active_mask;
+
+       crit_enter();
+       while (map) {
+               int n = bsfl(map);
+               map &= ~(1 << n);
+               stopped_cpus |= 1 << n;
+               if (pthread_kill(ap_tids[n], SIGXCPU) != 0)
+                       panic("stop_cpus: pthread_kill failed");
+       }
+       crit_exit();
+#if 0
+       panic("XXX stop_cpus()");
+#endif
+
+       return(1);
+}
+
+int
+restart_cpus(u_int map)
+{
+       map &= smp_active_mask;
+
+       crit_enter();
+       while (map) {
+               int n = bsfl(map);
+               map &= ~(1 << n);
+               stopped_cpus &= ~(1 << n);
+               if (pthread_kill(ap_tids[n], SIGXCPU) != 0)
+                       panic("restart_cpus: pthread_kill failed");
+       }
+       crit_exit();
+#if 0
+       panic("XXX restart_cpus()");
+#endif
+
+       return(1);
+}
+
+void
+ap_init(void)
+{
+        /*
+         * Adjust smp_startup_mask to signal the BSP that we have started
+         * up successfully.  Note that we do not yet hold the BGL.  The BSP
+         * is waiting for our signal.
+         *
+         * We can't set our bit in smp_active_mask yet because we are holding
+         * interrupts physically disabled and remote cpus could deadlock
+         * trying to send us an IPI.
+         */
+       smp_startup_mask |= 1 << mycpu->gd_cpuid;
+       cpu_mfence();
+
+        /*
+         * Interlock for finalization.  Wait until mp_finish is non-zero,
+         * then get the MP lock.
+         *
+         * Note: We are in a critical section.
+         *
+         * Note: We have to synchronize td_mpcount to our desired MP state
+         * before calling cpu_try_mplock().
+         *
+         * Note: we are the idle thread, we can only spin.
+         *
+         * Note: The load fence is memory volatile and prevents the compiler
+         * from improperly caching mp_finish, and the cpu from improperly
+         * caching it.
+         */
+
+       while (mp_finish == 0) {
+               cpu_lfence();
+               DELAY(500000);
+       }
+        ++curthread->td_mpcount;
+        while (cpu_try_mplock() == 0)
+               DELAY(100000);
+
+        /* BSP may have changed PTD while we're waiting for the lock */
+        cpu_invltlb();
+
+        /* Build our map of 'other' CPUs. */
+        mycpu->gd_other_cpus = smp_startup_mask & ~(1 << mycpu->gd_cpuid);
+
+        kprintf("SMP: AP CPU #%d Launched!\n", mycpu->gd_cpuid);
+
+
+        /* Set memory range attributes for this CPU to match the BSP */
+        mem_range_AP_init();
+        /*
+         * Once we go active we must process any IPIQ messages that may
+         * have been queued, because no actual IPI will occur until we
+         * set our bit in the smp_active_mask.  If we don't the IPI
+         * message interlock could be left set which would also prevent
+         * further IPIs.
+         *
+         * The idle loop doesn't expect the BGL to be held and while
+         * lwkt_switch() normally cleans things up this is a special case
+         * because we returning almost directly into the idle loop.
+         *
+         * The idle thread is never placed on the runq, make sure
+         * nothing we've done put it there.
+         */
+        KKASSERT(curthread->td_mpcount == 1);
+        smp_active_mask |= 1 << mycpu->gd_cpuid;
+
+       mdcpu->gd_fpending = 0;
+       mdcpu->gd_ipending = 0;
+       initclocks_pcpu();      /* clock interrupts (via IPIs) */
+       lwkt_process_ipiq();
+
+        /*
+         * Releasing the mp lock lets the BSP finish up the SMP init
+         */
+        rel_mplock();
+        KKASSERT((curthread->td_flags & TDF_RUNQ) == 0);
+}
+
+void
+init_secondary(void)
+{
+        int     myid = bootAP;
+        struct mdglobaldata *md;
+        struct privatespace *ps;
+
+        ps = &CPU_prvspace[myid];
+
+       KKASSERT(ps->mdglobaldata.mi.gd_prvspace == ps);
+
+       /*
+        * Setup the %gs for cpu #n.  The mycpu macro works after this
+        * point.  Note that %fs is used by pthreads.
+        */
+       tls_set_gs(&CPU_prvspace[myid], sizeof(struct privatespace));
+
+        md = mdcpu;     /* loaded through %gs:0 (mdglobaldata.mi.gd_prvspace)*/
+
+       /* JG */
+        md->gd_common_tss.tss_rsp0 = 0; /* not used until after switch */
+        //md->gd_common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
+        //md->gd_common_tss.tss_ioopt = (sizeof md->gd_common_tss) << 16;
+
+        /*
+         * Set to a known state:
+         * Set by mpboot.s: CR0_PG, CR0_PE
+         * Set by cpu_setregs: CR0_NE, CR0_MP, CR0_TS, CR0_WP, CR0_AM
+         */
+}
+
+static int
+start_all_aps(u_int boot_addr)
+{
+       int x, i;
+       struct mdglobaldata *gd;
+       struct privatespace *ps;
+       vm_page_t m;
+       vm_offset_t va;
+#if 0
+       struct lwp_params params;
+#endif
+
+       /*
+        * needed for ipis to initial thread
+        * FIXME: rename ap_tids?
+        */
+       ap_tids[0] = pthread_self();
+
+       for (x = 1; x <= mp_naps; x++)
+       {
+               /* Allocate space for the CPU's private space. */
+               va = (vm_offset_t)&CPU_prvspace[x];
+               for (i = 0; i < sizeof(struct mdglobaldata); i += PAGE_SIZE) {
+                       va =(vm_offset_t)&CPU_prvspace[x].mdglobaldata + i;
+                       m = vm_page_alloc(&kernel_object, va, VM_ALLOC_SYSTEM);
+                       pmap_kenter_quick(va, m->phys_addr);
+               }
+
+               for (i = 0; i < sizeof(CPU_prvspace[x].idlestack); i += PAGE_SIZE) {
+                       va =(vm_offset_t)&CPU_prvspace[x].idlestack + i;
+                       m = vm_page_alloc(&kernel_object, va, VM_ALLOC_SYSTEM);
+                       pmap_kenter_quick(va, m->phys_addr);
+               }
+
+                gd = &CPU_prvspace[x].mdglobaldata;     /* official location */
+                bzero(gd, sizeof(*gd));
+                gd->mi.gd_prvspace = ps = &CPU_prvspace[x];
+
+                /* prime data page for it to use */
+                mi_gdinit(&gd->mi, x);
+                cpu_gdinit(gd, x);
+
+#if 0
+                gd->gd_CMAP1 = pmap_kpte((vm_offset_t)CPU_prvspace[x].CPAGE1);
+                gd->gd_CMAP2 = pmap_kpte((vm_offset_t)CPU_prvspace[x].CPAGE2);
+                gd->gd_CMAP3 = pmap_kpte((vm_offset_t)CPU_prvspace[x].CPAGE3);
+                gd->gd_PMAP1 = pmap_kpte((vm_offset_t)CPU_prvspace[x].PPAGE1);
+                gd->gd_CADDR1 = ps->CPAGE1;
+                gd->gd_CADDR2 = ps->CPAGE2;
+                gd->gd_CADDR3 = ps->CPAGE3;
+                gd->gd_PADDR1 = (vpte_t *)ps->PPAGE1;
+#endif
+
+                gd->mi.gd_ipiq = (void *)kmem_alloc(&kernel_map, sizeof(lwkt_ipiq) * (mp_naps + 1));
+                bzero(gd->mi.gd_ipiq, sizeof(lwkt_ipiq) * (mp_naps + 1));
+
+                /*
+                 * Setup the AP boot stack
+                 */
+                bootSTK = &ps->idlestack[UPAGES*PAGE_SIZE/2];
+                bootAP = x;
+
+               /*
+                * Setup the AP's lwp, this is the 'cpu'
+                *
+                * We have to make sure our signals are masked or the new LWP
+                * may pick up a signal that it isn't ready for yet.  SMP
+                * startup occurs after SI_BOOT2_LEAVE_CRIT so interrupts
+                * have already been enabled.
+                */
+               cpu_disable_intr();
+               pthread_create(&ap_tids[x], NULL, start_ap, NULL);
+               cpu_enable_intr();
+
+               while((smp_startup_mask & (1 << x)) == 0) {
+                       cpu_lfence(); /* XXX spin until the AP has started */
+                       DELAY(1000);
+               }
+       }
+
+       return(ncpus - 1);
+}
diff --git a/sys/platform/vkernel64/amd64/mplock.s b/sys/platform/vkernel64/amd64/mplock.s
new file mode 100644 (file)
index 0000000..7bd0f5c
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * $FreeBSD: src/sys/i386/i386/mplock.s,v 1.29.2.2 2000/05/16 06:58:06 dillon Exp $
+ * $DragonFly: src/sys/platform/pc32/i386/mplock.s,v 1.21 2006/11/07 06:43:24 dillon Exp $
+ *
+ * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ *                             DragonFly MPLOCK operation
+ *
+ * Each thread has an MP lock count, td_mpcount, and there is a shared
+ * global called mp_lock.  mp_lock is the physical MP lock and contains either
+ * -1 or the cpuid of the cpu owning the lock.  The count is *NOT* integrated
+ * into mp_lock but instead resides in each thread td_mpcount.
+ *
+ * When obtaining or releasing the MP lock the td_mpcount is PREDISPOSED
+ * to the desired count *PRIOR* to operating on the mp_lock itself.  MP
+ * lock operations can occur outside a critical section with interrupts
+ * enabled with the provisio (which the routines below handle) that an
+ * interrupt may come along and preempt us, racing our cmpxchgl instruction
+ * to perform the operation we have requested by pre-disposing td_mpcount.
+ *
+ * Additionally, the LWKT threading system manages the MP lock and
+ * lwkt_switch(), in particular, may be called after pre-disposing td_mpcount
+ * to handle 'blocking' on the MP lock.
+ *
+ *
+ * Recoded from the FreeBSD original:
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ */
+
+#include <machine/asmacros.h>
+#if 0
+#include <machine_base/apic/apicreg.h>
+#endif
+
+#include "assym.s"
+
+/*
+ * YYY Debugging only.  Define this to be paranoid about invalidating the
+ * TLB when we get giant.
+ */
+#undef PARANOID_INVLTLB
+
+       .data
+       ALIGN_DATA
+#ifdef SMP
+       .globl  mp_lock
+mp_lock:
+       .long   -1                      /* initialized to not held */
+#endif
+
+       .text
+       SUPERALIGN_TEXT
+
+       /*
+        * Note on cmpxchgl... exchanges ecx with mem if mem matches eax.
+        * Z=1 (jz) on success.   A lock prefix is required for MP.
+        */
+NON_GPROF_ENTRY(cpu_get_initial_mplock)
+       movq    PCPU(curthread),%rcx
+       movl    $1,TD_MPCOUNT(%rcx)     /* curthread has mpcount of 1 */
+       movl    $0,mp_lock              /* owned by cpu 0 */
+       NON_GPROF_RET
+
+       /*
+        * cpu_try_mplock() returns non-zero on success, 0 on failure.  It
+        * only adjusts mp_lock, it does not touch td_mpcount.  Callers
+        * should always increment td_mpcount *before* trying to acquire
+        * the actual lock, predisposing td_mpcount to the desired state of
+        * the lock.
+        *
+        * NOTE! Only call cpu_try_mplock() inside a critical section.  If
+        * you don't an interrupt can come along and get and release
+        * the lock before our cmpxchgl instruction, causing us to fail
+        * but resulting in the lock being held by our cpu.
+        */
+NON_GPROF_ENTRY(cpu_try_mplock)
+       movl    PCPU(cpuid),%ecx
+       movl    $-1,%eax
+       lock cmpxchgl %ecx,mp_lock      /* ecx<->mem if eax matches */
+       jnz     1f
+#ifdef PARANOID_INVLTLB
+       movq    %cr3,%rax; movq %rax,%cr3       /* YYY check and remove */
+#endif
+       movl    $1,%eax
+       NON_GPROF_RET
+1:
+       subl    %eax,%eax
+       NON_GPROF_RET
+
+       /*
+        * get_mplock() Obtains the MP lock and may switch away if it cannot
+        * get it.  This routine may be called WITHOUT a critical section
+        * and with cpu interrupts enabled.
+        *
+        * To handle races in a sane fashion we predispose TD_MPCOUNT,
+        * which prevents us from losing the lock in a race if we already
+        * have it or happen to get it.  It also means that we might get
+        * the lock in an interrupt race before we have a chance to execute
+        * our cmpxchgl instruction, so we have to handle that case.
+        * Fortunately simply calling lwkt_switch() handles the situation
+        * for us and also 'blocks' us until the MP lock can be obtained.
+        */
+NON_GPROF_ENTRY(get_mplock)
+       movl    PCPU(cpuid),%ecx
+       movq    PCPU(curthread),%rdx
+       incl    TD_MPCOUNT(%rdx)        /* predispose */
+       cmpl    %ecx,mp_lock
+       jne     1f
+       NON_GPROF_RET                   /* success! */
+
+       /*
+        * We don't already own the mp_lock, use cmpxchgl to try to get
+        * it.
+        */
+1:
+       movl    $-1,%eax
+       lock cmpxchgl %ecx,mp_lock
+       jnz     2f
+       NON_GPROF_RET                   /* success */
+
+       /*
+        * Failure, but we could end up owning mp_lock anyway due to
+        * an interrupt race.  lwkt_switch() will clean up the mess
+        * and 'block' until the mp_lock is obtained.
+        *
+        * Create a stack frame for the call so KTR logs the stack
+        * backtrace properly.
+        */
+2:
+       pushq   %rbp
+       movq    %rsp,%rbp
+       call    lwkt_mp_lock_contested
+       popq    %rbp
+#ifdef INVARIANTS
+       movl    PCPU(cpuid),%eax        /* failure */
+       cmpl    %eax,mp_lock
+       jne     4f
+#endif
+       NON_GPROF_RET
+#ifdef INVARIANTS
+4:
+       cmpl    $0,panicstr             /* don't double panic */
+       je      badmp_get2
+       NON_GPROF_RET
+#endif
+
+       /*
+        * try_mplock() attempts to obtain the MP lock.  1 is returned on
+        * success, 0 on failure.  We do not have to be in a critical section
+        * and interrupts are almost certainly enabled.
+        *
+        * We must pre-dispose TD_MPCOUNT in order to deal with races in
+        * a reasonable way.
+        *
+        */
+NON_GPROF_ENTRY(try_mplock)
+       movl    PCPU(cpuid),%ecx
+       movq    PCPU(curthread),%rdx
+       incl    TD_MPCOUNT(%rdx)                /* pre-dispose for race */
+       cmpl    %ecx,mp_lock
+       je      1f                              /* trivial success */
+       movl    $-1,%eax
+       lock cmpxchgl %ecx,mp_lock
+       jnz     2f
+       /*
+        * Success
+        */
+#ifdef PARANOID_INVLTLB
+       movq    %cr3,%rax; movq %rax,%cr3       /* YYY check and remove */
+#endif
+1:
+       movl    $1,%eax                         /* success (cmpxchgl good!) */
+       NON_GPROF_RET
+
+       /*
+        * The cmpxchgl failed but we might have raced.  Undo the mess by
+        * predispoing TD_MPCOUNT and then checking.  If TD_MPCOUNT is
+        * still non-zero we don't care what state the lock is in (since
+        * we obviously didn't own it above), just return failure even if
+        * we won the lock in an interrupt race.  If TD_MPCOUNT is zero
+        * make sure we don't own the lock in case we did win it in a race.
+        */
+2:
+       decl    TD_MPCOUNT(%rdx)
+       cmpl    $0,TD_MPCOUNT(%rdx)
+       jne     3f
+       movl    PCPU(cpuid),%eax
+       movl    $-1,%ecx
+       lock cmpxchgl %ecx,mp_lock
+3:
+       subl    %eax,%eax
+       NON_GPROF_RET
+
+       /*
+        * rel_mplock() releases a previously obtained MP lock.
+        *
+        * In order to release the MP lock we pre-dispose TD_MPCOUNT for
+        * the release and basically repeat the release portion of try_mplock
+        * above.
+        */
+NON_GPROF_ENTRY(rel_mplock)
+       movq    PCPU(curthread),%rdx
+       movl    TD_MPCOUNT(%rdx),%eax
+#ifdef INVARIANTS
+       cmpl    $0,%eax
+       je      badmp_rel
+#endif
+       subl    $1,%eax
+       movl    %eax,TD_MPCOUNT(%rdx)
+       cmpl    $0,%eax
+       jne     3f
+       movl    PCPU(cpuid),%eax
+       movl    $-1,%ecx
+       lock cmpxchgl %ecx,mp_lock
+       movl    mp_lock_contention_mask,%eax
+       cmpl    $0,%eax
+       je      3f
+       call    lwkt_mp_lock_uncontested
+3:
+       NON_GPROF_RET
+
+#ifdef INVARIANTS
+
+badmp_get:
+       movq    $bmpsw1,%rdi
+       movl    $0,%eax
+       call    panic
+badmp_get2:
+       movq    $bmpsw1a,%rdi
+       movl    $0,%eax
+       call    panic
+badmp_rel:
+       movq    $bmpsw2,%rdi
+       movl    $0,%eax
+       call    panic
+
+       .data
+
+bmpsw1:
+       .asciz  "try/get_mplock(): already have lock! %d %p"
+
+bmpsw1a:
+       .asciz  "try/get_mplock(): failed on count or switch %d %p"
+
+bmpsw2:
+       .asciz  "rel_mplock(): mpcount already 0 @ %p %p %p %p %p %p %p %p!"
+
+#endif
diff --git a/sys/platform/vkernel64/amd64/npx.c b/sys/platform/vkernel64/amd64/npx.c
new file mode 100644 (file)
index 0000000..439b73b
--- /dev/null
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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: @(#)npx.c     7.2 (Berkeley) 5/12/91
+ * $FreeBSD: src/sys/i386/isa/npx.c,v 1.80.2.3 2001/10/20 19:04:38 tegge Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/npx.c,v 1.8 2008/01/29 19:54:56 dillon Exp $
+ */
+
+#include "opt_debug_npx.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/rman.h>
+#ifdef NPX_DEBUG
+#include <sys/syslog.h>
+#endif
+#include <sys/signalvar.h>
+#include <sys/thread2.h>
+
+#ifndef SMP
+#include <machine/asmacros.h>
+#endif
+#include <machine/cputypes.h>
+#include <machine/frame.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/psl.h>
+#ifndef SMP
+#include <machine/clock.h>
+#endif
+#include <machine/specialreg.h>
+#include <machine/segments.h>
+#include <machine/globaldata.h>
+
+#define        fldcw(addr)             __asm("fldcw %0" : : "m" (*(addr)))
+#define        fnclex()                __asm("fnclex")
+#define        fninit()                __asm("fninit")
+#define        fnop()                  __asm("fnop")
+#define        fnsave(addr)            __asm __volatile("fnsave %0" : "=m" (*(addr)))
+#define        fnstcw(addr)            __asm __volatile("fnstcw %0" : "=m" (*(addr)))
+#define        fnstsw(addr)            __asm __volatile("fnstsw %0" : "=m" (*(addr)))
+#define        frstor(addr)            __asm("frstor %0" : : "m" (*(addr)))
+#ifndef CPU_DISABLE_SSE
+#define        fxrstor(addr)           __asm("fxrstor %0" : : "m" (*(addr)))
+#define        fxsave(addr)            __asm __volatile("fxsave %0" : "=m" (*(addr)))
+#endif
+
+#ifndef CPU_DISABLE_SSE
+#define GET_FPU_EXSW_PTR(td) \
+       (cpu_fxsr ? \
+               &(td)->td_savefpu->sv_xmm.sv_ex_sw : \
+               &(td)->td_savefpu->sv_87.sv_ex_sw)
+#else /* CPU_DISABLE_SSE */
+#define GET_FPU_EXSW_PTR(td) \
+       (&(td)->td_savefpu->sv_87.sv_ex_sw)
+#endif /* CPU_DISABLE_SSE */
+
+typedef u_char bool_t;
+#ifndef CPU_DISABLE_SSE
+static void    fpu_clean_state(void);
+#endif
+
+int cpu_fxsr = 0;
+
+static struct krate badfprate = { 1 };
+
+/*static       int     npx_attach      (device_t dev);*/
+static void    fpusave         (union savefpu *);
+static void    fpurstor        (union savefpu *);
+
+#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(CPU_DISABLE_SSE)
+int mmxopt = 1;
+SYSCTL_INT(_kern, OID_AUTO, mmxopt, CTLFLAG_RD, &mmxopt, 0,
+       "MMX/XMM optimized bcopy/copyin/copyout support");
+#endif
+
+static int      hw_instruction_sse;
+SYSCTL_INT(_hw, OID_AUTO, instruction_sse, CTLFLAG_RD,
+    &hw_instruction_sse, 0, "SIMD/MMX2 instructions available in CPU");
+
+#if 0
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npx_attach(device_t dev)
+{
+       npxinit(__INITIAL_NPXCW__);
+       return (0);
+}
+#endif
+
+void
+init_fpu(int supports_sse)
+{
+       cpu_fxsr = hw_instruction_sse = supports_sse;
+}
+
+/*
+ * Initialize the floating point unit.
+ */
+void
+npxinit(u_short control)
+{
+       static union savefpu dummy __aligned(16);
+
+       /*
+        * fninit has the same h/w bugs as fnsave.  Use the detoxified
+        * fnsave to throw away any junk in the fpu.  npxsave() initializes
+        * the fpu and sets npxthread = NULL as important side effects.
+        */
+       npxsave(&dummy);
+       crit_enter();
+       /*stop_emulating();*/
+       fldcw(&control);
+       fpusave(curthread->td_savefpu);
+       mdcpu->gd_npxthread = NULL;
+       /*start_emulating();*/
+       crit_exit();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(void)
+{
+       if (curthread == mdcpu->gd_npxthread)
+               npxsave(curthread->td_savefpu);
+}
+
+#if 0
+/*
+ * The following mechanism is used to ensure that the FPE_... value
+ * that is passed as a trapcode to the signal handler of the user
+ * process does not have more than one bit set.
+ *
+ * Multiple bits may be set if the user process modifies the control
+ * word while a status word bit is already set.  While this is a sign
+ * of bad coding, we have no choise than to narrow them down to one
+ * bit, since we must not send a trapcode that is not exactly one of
+ * the FPE_ macros.
+ *
+ * The mechanism has a static table with 127 entries.  Each combination
+ * of the 7 FPU status word exception bits directly translates to a
+ * position in this table, where a single FPE_... value is stored.
+ * This FPE_... value stored there is considered the "most important"
+ * of the exception bits and will be sent as the signal code.  The
+ * precedence of the bits is based upon Intel Document "Numerical
+ * Applications", Chapter "Special Computational Situations".
+ *
+ * The macro to choose one of these values does these steps: 1) Throw
+ * away status word bits that cannot be masked.  2) Throw away the bits
+ * currently masked in the control word, assuming the user isn't
+ * interested in them anymore.  3) Reinsert status word bit 7 (stack
+ * fault) if it is set, which cannot be masked but must be presered.
+ * 4) Use the remaining bits to point into the trapcode table.
+ *
+ * The 6 maskable bits in order of their preference, as stated in the
+ * above referenced Intel manual:
+ * 1  Invalid operation (FP_X_INV)
+ * 1a   Stack underflow
+ * 1b   Stack overflow
+ * 1c   Operand of unsupported format
+ * 1d   SNaN operand.
+ * 2  QNaN operand (not an exception, irrelavant here)
+ * 3  Any other invalid-operation not mentioned above or zero divide
+ *      (FP_X_INV, FP_X_DZ)
+ * 4  Denormal operand (FP_X_DNML)
+ * 5  Numeric over/underflow (FP_X_OFL, FP_X_UFL)
+ * 6  Inexact result (FP_X_IMP)
+ */
+static char fpetable[128] = {
+       0,
+       FPE_FLTINV,     /*  1 - INV */
+       FPE_FLTUND,     /*  2 - DNML */
+       FPE_FLTINV,     /*  3 - INV | DNML */
+       FPE_FLTDIV,     /*  4 - DZ */
+       FPE_FLTINV,     /*  5 - INV | DZ */
+       FPE_FLTDIV,     /*  6 - DNML | DZ */
+       FPE_FLTINV,     /*  7 - INV | DNML | DZ */
+       FPE_FLTOVF,     /*  8 - OFL */
+       FPE_FLTINV,     /*  9 - INV | OFL */
+       FPE_FLTUND,     /*  A - DNML | OFL */
+       FPE_FLTINV,     /*  B - INV | DNML | OFL */
+       FPE_FLTDIV,     /*  C - DZ | OFL */
+       FPE_FLTINV,     /*  D - INV | DZ | OFL */
+       FPE_FLTDIV,     /*  E - DNML | DZ | OFL */
+       FPE_FLTINV,     /*  F - INV | DNML | DZ | OFL */
+       FPE_FLTUND,     /* 10 - UFL */
+       FPE_FLTINV,     /* 11 - INV | UFL */
+       FPE_FLTUND,     /* 12 - DNML | UFL */
+       FPE_FLTINV,     /* 13 - INV | DNML | UFL */
+       FPE_FLTDIV,     /* 14 - DZ | UFL */
+       FPE_FLTINV,     /* 15 - INV | DZ | UFL */
+       FPE_FLTDIV,     /* 16 - DNML | DZ | UFL */
+       FPE_FLTINV,     /* 17 - INV | DNML | DZ | UFL */
+       FPE_FLTOVF,     /* 18 - OFL | UFL */
+       FPE_FLTINV,     /* 19 - INV | OFL | UFL */
+       FPE_FLTUND,     /* 1A - DNML | OFL | UFL */
+       FPE_FLTINV,     /* 1B - INV | DNML | OFL | UFL */
+       FPE_FLTDIV,     /* 1C - DZ | OFL | UFL */
+       FPE_FLTINV,     /* 1D - INV | DZ | OFL | UFL */
+       FPE_FLTDIV,     /* 1E - DNML | DZ | OFL | UFL */
+       FPE_FLTINV,     /* 1F - INV | DNML | DZ | OFL | UFL */
+       FPE_FLTRES,     /* 20 - IMP */
+       FPE_FLTINV,     /* 21 - INV | IMP */
+       FPE_FLTUND,     /* 22 - DNML | IMP */
+       FPE_FLTINV,     /* 23 - INV | DNML | IMP */
+       FPE_FLTDIV,     /* 24 - DZ | IMP */
+       FPE_FLTINV,     /* 25 - INV | DZ | IMP */
+       FPE_FLTDIV,     /* 26 - DNML | DZ | IMP */
+       FPE_FLTINV,     /* 27 - INV | DNML | DZ | IMP */
+       FPE_FLTOVF,     /* 28 - OFL | IMP */
+       FPE_FLTINV,     /* 29 - INV | OFL | IMP */
+       FPE_FLTUND,     /* 2A - DNML | OFL | IMP */
+       FPE_FLTINV,     /* 2B - INV | DNML | OFL | IMP */
+       FPE_FLTDIV,     /* 2C - DZ | OFL | IMP */
+       FPE_FLTINV,     /* 2D - INV | DZ | OFL | IMP */
+       FPE_FLTDIV,     /* 2E - DNML | DZ | OFL | IMP */
+       FPE_FLTINV,     /* 2F - INV | DNML | DZ | OFL | IMP */
+       FPE_FLTUND,     /* 30 - UFL | IMP */
+       FPE_FLTINV,     /* 31 - INV | UFL | IMP */
+       FPE_FLTUND,     /* 32 - DNML | UFL | IMP */
+       FPE_FLTINV,     /* 33 - INV | DNML | UFL | IMP */
+       FPE_FLTDIV,     /* 34 - DZ | UFL | IMP */
+       FPE_FLTINV,     /* 35 - INV | DZ | UFL | IMP */
+       FPE_FLTDIV,     /* 36 - DNML | DZ | UFL | IMP */
+       FPE_FLTINV,     /* 37 - INV | DNML | DZ | UFL | IMP */
+       FPE_FLTOVF,     /* 38 - OFL | UFL | IMP */
+       FPE_FLTINV,     /* 39 - INV | OFL | UFL | IMP */
+       FPE_FLTUND,     /* 3A - DNML | OFL | UFL | IMP */
+       FPE_FLTINV,     /* 3B - INV | DNML | OFL | UFL | IMP */
+       FPE_FLTDIV,     /* 3C - DZ | OFL | UFL | IMP */
+       FPE_FLTINV,     /* 3D - INV | DZ | OFL | UFL | IMP */
+       FPE_FLTDIV,     /* 3E - DNML | DZ | OFL | UFL | IMP */
+       FPE_FLTINV,     /* 3F - INV | DNML | DZ | OFL | UFL | IMP */
+       FPE_FLTSUB,     /* 40 - STK */
+       FPE_FLTSUB,     /* 41 - INV | STK */
+       FPE_FLTUND,     /* 42 - DNML | STK */
+       FPE_FLTSUB,     /* 43 - INV | DNML | STK */
+       FPE_FLTDIV,     /* 44 - DZ | STK */
+       FPE_FLTSUB,     /* 45 - INV | DZ | STK */
+       FPE_FLTDIV,     /* 46 - DNML | DZ | STK */
+       FPE_FLTSUB,     /* 47 - INV | DNML | DZ | STK */
+       FPE_FLTOVF,     /* 48 - OFL | STK */
+       FPE_FLTSUB,     /* 49 - INV | OFL | STK */
+       FPE_FLTUND,     /* 4A - DNML | OFL | STK */
+       FPE_FLTSUB,     /* 4B - INV | DNML | OFL | STK */
+       FPE_FLTDIV,     /* 4C - DZ | OFL | STK */
+       FPE_FLTSUB,     /* 4D - INV | DZ | OFL | STK */
+       FPE_FLTDIV,     /* 4E - DNML | DZ | OFL | STK */
+       FPE_FLTSUB,     /* 4F - INV | DNML | DZ | OFL | STK */
+       FPE_FLTUND,     /* 50 - UFL | STK */
+       FPE_FLTSUB,     /* 51 - INV | UFL | STK */
+       FPE_FLTUND,     /* 52 - DNML | UFL | STK */
+       FPE_FLTSUB,     /* 53 - INV | DNML | UFL | STK */
+       FPE_FLTDIV,     /* 54 - DZ | UFL | STK */
+       FPE_FLTSUB,     /* 55 - INV | DZ | UFL | STK */
+       FPE_FLTDIV,     /* 56 - DNML | DZ | UFL | STK */
+       FPE_FLTSUB,     /* 57 - INV | DNML | DZ | UFL | STK */
+       FPE_FLTOVF,     /* 58 - OFL | UFL | STK */
+       FPE_FLTSUB,     /* 59 - INV | OFL | UFL | STK */
+       FPE_FLTUND,     /* 5A - DNML | OFL | UFL | STK */
+       FPE_FLTSUB,     /* 5B - INV | DNML | OFL | UFL | STK */
+       FPE_FLTDIV,     /* 5C - DZ | OFL | UFL | STK */
+       FPE_FLTSUB,     /* 5D - INV | DZ | OFL | UFL | STK */
+       FPE_FLTDIV,     /* 5E - DNML | DZ | OFL | UFL | STK */
+       FPE_FLTSUB,     /* 5F - INV | DNML | DZ | OFL | UFL | STK */
+       FPE_FLTRES,     /* 60 - IMP | STK */
+       FPE_FLTSUB,     /* 61 - INV | IMP | STK */
+       FPE_FLTUND,     /* 62 - DNML | IMP | STK */
+       FPE_FLTSUB,     /* 63 - INV | DNML | IMP | STK */
+       FPE_FLTDIV,     /* 64 - DZ | IMP | STK */
+       FPE_FLTSUB,     /* 65 - INV | DZ | IMP | STK */
+       FPE_FLTDIV,     /* 66 - DNML | DZ | IMP | STK */
+       FPE_FLTSUB,     /* 67 - INV | DNML | DZ | IMP | STK */
+       FPE_FLTOVF,     /* 68 - OFL | IMP | STK */
+       FPE_FLTSUB,     /* 69 - INV | OFL | IMP | STK */
+       FPE_FLTUND,     /* 6A - DNML | OFL | IMP | STK */
+       FPE_FLTSUB,     /* 6B - INV | DNML | OFL | IMP | STK */
+       FPE_FLTDIV,     /* 6C - DZ | OFL | IMP | STK */
+       FPE_FLTSUB,     /* 6D - INV | DZ | OFL | IMP | STK */
+       FPE_FLTDIV,     /* 6E - DNML | DZ | OFL | IMP | STK */
+       FPE_FLTSUB,     /* 6F - INV | DNML | DZ | OFL | IMP | STK */
+       FPE_FLTUND,     /* 70 - UFL | IMP | STK */
+       FPE_FLTSUB,     /* 71 - INV | UFL | IMP | STK */
+       FPE_FLTUND,     /* 72 - DNML | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 73 - INV | DNML | UFL | IMP | STK */
+       FPE_FLTDIV,     /* 74 - DZ | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 75 - INV | DZ | UFL | IMP | STK */
+       FPE_FLTDIV,     /* 76 - DNML | DZ | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 77 - INV | DNML | DZ | UFL | IMP | STK */
+       FPE_FLTOVF,     /* 78 - OFL | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 79 - INV | OFL | UFL | IMP | STK */
+       FPE_FLTUND,     /* 7A - DNML | OFL | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 7B - INV | DNML | OFL | UFL | IMP | STK */
+       FPE_FLTDIV,     /* 7C - DZ | OFL | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 7D - INV | DZ | OFL | UFL | IMP | STK */
+       FPE_FLTDIV,     /* 7E - DNML | DZ | OFL | UFL | IMP | STK */
+       FPE_FLTSUB,     /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */
+};
+#endif
+
+#if 0
+
+/*
+ * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
+ *
+ * Clearing exceptions is necessary mainly to avoid IRQ13 bugs.  We now
+ * depend on longjmp() restoring a usable state.  Restoring the state
+ * or examining it might fail if we didn't clear exceptions.
+ *
+ * The error code chosen will be one of the FPE_... macros. It will be
+ * sent as the second argument to old BSD-style signal handlers and as
+ * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers.
+ *
+ * XXX the FP state is not preserved across signal handlers.  So signal
+ * handlers cannot afford to do FP unless they preserve the state or
+ * longjmp() out.  Both preserving the state and longjmp()ing may be
+ * destroyed by IRQ13 bugs.  Clearing FP exceptions is not an acceptable
+ * solution for signals other than SIGFPE.
+ *
+ * The MP lock is not held on entry (see i386/i386/exception.s) and
+ * should not be held on exit.  Interrupts are enabled.  We must enter
+ * a critical section to stabilize the FP system and prevent an interrupt
+ * or preemption from changing the FP state out from under us.
+ */
+void
+npx_intr(void *dummy)
+{
+       int code;
+       u_short control;
+       struct intrframe *frame;
+       u_long *exstat;
+
+       crit_enter();
+
+       /*
+        * This exception can only occur with CR0_TS clear, otherwise we
+        * would get a DNA exception.  However, since interrupts were
+        * enabled a preemption could have sneaked in and used the FP system
+        * before we entered our critical section.  If that occured, the
+        * TS bit will be set and npxthread will be NULL.
+        */
+       panic("npx_intr: not coded");
+       /* XXX FP STATE FLAG MUST BE PART OF CONTEXT SUPPLIED BY REAL KERNEL */
+#if 0
+       if (rcr0() & CR0_TS) {
+               KASSERT(mdcpu->gd_npxthread == NULL, ("gd_npxthread was %p with TS set!", mdcpu->gd_npxthread));
+               npxdna();
+               crit_exit();
+               return;
+       }
+#endif
+       if (mdcpu->gd_npxthread == NULL) {
+               get_mplock();
+               kprintf("npxintr: npxthread = %p, curthread = %p\n",
+                      mdcpu->gd_npxthread, curthread);
+               panic("npxintr from nowhere");
+       }
+       if (mdcpu->gd_npxthread != curthread) {
+               get_mplock();
+               kprintf("npxintr: npxthread = %p, curthread = %p\n",
+                      mdcpu->gd_npxthread, curthread);
+               panic("npxintr from non-current process");
+       }
+
+       exstat = GET_FPU_EXSW_PTR(curthread);
+       outb(0xf0, 0);
+       fnstsw(exstat);
+       fnstcw(&control);
+       fnclex();
+
+       get_mplock();
+
+       /*
+        * Pass exception to process.
+        */
+       frame = (struct intrframe *)&dummy;     /* XXX */
+       if ((ISPL(frame->if_cs) == SEL_UPL) /*||(frame->if_eflags&PSL_VM)*/) {
+               /*
+                * Interrupt is essentially a trap, so we can afford to call
+                * the SIGFPE handler (if any) as soon as the interrupt
+                * returns.
+                *
+                * XXX little or nothing is gained from this, and plenty is
+                * lost - the interrupt frame has to contain the trap frame
+                * (this is otherwise only necessary for the rescheduling trap
+                * in doreti, and the frame for that could easily be set up
+                * just before it is used).
+                */
+               curthread->td_lwp->lwp_md.md_regs = INTR_TO_TRAPFRAME(frame);
+               /*
+                * Encode the appropriate code for detailed information on
+                * this exception.
+                */
+               code =
+                   fpetable[(*exstat & ~control & 0x3f) | (*exstat & 0x40)];
+               trapsignal(curthread->td_lwp, SIGFPE, code);
+       } else {
+               /*
+                * Nested interrupt.  These losers occur when:
+                *      o an IRQ13 is bogusly generated at a bogus time, e.g.:
+                *              o immediately after an fnsave or frstor of an
+                *                error state.
+                *              o a couple of 386 instructions after
+                *                "fstpl _memvar" causes a stack overflow.
+                *        These are especially nasty when combined with a
+                *        trace trap.
+                *      o an IRQ13 occurs at the same time as another higher-
+                *        priority interrupt.
+                *
+                * Treat them like a true async interrupt.
+                */
+               lwpsignal(curproc, curthread->td_lwp, SIGFPE);
+       }
+       rel_mplock();
+       crit_exit();
+}
+
+#endif
+
+/*
+ * Implement the device not available (DNA) exception.  gd_npxthread had
+ * better be NULL.  Restore the current thread's FP state and set gd_npxthread
+ * to curthread.
+ *
+ * Interrupts are enabled and preemption can occur.  Enter a critical
+ * section to stabilize the FP state.
+ */
+int
+npxdna(struct trapframe *frame)
+{
+       thread_t td = curthread;
+       u_long *exstat;
+       int didinit = 0;
+
+       if (mdcpu->gd_npxthread != NULL) {
+               kprintf("npxdna: npxthread = %p, curthread = %p\n",
+                      mdcpu->gd_npxthread, td);
+               panic("npxdna");
+       }
+
+       /*
+        * Setup the initial saved state if the thread has never before
+        * used the FP unit.  This also occurs when a thread pushes a
+        * signal handler and uses FP in the handler.
+        */
+       if ((curthread->td_flags & TDF_USINGFP) == 0) {
+               curthread->td_flags |= TDF_USINGFP;
+               npxinit(__INITIAL_NPXCW__);
+               didinit = 1;
+       }
+
+       /*
+        * The setting of gd_npxthread and the call to fpurstor() must not
+        * be preempted by an interrupt thread or we will take an npxdna
+        * trap and potentially save our current fpstate (which is garbage)
+        * and then restore the garbage rather then the originally saved
+        * fpstate.
+        */
+       crit_enter();
+       /*stop_emulating();*/
+       /*
+        * Record new context early in case frstor causes an IRQ13.
+        */
+       mdcpu->gd_npxthread = td;
+       exstat = GET_FPU_EXSW_PTR(td);
+       *exstat = 0;
+       /*
+        * The following frstor may cause an IRQ13 when the state being
+        * restored has a pending error.  The error will appear to have been
+        * triggered by the current (npx) user instruction even when that
+        * instruction is a no-wait instruction that should not trigger an
+        * error (e.g., fnclex).  On at least one 486 system all of the
+        * no-wait instructions are broken the same as frstor, so our
+        * treatment does not amplify the breakage.  On at least one
+        * 386/Cyrix 387 system, fnclex works correctly while frstor and
+        * fnsave are broken, so our treatment breaks fnclex if it is the
+        * first FPU instruction after a context switch.
+        */
+       if ((td->td_savefpu->sv_xmm.sv_env.en_mxcsr & ~0xFFBF) && cpu_fxsr) {
+               krateprintf(&badfprate,
+                           "FXRSTR: illegal FP MXCSR %08x didinit = %d\n",
+                           td->td_savefpu->sv_xmm.sv_env.en_mxcsr, didinit);
+               td->td_savefpu->sv_xmm.sv_env.en_mxcsr &= 0xFFBF;
+               lwpsignal(curproc, curthread->td_lwp, SIGFPE);
+       }
+       fpurstor(curthread->td_savefpu);
+       crit_exit();
+
+       return (1);
+}
+
+/*
+ * Wrapper for the fnsave instruction to handle h/w bugs.  If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems.  Force
+ * any IRQ13 to be handled immediately, and then ignore it.  This routine is
+ * often called at splhigh so it must not use many system services.  In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ *
+ * WARNING!  This call is made during a switch and the MP lock will be
+ * setup for the new target thread rather then the current thread, so we
+ * cannot do anything here that depends on the *_mplock() functions as
+ * we may trip over their assertions.
+ *
+ * WARNING!  When using fxsave we MUST fninit after saving the FP state.  The
+ * kernel will always assume that the FP state is 'safe' (will not cause
+ * exceptions) for mmx/xmm use if npxthread is NULL.  The kernel must still
+ * setup a custom save area before actually using the FP unit, but it will
+ * not bother calling fninit.  This greatly improves kernel performance when
+ * it wishes to use the FP unit.
+ */
+void
+npxsave(union savefpu *addr)
+{
+       crit_enter();
+       /*stop_emulating();*/
+       fpusave(addr);
+       mdcpu->gd_npxthread = NULL;
+       fninit();
+       /*start_emulating();*/
+       crit_exit();
+}
+
+static void
+fpusave(union savefpu *addr)
+{
+       if (cpu_fxsr)
+               fxsave(addr);
+       else
+               fnsave(addr);
+}
+
+/*
+ * Save the FP state to the mcontext structure.
+ *
+ * WARNING: If you want to try to npxsave() directly to mctx->mc_fpregs,
+ * then it MUST be 16-byte aligned.  Currently this is not guarenteed.
+ */
+void
+npxpush(mcontext_t *mctx)
+{
+       thread_t td = curthread;
+
+       if (td->td_flags & TDF_USINGFP) {
+               if (mdcpu->gd_npxthread == td) {
+                       /*
+                        * XXX Note: This is a bit inefficient if the signal
+                        * handler uses floating point, extra faults will
+                        * occur.
+                        */
+                       mctx->mc_ownedfp = _MC_FPOWNED_FPU;
+                       npxsave(td->td_savefpu);
+               } else {
+                       mctx->mc_ownedfp = _MC_FPOWNED_PCB;
+               }
+               bcopy(td->td_savefpu, mctx->mc_fpregs, sizeof(mctx->mc_fpregs));
+               td->td_flags &= ~TDF_USINGFP;
+               mctx->mc_fpformat =
+#ifndef CPU_DISABLE_SSE
+                       (cpu_fxsr) ? _MC_FPFMT_XMM :
+#endif
+                       _MC_FPFMT_387;
+       } else {
+               mctx->mc_ownedfp = _MC_FPOWNED_NONE;
+               mctx->mc_fpformat = _MC_FPFMT_NODEV;
+       }
+}
+
+/*
+ * Restore the FP state from the mcontext structure.
+ */
+void
+npxpop(mcontext_t *mctx)
+{
+       thread_t td = curthread;
+
+       switch(mctx->mc_ownedfp) {
+       case _MC_FPOWNED_NONE:
+               /*
+                * If the signal handler used the FP unit but the interrupted
+                * code did not, release the FP unit.  Clear TDF_USINGFP will
+                * force the FP unit to reinit so the interrupted code sees
+                * a clean slate.
+                */
+               if (td->td_flags & TDF_USINGFP) {
+                       if (td == mdcpu->gd_npxthread)
+                               npxsave(td->td_savefpu);
+                       td->td_flags &= ~TDF_USINGFP;
+               }
+               break;
+       case _MC_FPOWNED_FPU:
+       case _MC_FPOWNED_PCB:
+               /*
+                * Clear ownership of the FP unit and restore our saved state.
+                *
+                * NOTE: The signal handler may have set-up some FP state and
+                * enabled the FP unit, so we have to restore no matter what.
+                *
+                * XXX: This is bit inefficient, if the code being returned
+                * to is actively using the FP this results in multiple
+                * kernel faults.
+                *
+                * WARNING: The saved state was exposed to userland and may
+                * have to be sanitized to avoid a GP fault in the kernel.
+                */
+               if (td == mdcpu->gd_npxthread)
+                       npxsave(td->td_savefpu);
+               bcopy(mctx->mc_fpregs, td->td_savefpu, sizeof(*td->td_savefpu));
+               if ((td->td_savefpu->sv_xmm.sv_env.en_mxcsr & ~0xFFBF) &&
+                   cpu_fxsr) {
+                       krateprintf(&badfprate,
+                                   "pid %d (%s) signal return from user: "
+                                   "illegal FP MXCSR %08x\n",
+                                   td->td_proc->p_pid,
+                                   td->td_proc->p_comm,
+                                   td->td_savefpu->sv_xmm.sv_env.en_mxcsr);
+                       td->td_savefpu->sv_xmm.sv_env.en_mxcsr &= 0xFFBF;
+               }
+               td->td_flags |= TDF_USINGFP;
+               break;
+       }
+}
+
+
+#ifndef CPU_DISABLE_SSE
+/*
+ * On AuthenticAMD processors, the fxrstor instruction does not restore
+ * the x87's stored last instruction pointer, last data pointer, and last
+ * opcode values, except in the rare case in which the exception summary
+ * (ES) bit in the x87 status word is set to 1.
+ *
+ * In order to avoid leaking this information across processes, we clean
+ * these values by performing a dummy load before executing fxrstor().
+ */
+static double  dummy_variable = 0.0;
+static void
+fpu_clean_state(void)
+{
+       u_short status;
+
+       /*
+        * Clear the ES bit in the x87 status word if it is currently
+        * set, in order to avoid causing a fault in the upcoming load.
+        */
+       fnstsw(&status);
+       if (status & 0x80)
+               fnclex();
+
+       /*
+        * Load the dummy variable into the x87 stack.  This mangles
+        * the x87 stack, but we don't care since we're about to call
+        * fxrstor() anyway.
+        */
+       __asm __volatile("ffree %%st(7); fld %0" : : "m" (dummy_variable));
+}
+#endif /* CPU_DISABLE_SSE */
+
+static void
+fpurstor(union savefpu *addr)
+{
+#ifndef CPU_DISABLE_SSE
+       if (cpu_fxsr) {
+               fpu_clean_state();
+               fxrstor(addr);
+       } else {
+               frstor(addr);
+       }
+#else
+       frstor(addr);
+#endif
+}
diff --git a/sys/platform/vkernel64/amd64/procfs_machdep.c b/sys/platform/vkernel64/amd64/procfs_machdep.c
new file mode 100644 (file)
index 0000000..584d04b
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1993 Jan-Simon Pendry
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ *     @(#)procfs_machdep.c    8.3 (Berkeley) 1/27/94
+ *
+ * From:
+ * $FreeBSD: src/sys/i386/i386/procfs_machdep.c,v 1.14 1999/10/11 14:50:03 peter Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/procfs_machdep.c,v 1.2 2007/09/24 03:24:45 yanyh Exp $
+ */
+
+/*
+ * Functions to be implemented here are:
+ *
+ * procfs_read_regs(lwp, 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.
+ *
+ * procfs_write_regs(lwp, 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.
+ *     Depending on the architecture this may have fix-up work to do,
+ *     especially if the IAR or PCW are modified.
+ *     The process is stopped at the time write_regs is called.
+ *
+ * procfs_read_fpregs, procfs_write_fpregs
+ *     deal with the floating point register set, otherwise as above.
+ *
+ * procfs_read_dbregs, procfs_write_dbregs
+ *     deal with the processor debug register set, otherwise as above.
+ *
+ * procfs_sstep(lwp)
+ *     Arrange for the process to trap after executing a single instruction.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/vnode.h>
+#include <sys/reg.h>
+#include <machine/md_var.h>
+#include <vfs/procfs/procfs.h>
+
+#include <vm/vm.h>
+#include <sys/lock.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+
+int
+procfs_read_regs(struct lwp *lp, struct reg *regs)
+{
+       return (fill_regs(lp, regs));
+}
+
+int
+procfs_write_regs(struct lwp *lp, struct reg *regs)
+{
+       return (set_regs(lp, regs));
+}
+
+int
+procfs_read_dbregs(struct lwp *lp, struct dbreg *dbregs)
+{
+       return (fill_dbregs(lp, dbregs));
+}
+
+int
+procfs_write_dbregs(struct lwp *lp, struct dbreg *dbregs)
+{
+       return (set_dbregs(lp, dbregs));
+}
+
+/*
+ * Ptrace doesn't support fpregs at all, and there are no security holes
+ * or translations for fpregs, so we can just copy them.
+ */
+
+int
+procfs_read_fpregs(struct lwp *lp, struct fpreg *fpregs)
+{
+       return (fill_fpregs(lp, fpregs));
+}
+
+int
+procfs_write_fpregs(struct lwp *lp, struct fpreg *fpregs)
+{
+       return (set_fpregs(lp, fpregs));
+}
+
+int
+procfs_sstep(struct lwp *lp)
+{
+       return (ptrace_single_step(lp));
+}
diff --git a/sys/platform/vkernel64/amd64/swtch.s b/sys/platform/vkernel64/amd64/swtch.s
new file mode 100644 (file)
index 0000000..d2aed01
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2003,2004,2008 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2008 Jordan Gordeev.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/swtch.s,v 1.3 2008/08/29 17:07:10 dillon Exp $
+ */
+
+//#include "use_npx.h"
+
+#include <sys/rtprio.h>
+
+#include <machine/asmacros.h>
+#include <machine/segments.h>
+
+#include <machine/pmap.h>
+#include <machine/lock.h>
+
+#define CHECKNZ(expr, scratch_reg) \
+       movq expr, scratch_reg; testq scratch_reg, scratch_reg; jnz 7f; int $3; 7:
+
+#include "assym.s"
+
+#if defined(SMP)
+#define MPLOCKED        lock ;
+#else
+#define MPLOCKED
+#endif
+
+       .data
+
+       .globl  panic
+
+#if defined(SWTCH_OPTIM_STATS)
+       .globl  swtch_optim_stats, tlb_flush_count
+swtch_optim_stats:     .long   0               /* number of _swtch_optims */
+tlb_flush_count:       .long   0
+#endif
+
+       .text
+
+
+/*
+ * cpu_heavy_switch(struct thread *next_thread)
+ *
+ *     Switch from the current thread to a new thread.  This entry
+ *     is normally called via the thread->td_switch function, and will
+ *     only be called when the current thread is a heavy weight process.
+ *
+ *     Some instructions have been reordered to reduce pipeline stalls.
+ *
+ *     YYY disable interrupts once giant is removed.
+ */
+ENTRY(cpu_heavy_switch)
+       /*
+        * Save RIP, RSP and callee-saved registers (RBX, RBP, R12-R15).
+        */
+       movq    PCPU(curthread),%rcx
+       /* On top of the stack is the return adress. */
+       movq    (%rsp),%rax                     /* (reorder optimization) */
+       movq    TD_PCB(%rcx),%rdx               /* RDX = PCB */
+       movq    %rax,PCB_RIP(%rdx)              /* return PC may be modified */
+       movq    %rbx,PCB_RBX(%rdx)
+       movq    %rsp,PCB_RSP(%rdx)
+       movq    %rbp,PCB_RBP(%rdx)
+       movq    %r12,PCB_R12(%rdx)
+       movq    %r13,PCB_R13(%rdx)
+       movq    %r14,PCB_R14(%rdx)
+       movq    %r15,PCB_R15(%rdx)
+
+       movq    %rcx,%rbx                       /* RBX = curthread */
+       movq    TD_LWP(%rcx),%rcx
+       movl    PCPU(cpuid), %eax
+       movq    LWP_VMSPACE(%rcx), %rcx         /* RCX = vmspace */
+       MPLOCKED btrl   %eax, VM_PMAP+PM_ACTIVE(%rcx)
+
+       /*
+        * Push the LWKT switch restore function, which resumes a heavy
+        * weight process.  Note that the LWKT switcher is based on
+        * TD_SP, while the heavy weight process switcher is based on
+        * PCB_RSP.  TD_SP is usually two ints pushed relative to
+        * PCB_RSP.  We push the flags for later restore by cpu_heavy_restore.
+        */
+       pushfq
+       movq    $cpu_heavy_restore, %rax
+       pushq   %rax
+       movq    %rsp,TD_SP(%rbx)
+
+       /*
+        * Save debug regs if necessary
+        */
+       movq    PCB_FLAGS(%rdx),%rax
+       andq    $PCB_DBREGS,%rax
+       jz      1f                              /* no, skip over */
+       movq    %dr7,%rax                       /* yes, do the save */
+       movq    %rax,PCB_DR7(%rdx)
+       /* JG correct value? */
+       andq    $0x0000fc00, %rax               /* disable all watchpoints */
+       movq    %rax,%dr7
+       movq    %dr6,%rax
+       movq    %rax,PCB_DR6(%rdx)
+       movq    %dr3,%rax
+       movq    %rax,PCB_DR3(%rdx)
+       movq    %dr2,%rax
+       movq    %rax,PCB_DR2(%rdx)
+       movq    %dr1,%rax
+       movq    %rax,PCB_DR1(%rdx)
+       movq    %dr0,%rax
+       movq    %rax,PCB_DR0(%rdx)
+1:
+
+#if 1
+       /*
+        * Save the FP state if we have used the FP.  Note that calling
+        * npxsave will NULL out PCPU(npxthread).
+        */
+       cmpq    %rbx,PCPU(npxthread)
+       jne     1f
+       movq    %rdi,%r12               /* save %rdi. %r12 is callee-saved */
+       movq    TD_SAVEFPU(%rbx),%rdi
+       call    npxsave                 /* do it in a big C function */
+       movq    %r12,%rdi               /* restore %rdi */
+1:
+#endif
+
+       /*
+        * Switch to the next thread, which was passed as an argument
+        * to cpu_heavy_switch().  The argument is in %rdi.
+        * Set the current thread, load the stack pointer,
+        * and 'ret' into the switch-restore function.
+        *
+        * The switch restore function expects the new thread to be in %rax
+        * and the old one to be in %rbx.
+        *
+        * There is a one-instruction window where curthread is the new
+        * thread but %rsp still points to the old thread's stack, but
+        * we are protected by a critical section so it is ok.
+        */
+       movq    %rdi,%rax               /* RAX = newtd, RBX = oldtd */
+       movq    %rax,PCPU(curthread)
+       movq    TD_SP(%rax),%rsp
+       CHECKNZ((%rsp), %r9)
+       ret
+
+/*
+ *  cpu_exit_switch(struct thread *next)
+ *
+ *     The switch function is changed to this when a thread is going away
+ *     for good.  We have to ensure that the MMU state is not cached, and
+ *     we don't bother saving the existing thread state before switching.
+ *
+ *     At this point we are in a critical section and this cpu owns the
+ *     thread's token, which serves as an interlock until the switchout is
+ *     complete.
+ */
+ENTRY(cpu_exit_switch)
+       /*
+        * Get us out of the vmspace
+        */
+#if 0
+       movq    KPML4phys,%rcx
+       movq    %cr3,%rax
+       cmpq    %rcx,%rax
+       je      1f
+       /* JG no increment of statistics counters? see cpu_heavy_restore */
+       movq    %rcx,%cr3
+1:
+#endif
+       movq    PCPU(curthread),%rbx
+
+       /*
+        * If this is a process/lwp, deactivate the pmap after we've
+        * switched it out.
+        */
+       movq    TD_LWP(%rbx),%rcx
+       testq   %rcx,%rcx
+       jz      2f
+       movl    PCPU(cpuid), %eax
+       movq    LWP_VMSPACE(%rcx), %rcx         /* RCX = vmspace */
+       MPLOCKED btrl   %eax, VM_PMAP+PM_ACTIVE(%rcx)
+2:
+       /*
+        * Switch to the next thread.  RET into the restore function, which
+        * expects the new thread in RAX and the old in RBX.
+        *
+        * There is a one-instruction window where curthread is the new
+        * thread but %rsp still points to the old thread's stack, but
+        * we are protected by a critical section so it is ok.
+        */
+       movq    %rdi,%rax
+       movq    %rax,PCPU(curthread)
+       movq    TD_SP(%rax),%rsp
+       CHECKNZ((%rsp), %r9)
+       ret
+
+/*
+ * cpu_heavy_restore() (current thread in %rax on entry)
+ *
+ *     Restore the thread after an LWKT switch.  This entry is normally
+ *     called via the LWKT switch restore function, which was pulled
+ *     off the thread stack and jumped to.
+ *
+ *     This entry is only called if the thread was previously saved
+ *     using cpu_heavy_switch() (the heavy weight process thread switcher),
+ *     or when a new process is initially scheduled.  The first thing we
+ *     do is clear the TDF_RUNNING bit in the old thread and set it in the
+ *     new thread.
+ *
+ *     NOTE: The lwp may be in any state, not necessarily LSRUN, because
+ *     a preemption switch may interrupt the process and then return via
+ *     cpu_heavy_restore.
+ *
+ *     YYY theoretically we do not have to restore everything here, a lot
+ *     of this junk can wait until we return to usermode.  But for now
+ *     we restore everything.
+ *
+ *     YYY the PCB crap is really crap, it makes startup a bitch because
+ *     we can't switch away.
+ *
+ *     YYY note: spl check is done in mi_switch when it splx()'s.
+ */
+
+ENTRY(cpu_heavy_restore)
+       popfq
+       movq    TD_PCB(%rax),%rdx               /* RDX = PCB */
+       movq    TD_LWP(%rax),%rcx
+
+#if defined(SWTCH_OPTIM_STATS)
+       incl    _swtch_optim_stats
+#endif
+       /*
+        * Tell the pmap that our cpu is using the VMSPACE now.  We cannot
+        * safely test/reload %cr3 until after we have set the bit in the
+        * pmap (remember, we do not hold the MP lock in the switch code).
+        */
+       movq    LWP_VMSPACE(%rcx), %rcx         /* RCX = vmspace */
+       movl    PCPU(cpuid), %esi
+       MPLOCKED btsl   %esi, VM_PMAP+PM_ACTIVE(%rcx)
+
+       /*
+        * Restore the MMU address space.  If it is the same as the last
+        * thread we don't have to invalidate the tlb (i.e. reload cr3).
+        * YYY which naturally also means that the PM_ACTIVE bit had better
+        * already have been set before we set it above, check? YYY
+        */
+#if 0
+       movq    %cr3,%rsi
+       movq    PCB_CR3(%rdx),%rcx
+       cmpq    %rsi,%rcx
+       je      4f
+#if defined(SWTCH_OPTIM_STATS)
+       decl    _swtch_optim_stats
+       incl    _tlb_flush_count
+#endif
+       movq    %rcx,%cr3
+4:
+#endif
+       /*
+        * Clear TDF_RUNNING flag in old thread only after cleaning up
+        * %cr3.  The target thread is already protected by being TDF_RUNQ
+        * so setting TDF_RUNNING isn't as big a deal.
+        */
+       andl    $~TDF_RUNNING,TD_FLAGS(%rbx)
+       orl     $TDF_RUNNING,TD_FLAGS(%rax)
+
+#if 0
+       /*
+        * Deal with the PCB extension, restore the private tss
+        */
+       movq    PCB_EXT(%rdx),%rdi      /* check for a PCB extension */
+       /* JG cheaper than "movq $1,%rbx", right? */
+       /* JG what's that magic value $1? */
+       movl    $1,%ebx                 /* maybe mark use of a private tss */
+       testq   %rdi,%rdi
+#if JG
+       jnz     2f
+#endif
+
+       /* JG
+        * Going back to the common_tss.  We may need to update TSS_ESP0
+        * which sets the top of the supervisor stack when entering from
+        * usermode.  The PCB is at the top of the stack but we need another
+        * 16 bytes to take vm86 into account.
+        */
+       leaq    -16(%rdx),%rbx
+       movq    %rbx, PCPU(common_tss) + TSS_RSP0
+       movq    %rbx, PCPU(rsp0)
+
+#if JG
+       cmpl    $0,PCPU(private_tss)    /* don't have to reload if      */
+       je      3f                      /* already using the common TSS */
+
+       /* JG? */
+       subl    %ebx,%ebx               /* unmark use of private tss */
+
+       /*
+        * Get the address of the common TSS descriptor for the ltr.
+        * There is no way to get the address of a segment-accessed variable
+        * so we store a self-referential pointer at the base of the per-cpu
+        * data area and add the appropriate offset.
+        */
+       /* JG movl? */
+       movq    $gd_common_tssd, %rdi
+       /* JG name for "%gs:0"? */
+       addq    %gs:0, %rdi
+
+       /*
+        * Move the correct TSS descriptor into the GDT slot, then reload
+        * ltr.
+        */
+2:
+       /* JG */
+       movl    %ebx,PCPU(private_tss)          /* mark/unmark private tss */
+       movq    PCPU(tss_gdt), %rbx             /* entry in GDT */
+       movq    0(%rdi), %rax
+       movq    %rax, 0(%rbx)
+       movl    $GPROC0_SEL*8, %esi             /* GSEL(entry, SEL_KPL) */
+       ltr     %si
+#endif
+
+3:
+#endif
+#if 0
+       /*
+        * Restore the user %gs and %fs
+        */
+       movq    PCB_FSBASE(%rdx),%r9
+       cmpq    PCPU(user_fs),%r9
+       je      4f
+       movq    %rdx,%r10
+       movq    %r9,PCPU(user_fs)
+       movl    $MSR_FSBASE,%ecx
+       movl    PCB_FSBASE(%r10),%eax
+       movl    PCB_FSBASE+4(%r10),%edx
+       wrmsr
+       movq    %r10,%rdx
+4:
+       movq    PCB_GSBASE(%rdx),%r9
+       cmpq    PCPU(user_gs),%r9
+       je      5f
+       movq    %rdx,%r10
+       movq    %r9,PCPU(user_gs)
+       movl    $MSR_KGSBASE,%ecx       /* later swapgs moves it to GSBASE */
+       movl    PCB_GSBASE(%r10),%eax
+       movl    PCB_GSBASE+4(%r10),%edx
+       wrmsr
+       movq    %r10,%rdx
+5:
+#endif
+
+       /*
+        * Restore general registers.
+        */
+       movq    PCB_RBX(%rdx), %rbx
+       movq    PCB_RSP(%rdx), %rsp
+       movq    PCB_RBP(%rdx), %rbp
+       movq    PCB_R12(%rdx), %r12
+       movq    PCB_R13(%rdx), %r13
+       movq    PCB_R14(%rdx), %r14
+       movq    PCB_R15(%rdx), %r15
+       movq    PCB_RIP(%rdx), %rax
+       movq    %rax, (%rsp)
+
+#if 0
+       /*
+        * Restore the user LDT if we have one
+        */
+       cmpl    $0, PCB_USERLDT(%edx)
+       jnz     1f
+       movl    _default_ldt,%eax
+       cmpl    PCPU(currentldt),%eax
+       je      2f
+       lldt    _default_ldt
+       movl    %eax,PCPU(currentldt)
+       jmp     2f
+1:     pushl   %edx
+       call    set_user_ldt
+       popl    %edx
+2:
+#endif
+#if 0
+       /*
+        * Restore the user TLS if we have one
+        */
+       pushl   %edx
+       call    set_user_TLS
+       popl    %edx
+#endif
+
+       /*
+        * Restore the DEBUG register state if necessary.
+        */
+       movq    PCB_FLAGS(%rdx),%rax
+       andq    $PCB_DBREGS,%rax
+       jz      1f                              /* no, skip over */
+       movq    PCB_DR6(%rdx),%rax              /* yes, do the restore */
+       movq    %rax,%dr6
+       movq    PCB_DR3(%rdx),%rax
+       movq    %rax,%dr3
+       movq    PCB_DR2(%rdx),%rax
+       movq    %rax,%dr2
+       movq    PCB_DR1(%rdx),%rax
+       movq    %rax,%dr1
+       movq    PCB_DR0(%rdx),%rax
+       movq    %rax,%dr0
+       movq    %dr7,%rax                /* load dr7 so as not to disturb */
+       /* JG correct value? */
+       andq    $0x0000fc00,%rax         /*   reserved bits               */
+       /* JG we've got more registers on amd64 */
+       pushq   %rbx
+       movq    PCB_DR7(%rdx),%rbx
+       /* JG correct value? */
+       andq    $~0x0000fc00,%rbx
+       orq     %rbx,%rax
+       popq    %rbx
+       movq    %rax,%dr7
+1:
+
+       CHECKNZ((%rsp), %r9)
+       ret
+
+/*
+ * savectx(struct pcb *pcb)
+ *
+ * Update pcb, saving current processor state.
+ */
+ENTRY(savectx)
+       /* fetch PCB */
+       /* JG use %rdi instead of %rcx everywhere? */
+       movq    %rdi,%rcx
+
+       /* caller's return address - child won't execute this routine */
+       movq    (%rsp),%rax
+       movq    %rax,PCB_RIP(%rcx)
+       movq    %rbx,PCB_RBX(%rcx)
+       movq    %rsp,PCB_RSP(%rcx)
+       movq    %rbp,PCB_RBP(%rcx)
+       movq    %r12,PCB_R12(%rcx)
+       movq    %r13,PCB_R13(%rcx)
+       movq    %r14,PCB_R14(%rcx)
+       movq    %r15,PCB_R15(%rcx)
+
+#if 1
+       /*
+        * If npxthread == NULL, then the npx h/w state is irrelevant and the
+        * state had better already be in the pcb.  This is true for forks
+        * but not for dumps (the old book-keeping with FP flags in the pcb
+        * always lost for dumps because the dump pcb has 0 flags).
+        *
+        * If npxthread != NULL, then we have to save the npx h/w state to
+        * npxthread's pcb and copy it to the requested pcb, or save to the
+        * requested pcb and reload.  Copying is easier because we would
+        * have to handle h/w bugs for reloading.  We used to lose the
+        * parent's npx state for forks by forgetting to reload.
+        */
+       movq    PCPU(npxthread),%rax
+       testq   %rax,%rax
+       jz      1f
+
+       pushq   %rcx                    /* target pcb */
+       movq    TD_SAVEFPU(%rax),%rax   /* originating savefpu area */
+       pushq   %rax
+
+       movq    %rax,%rdi
+       call    npxsave
+
+       popq    %rax
+       popq    %rcx
+
+       movq    $PCB_SAVEFPU_SIZE,%rdx
+       leaq    PCB_SAVEFPU(%rcx),%rcx
+       movq    %rcx,%rsi
+       movq    %rax,%rdi
+       call    bcopy
+#endif
+
+1:
+       CHECKNZ((%rsp), %r9)
+       ret
+
+/*
+ * cpu_idle_restore()  (current thread in %rax on entry) (one-time execution)
+ *
+ *     Don't bother setting up any regs other than %rbp so backtraces
+ *     don't die.  This restore function is used to bootstrap into the
+ *     cpu_idle() LWKT only, after that cpu_lwkt_*() will be used for
+ *     switching.
+ *
+ *     Clear TDF_RUNNING in old thread only after we've cleaned up %cr3.
+ *
+ *     If we are an AP we have to call ap_init() before jumping to
+ *     cpu_idle().  ap_init() will synchronize with the BP and finish
+ *     setting up various ncpu-dependant globaldata fields.  This may
+ *     happen on UP as well as SMP if we happen to be simulating multiple
+ *     cpus.
+ */
+ENTRY(cpu_idle_restore)
+       /* cli */
+       /* JG xor? */
+       movl    $0,%ebp
+       /* JG push RBP? */
+       pushq   $0
+       andl    $~TDF_RUNNING,TD_FLAGS(%rbx)
+       orl     $TDF_RUNNING,TD_FLAGS(%rax)
+#ifdef SMP
+       cmpl    $0,PCPU(cpuid)
+       je      1f
+       call    ap_init
+1:
+#endif
+       /* sti */
+       jmp     cpu_idle
+
+/*
+ * cpu_kthread_restore() (current thread is %rax on entry) (one-time execution)
+ *
+ *     Don't bother setting up any regs other then %rbp so backtraces
+ *     don't die.  This restore function is used to bootstrap into an
+ *     LWKT based kernel thread only.  cpu_lwkt_switch() will be used
+ *     after this.
+ *
+ *     Since all of our context is on the stack we are reentrant and
+ *     we can release our critical section and enable interrupts early.
+ */
+ENTRY(cpu_kthread_restore)
+       /*sti*/
+       movq    TD_PCB(%rax),%rdx
+       /* JG "movq $0, %rbp"? "xorq %rbp, %rbp"? */
+       movl    $0,%ebp
+       /* rax and rbx come from the switchout code */
+       andl    $~TDF_RUNNING,TD_FLAGS(%rbx)
+       orl     $TDF_RUNNING,TD_FLAGS(%rax)
+       subl    $TDPRI_CRIT,TD_PRI(%rax)
+       movq    PCB_R12(%rdx),%rdi      /* argument to RBX function */
+       movq    PCB_RBX(%rdx),%rax      /* thread function */
+       /* note: top of stack return address inherited by function */
+       CHECKNZ(%rax, %r9)
+       jmp     *%rax
+
+/*
+ * cpu_lwkt_switch(struct thread *)
+ *
+ *     Standard LWKT switching function.  Only non-scratch registers are
+ *     saved and we don't bother with the MMU state or anything else.
+ *
+ *     This function is always called while in a critical section.
+ *
+ *     There is a one-instruction window where curthread is the new
+ *     thread but %rsp still points to the old thread's stack, but
+ *     we are protected by a critical section so it is ok.
+ *
+ *     YYY BGL, SPL
+ */
+ENTRY(cpu_lwkt_switch)
+       pushq   %rbp    /* JG note: GDB hacked to locate ebp relative to td_sp */
+       /* JG we've got more registers on AMD64 */
+       pushq   %rbx
+       movq    PCPU(curthread),%rbx
+       pushq   %r12
+       pushq   %r13
+       pushq   %r14
+       pushq   %r15
+       pushfq
+
+#if 1
+       /*
+        * Save the FP state if we have used the FP.  Note that calling
+        * npxsave will NULL out PCPU(npxthread).
+        *
+        * We have to deal with the FP state for LWKT threads in case they
+        * happen to get preempted or block while doing an optimized
+        * bzero/bcopy/memcpy.
+        */
+       cmpq    %rbx,PCPU(npxthread)
+       jne     1f
+       movq    %rdi,%r12               /* save %rdi. %r12 is callee-saved */
+       movq    TD_SAVEFPU(%rbx),%rdi
+       call    npxsave                 /* do it in a big C function */
+       movq    %r12,%rdi               /* restore %rdi */
+1:
+#endif
+
+       movq    %rdi,%rax               /* switch to this thread */
+       pushq   $cpu_lwkt_restore
+       movq    %rsp,TD_SP(%rbx)
+       movq    %rax,PCPU(curthread)
+       movq    TD_SP(%rax),%rsp
+
+       /*
+        * %rax contains new thread, %rbx contains old thread.
+        */
+       CHECKNZ((%rsp), %r9)
+       ret
+
+/*
+ * cpu_lwkt_restore()  (current thread in %rax on entry)
+ *
+ *     Standard LWKT restore function.  This function is always called
+ *     while in a critical section.
+ *
+ *     Warning: due to preemption the restore function can be used to
+ *     'return' to the original thread.  Interrupt disablement must be
+ *     protected through the switch so we cannot run splz here.
+ */
+ENTRY(cpu_lwkt_restore)
+       andl    $~TDF_RUNNING,TD_FLAGS(%rbx)
+       orl     $TDF_RUNNING,TD_FLAGS(%rax)
+       popfq
+       popq    %r15
+       popq    %r14
+       popq    %r13
+       popq    %r12
+       popq    %rbx
+       popq    %rbp
+       ret
+
+/*
+ * bootstrap_idle()
+ *
+ * Make AP become the idle loop.
+ */
+ENTRY(bootstrap_idle)
+       movq    PCPU(curthread),%rax
+       movq    %rax,%rbx
+       movq    TD_SP(%rax),%rsp
+       ret
diff --git a/sys/platform/vkernel64/amd64/tls.c b/sys/platform/vkernel64/amd64/tls.c
new file mode 100644 (file)
index 0000000..fd1bf82
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2003,2004,2008 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by David Xu <davidxu@t2t2.com> and Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/pc64/amd64/tls.c,v 1.4 2008/08/29 17:07:10 dillon Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/sysctl.h>
+#include <sys/tls.h>
+#include <sys/reg.h>
+#include <sys/globaldata.h>
+
+#include <sys/thread2.h>
+
+#include <machine/cpu.h>
+#include <machine/clock.h>
+#include <machine/specialreg.h>
+#include <machine/segments.h>
+#include <machine/md_var.h>
+#include <machine/pcb_ext.h>           /* pcb.h included via sys/user.h */
+#include <machine/globaldata.h>                /* CPU_prvspace */
+#include <machine/smp.h>
+#include <machine/pcb.h>
+
+/*
+ * set a TLS descriptor.  For AMD64 descriptor 0 identifies %fs and
+ * descriptor 1 identifies %gs, and 0 is returned in sysmsg_result.
+ *
+ * Returns the value userland needs to load into %gs representing the
+ * TLS descriptor or -1 on error.
+ *
+ * (int which, struct tls_info *info, size_t infosize)
+ */
+int
+sys_set_tls_area(struct set_tls_area_args *uap)
+{
+       struct tls_info info;
+       int error;
+       int i;
+
+       /*
+        * Sanity checks
+        *
+        * which 0 == %fs, which 1 == %gs
+        */
+       i = uap->which;
+       if (i < 0 || i > 1)
+               return (ERANGE);
+       if (uap->infosize < 0)
+               return (EINVAL);
+
+       /*
+        * Maintain forwards compatibility with future extensions.
+        */
+       if (uap->infosize != sizeof(info)) {
+               bzero(&info, sizeof(info));
+               error = copyin(uap->info, &info,
+                               min(sizeof(info), uap->infosize));
+       } else {
+               error = copyin(uap->info, &info, sizeof(info));
+       }
+       if (error)
+               return (error);
+       if (info.size < -1)
+               return (EINVAL);
+
+       /*
+        * For AMD64 we can only adjust FSBASE and GSBASE
+        */
+       curthread->td_tls.info[i] = info;
+       set_user_TLS();
+       uap->sysmsg_result = 0; /* segment descriptor $0 */
+       return(0);
+}
+
+/*
+ * Return the specified TLS descriptor to userland.
+ *
+ * Returns the value userland needs to load into %gs representing the
+ * TLS descriptor or -1 on error.
+ *
+ * (int which, struct tls_info *info, size_t infosize)
+ */
+int
+sys_get_tls_area(struct get_tls_area_args *uap)
+{
+       struct tls_info info;
+       int error;
+       int i;
+
+       /*
+        * Sanity checks
+        */
+       i = uap->which;
+       if (i < 0 || i > 1)
+               return (ERANGE);
+       if (uap->infosize < 0)
+               return (EINVAL);
+
+       info = curthread->td_tls.info[i];
+
+       error = copyout(&info, uap->info, min(sizeof(info), uap->infosize));
+       return(error);
+}
+
+/*
+ * This function is a NOP because the TLS segments are proactively copied
+ * by vmspace_ctl() when we switch to the (emulated) user process.
+ */
+void
+set_user_TLS(void)
+{
+}
diff --git a/sys/platform/vkernel64/amd64/trap.c b/sys/platform/vkernel64/amd64/trap.c
new file mode 100644 (file)
index 0000000..95a3a01
--- /dev/null
@@ -0,0 +1,1501 @@
+/*-
+ * Copyright (C) 1994, David Greenman
+ * Copyright (c) 1990, 1993
+ *     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.
+ *
+ *     from: @(#)trap.c        7.4 (Berkeley) 5/13/91
+ * $FreeBSD: src/sys/i386/i386/trap.c,v 1.147.2.11 2003/02/27 19:09:59 luoqi Exp $
+ * $DragonFly: src/sys/platform/vkernel/i386/trap.c,v 1.35 2008/09/09 04:06:19 dillon Exp $
+ */
+
+/*
+ * AMD64 Trap and System call handling
+ */
+
+#include "use_isa.h"
+
+#include "opt_ddb.h"
+#include "opt_ktrace.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/pioctl.h>
+#include <sys/kernel.h>
+#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
+#include <sys/signal2.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/uio.h>
+#include <sys/vmmeter.h>
+#include <sys/malloc.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+#include <sys/ktr.h>
+#include <sys/upcall.h>
+#include <sys/vkernel.h>
+#include <sys/sysproto.h>
+#include <sys/sysunion.h>
+#include <sys/vmspace.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <sys/lock.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/pcb.h>
+#include <machine/smp.h>
+#include <machine/tss.h>
+#include <machine/globaldata.h>
+
+
+#include <ddb/ddb.h>
+#include <sys/msgport2.h>
+#include <sys/thread2.h>
+
+#ifdef SMP
+
+#define MAKEMPSAFE(have_mplock)                        \
+       if (have_mplock == 0) {                 \
+               get_mplock();                   \
+               have_mplock = 1;                \
+       }
+
+#else
+
+#define MAKEMPSAFE(have_mplock)
+
+#endif
+
+int (*pmath_emulate) (struct trapframe *);
+
+extern int trapwrite (unsigned addr);
+
+static int trap_pfault (struct trapframe *, int, vm_offset_t);
+static void trap_fatal (struct trapframe *, int, vm_offset_t);
+void dblfault_handler (void);
+
+#if 0
+extern inthand_t IDTVEC(syscall);
+#endif
+
+#define MAX_TRAP_MSG           30
+static char *trap_msg[] = {
+       "",                                     /*  0 unused */
+       "privileged instruction fault",         /*  1 T_PRIVINFLT */
+       "",                                     /*  2 unused */
+       "breakpoint instruction fault",         /*  3 T_BPTFLT */
+       "",                                     /*  4 unused */
+       "",                                     /*  5 unused */
+       "arithmetic trap",                      /*  6 T_ARITHTRAP */
+       "system forced exception",              /*  7 T_ASTFLT */
+       "",                                     /*  8 unused */
+       "general protection fault",             /*  9 T_PROTFLT */
+       "trace trap",                           /* 10 T_TRCTRAP */
+       "",                                     /* 11 unused */
+       "page fault",                           /* 12 T_PAGEFLT */
+       "",                                     /* 13 unused */
+       "alignment fault",                      /* 14 T_ALIGNFLT */
+       "",                                     /* 15 unused */
+       "",                                     /* 16 unused */
+       "",                                     /* 17 unused */
+       "integer divide fault",                 /* 18 T_DIVIDE */
+       "non-maskable interrupt trap",          /* 19 T_NMI */
+       "overflow trap",                        /* 20 T_OFLOW */
+       "FPU bounds check fault",               /* 21 T_BOUND */
+       "FPU device not available",             /* 22 T_DNA */
+       "double fault",                         /* 23 T_DOUBLEFLT */
+       "FPU operand fetch fault",              /* 24 T_FPOPFLT */
+       "invalid TSS fault",                    /* 25 T_TSSFLT */
+       "segment not present fault",            /* 26 T_SEGNPFLT */
+       "stack fault",                          /* 27 T_STKFLT */
+       "machine check trap",                   /* 28 T_MCHK */
+       "SIMD floating-point exception",        /* 29 T_XMMFLT */
+       "reserved (unknown) fault",             /* 30 T_RESERVED */
+};
+
+#ifdef DDB
+static int ddb_on_nmi = 1;
+SYSCTL_INT(_machdep, OID_AUTO, ddb_on_nmi, CTLFLAG_RW,
+       &ddb_on_nmi, 0, "Go to DDB on NMI");
+#endif
+static int panic_on_nmi = 1;
+SYSCTL_INT(_machdep, OID_AUTO, panic_on_nmi, CTLFLAG_RW,
+       &panic_on_nmi, 0, "Panic on NMI");
+static int fast_release;
+SYSCTL_INT(_machdep, OID_AUTO, fast_release, CTLFLAG_RW,
+       &fast_release, 0, "Passive Release was optimal");
+static int slow_release;
+SYSCTL_INT(_machdep, OID_AUTO, slow_release, CTLFLAG_RW,
+       &slow_release, 0, "Passive Release was nonoptimal");
+#ifdef SMP
+static int syscall_mpsafe = 1;
+SYSCTL_INT(_kern, OID_AUTO, syscall_mpsafe, CTLFLAG_RW,
+       &syscall_mpsafe, 0, "Allow MPSAFE marked syscalls to run without BGL");
+TUNABLE_INT("kern.syscall_mpsafe", &syscall_mpsafe);
+static int trap_mpsafe = 1;
+SYSCTL_INT(_kern, OID_AUTO, trap_mpsafe, CTLFLAG_RW,
+       &trap_mpsafe, 0, "Allow traps to mostly run without the BGL");
+TUNABLE_INT("kern.trap_mpsafe", &trap_mpsafe);
+#endif
+
+MALLOC_DEFINE(M_SYSMSG, "sysmsg", "sysmsg structure");
+extern int max_sysmsg;
+
+/*
+ * userenter() passively intercepts the thread switch function to increase
+ * the thread priority from a user priority to a kernel priority, reducing
+ * syscall and trap overhead for the case where no switch occurs.
+ */
+
+static __inline void
+userenter(struct thread *curtd)
+{
+       curtd->td_release = lwkt_passive_release;
+}
+
+/*
+ * Handle signals, upcalls, profiling, and other AST's and/or tasks that
+ * must be completed before we can return to or try to return to userland.
+ *
+ * Note that td_sticks is a 64 bit quantity, but there's no point doing 64
+ * arithmatic on the delta calculation so the absolute tick values are
+ * truncated to an integer.
+ */
+static void
+userret(struct lwp *lp, struct trapframe *frame, int sticks)
+{
+       struct proc *p = lp->lwp_proc;
+       int sig;
+
+       /*
+        * Charge system time if profiling.  Note: times are in microseconds.
+        * This may do a copyout and block, so do it first even though it
+        * means some system time will be charged as user time.
+        */
+       if (p->p_flag & P_PROFIL) {
+               addupc_task(p, frame->tf_rip,
+                       (u_int)((int)lp->lwp_thread->td_sticks - sticks));
+       }
+
+recheck:
+       /*
+        * If the jungle wants us dead, so be it.
+        */
+       if (lp->lwp_flag & LWP_WEXIT) {
+               get_mplock();
+               lwp_exit(0);
+               rel_mplock(); /* NOT REACHED */
+       }
+
+       /*
+        * Block here if we are in a stopped state.
+        */
+       if (p->p_stat == SSTOP) {
+               get_mplock();
+               tstop();
+               rel_mplock();
+               goto recheck;
+       }
+
+       /*
+        * Post any pending upcalls
+        */
+       if (p->p_flag & P_UPCALLPEND) {
+               get_mplock();
+               p->p_flag &= ~P_UPCALLPEND;
+               postupcall(lp);
+               rel_mplock();
+               goto recheck;
+       }
+
+       /*
+        * Post any pending signals
+        */
+       if ((sig = CURSIG_TRACE(lp)) != 0) {
+               get_mplock();
+               postsig(sig);
+               rel_mplock();
+               goto recheck;
+       }
+
+       /*
+        * block here if we are swapped out, but still process signals
+        * (such as SIGKILL).  proc0 (the swapin scheduler) is already
+        * aware of our situation, we do not have to wake it up.
+        */
+       if (p->p_flag & P_SWAPPEDOUT) {
+               get_mplock();
+               p->p_flag |= P_SWAPWAIT;
+               swapin_request();
+               if (p->p_flag & P_SWAPWAIT)
+                       tsleep(p, PCATCH, "SWOUT", 0);
+               p->p_flag &= ~P_SWAPWAIT;
+               rel_mplock();
+               goto recheck;
+       }
+
+       /*
+        * Make sure postsig() handled request to restore old signal mask after
+        * running signal handler.
+        */
+       KKASSERT((lp->lwp_flag & LWP_OLDMASK) == 0);
+}
+
+/*
+ * Cleanup from userenter and any passive release that might have occured.
+ * We must reclaim the current-process designation before we can return
+ * to usermode.  We also handle both LWKT and USER reschedule requests.
+ */
+static __inline void
+userexit(struct lwp *lp)
+{
+       struct thread *td = lp->lwp_thread;
+       /* globaldata_t gd = td->td_gd; */
+
+       /*
+        * Handle stop requests at kernel priority.  Any requests queued
+        * after this loop will generate another AST.
+        */
+       while (lp->lwp_proc->p_stat == SSTOP) {
+               get_mplock();
+               tstop();
+               rel_mplock();
+       }
+
+       /*
+        * Reduce our priority in preparation for a return to userland.  If
+        * our passive release function was still in place, our priority was
+        * never raised and does not need to be reduced.
+        */
+       lwkt_passive_recover(td);
+
+       /*
+        * Become the current user scheduled process if we aren't already,
+        * and deal with reschedule requests and other factors.
+        */
+       lp->lwp_proc->p_usched->acquire_curproc(lp);
+       /* WARNING: we may have migrated cpu's */
+       /* gd = td->td_gd; */
+}
+
+#if !defined(KTR_KERNENTRY)
+#define        KTR_KERNENTRY   KTR_ALL
+#endif
+KTR_INFO_MASTER(kernentry);
+KTR_INFO(KTR_KERNENTRY, kernentry, trap, 0, "pid=%d, tid=%d, trapno=%d, eva=%p",
+        sizeof(int) + sizeof(int) + sizeof(int) + sizeof(vm_offset_t));
+KTR_INFO(KTR_KERNENTRY, kernentry, trap_ret, 0, "pid=%d, tid=%d",
+        sizeof(int) + sizeof(int));
+KTR_INFO(KTR_KERNENTRY, kernentry, syscall, 0, "pid=%d, tid=%d, call=%d",
+        sizeof(int) + sizeof(int) + sizeof(int));
+KTR_INFO(KTR_KERNENTRY, kernentry, syscall_ret, 0, "pid=%d, tid=%d, err=%d",
+        sizeof(int) + sizeof(int) + sizeof(int));
+KTR_INFO(KTR_KERNENTRY, kernentry, fork_ret, 0, "pid=%d, tid=%d",
+        sizeof(int) + sizeof(int));
+
+/*
+ * Exception, fault, and trap interface to the 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.
+ *
+ * This function is also called from doreti in an interlock to handle ASTs.
+ * For example:  hardwareint->INTROUTINE->(set ast)->doreti->trap
+ *
+ * NOTE!  We have to retrieve the fault address prior to obtaining the
+ * MP lock because get_mplock() may switch out.  YYY cr2 really ought
+ * to be retrieved by the assembly code, not here.
+ *
+ * XXX gd_trap_nesting_level currently prevents lwkt_switch() from panicing
+ * if an attempt is made to switch from a fast interrupt or IPI.  This is
+ * necessary to properly take fatal kernel traps on SMP machines if
+ * get_mplock() has to block.
+ */
+
+void
+user_trap(struct trapframe *frame)
+{
+       struct globaldata *gd = mycpu;
+       struct thread *td = gd->gd_curthread;
+       struct lwp *lp = td->td_lwp;
+       struct proc *p;
+       int sticks = 0;
+       int i = 0, ucode = 0, type, code;
+#ifdef SMP
+       int have_mplock = 0;
+#endif
+#ifdef INVARIANTS
+       int crit_count = td->td_pri & ~TDPRI_MASK;
+#endif
+       vm_offset_t eva;
+
+       p = td->td_proc;
+
+       if (frame->tf_trapno == T_PAGEFLT)
+               eva = frame->tf_addr;
+       else
+               eva = 0;
+#if 0
+       kprintf("USER_TRAP AT %08lx xflags %ld trapno %ld eva %08lx\n",
+               frame->tf_rip, frame->tf_xflags, frame->tf_trapno, eva);
+#endif
+
+       /*
+        * Everything coming from user mode runs through user_trap,
+        * including system calls.
+        */
+       if (frame->tf_trapno == T_SYSCALL80) {
+               syscall2(frame);
+               return;
+       }
+
+       KTR_LOG(kernentry_trap, lp->lwp_proc->p_pid, lp->lwp_tid,
+               frame->tf_trapno, eva);
+
+#ifdef DDB
+       if (db_active) {
+               eva = (frame->tf_trapno == T_PAGEFLT ? rcr2() : 0);
+               ++gd->gd_trap_nesting_level;
+               MAKEMPSAFE(have_mplock);
+               trap_fatal(frame, TRUE, eva);
+               --gd->gd_trap_nesting_level;
+               goto out2;
+       }
+#endif
+
+       ++gd->gd_trap_nesting_level;
+#ifdef SMP
+       if (trap_mpsafe == 0)
+               MAKEMPSAFE(have_mplock);
+#endif
+
+       --gd->gd_trap_nesting_level;
+
+#if defined(I586_CPU) && !defined(NO_F00F_HACK)
+restart:
+#endif
+       type = frame->tf_trapno;
+       code = frame->tf_err;
+
+       userenter(td);
+
+       sticks = (int)td->td_sticks;
+       lp->lwp_md.md_regs = frame;
+
+       switch (type) {
+       case T_PRIVINFLT:       /* privileged instruction fault */
+               ucode = type;
+               i = SIGILL;
+               break;
+
+       case T_BPTFLT:          /* bpt instruction fault */
+       case T_TRCTRAP:         /* trace trap */
+               frame->tf_rflags &= ~PSL_T;
+               i = SIGTRAP;
+               break;
+
+       case T_ARITHTRAP:       /* arithmetic trap */
+               ucode = code;
+               i = SIGFPE;
+               break;
+
+       case T_ASTFLT:          /* Allow process switch */
+               mycpu->gd_cnt.v_soft++;
+               if (mycpu->gd_reqflags & RQF_AST_OWEUPC) {
+                       atomic_clear_int_nonlocked(&mycpu->gd_reqflags,
+                                   RQF_AST_OWEUPC);
+                       addupc_task(p, p->p_prof.pr_addr,
+                                   p->p_prof.pr_ticks);
+               }
+               goto out;
+
+               /*
+                * The following two traps can happen in
+                * vm86 mode, and, if so, we want to handle
+                * them specially.
+                */
+       case T_PROTFLT:         /* general protection fault */
+       case T_STKFLT:          /* stack fault */
+#if 0
+               if (frame->tf_eflags & PSL_VM) {
+                       i = vm86_emulate((struct vm86frame *)frame);
+                       if (i == 0)
+                               goto out;
+                       break;
+               }
+#endif
+               /* FALL THROUGH */
+
+       case T_SEGNPFLT:        /* segment not present fault */
+       case T_TSSFLT:          /* invalid TSS fault */
+       case T_DOUBLEFLT:       /* double fault */
+       default:
+               ucode = code + BUS_SEGM_FAULT ;
+               i = SIGBUS;
+               break;
+
+       case T_PAGEFLT:         /* page fault */
+               MAKEMPSAFE(have_mplock);
+               i = trap_pfault(frame, TRUE, eva);
+               if (i == -1)
+                       goto out;
+#if defined(I586_CPU) && !defined(NO_F00F_HACK)
+               if (i == -2)
+                       goto restart;
+#endif
+               if (i == 0)
+                       goto out;
+
+               ucode = T_PAGEFLT;
+               break;
+
+       case T_DIVIDE:          /* integer divide fault */
+               ucode = FPE_INTDIV;
+               i = SIGFPE;
+               break;
+
+#if NISA > 0
+       case T_NMI:
+               MAKEMPSAFE(have_mplock);
+               /* machine/parity/power fail/"kitchen sink" faults */
+               if (isa_nmi(code) == 0) {
+#ifdef DDB
+                       /*
+                        * NMI can be hooked up to a pushbutton
+                        * for debugging.
+                        */
+                       if (ddb_on_nmi) {
+                               kprintf ("NMI ... going to debugger\n");
+                               kdb_trap (type, 0, frame);
+                       }
+#endif /* DDB */
+                       goto out2;
+               } else if (panic_on_nmi)
+                       panic("NMI indicates hardware failure");
+               break;
+#endif /* NISA > 0 */
+
+       case T_OFLOW:           /* integer overflow fault */
+               ucode = FPE_INTOVF;
+               i = SIGFPE;
+               break;
+
+       case T_BOUND:           /* bounds check fault */
+               ucode = FPE_FLTSUB;
+               i = SIGFPE;
+               break;
+
+       case T_DNA:
+               /*
+                * Virtual kernel intercept - pass the DNA exception
+                * to the (emulated) virtual kernel if it asked to handle
+                * it.  This occurs when the virtual kernel is holding
+                * onto the FP context for a different emulated
+                * process then the one currently running.
+                *
+                * We must still call npxdna() since we may have
+                * saved FP state that the (emulated) virtual kernel
+                * needs to hand over to a different emulated process.
+                */
+               if (lp->lwp_vkernel && lp->lwp_vkernel->ve &&
+                   (td->td_pcb->pcb_flags & FP_VIRTFP)
+               ) {
+                       npxdna(frame);
+                       break;
+               }
+               /*
+                * The kernel may have switched out the FP unit's
+                * state, causing the user process to take a fault
+                * when it tries to use the FP unit.  Restore the
+                * state here
+                */
+               if (npxdna(frame))
+                       goto out;
+               if (!pmath_emulate) {
+                       i = SIGFPE;
+                       ucode = FPE_FPU_NP_TRAP;
+                       break;
+               }
+               i = (*pmath_emulate)(frame);
+               if (i == 0) {
+                       if (!(frame->tf_rflags & PSL_T))
+                               goto out2;
+                       frame->tf_rflags &= ~PSL_T;
+                       i = SIGTRAP;
+               }
+               /* else ucode = emulator_only_knows() XXX */
+               break;
+
+       case T_FPOPFLT:         /* FPU operand fetch fault */
+               ucode = T_FPOPFLT;
+               i = SIGILL;
+               break;
+
+       case T_XMMFLT:          /* SIMD floating-point exception */
+               ucode = 0; /* XXX */
+               i = SIGFPE;
+               break;
+       }
+
+       /*
+        * Virtual kernel intercept - if the fault is directly related to a
+        * VM context managed by a virtual kernel then let the virtual kernel
+        * handle it.
+        */
+       if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
+               vkernel_trap(lp, frame);
+               goto out;
+       }
+
+       /*
+        * Translate fault for emulators (e.g. Linux)
+        */
+       if (*p->p_sysent->sv_transtrap)
+               i = (*p->p_sysent->sv_transtrap)(i, type);
+
+       MAKEMPSAFE(have_mplock);
+       trapsignal(lp, i, ucode);
+
+#ifdef DEBUG
+       if (type <= MAX_TRAP_MSG) {
+               uprintf("fatal process exception: %s",
+                       trap_msg[type]);
+               if ((type == T_PAGEFLT) || (type == T_PROTFLT))
+                       uprintf(", fault VA = 0x%lx", (u_long)eva);
+               uprintf("\n");
+       }
+#endif
+
+out:
+#ifdef SMP
+       KASSERT(td->td_mpcount == have_mplock, ("badmpcount trap/end from %p", (void *)frame->tf_rip));
+#endif
+       userret(lp, frame, sticks);
+       userexit(lp);
+out2:  ;
+#ifdef SMP
+       if (have_mplock)
+               rel_mplock();
+#endif
+       KTR_LOG(kernentry_trap_ret, lp->lwp_proc->p_pid, lp->lwp_tid);
+#ifdef INVARIANTS
+       KASSERT(crit_count == (td->td_pri & ~TDPRI_MASK),
+               ("syscall: critical section count mismatch! %d/%d",
+               crit_count / TDPRI_CRIT, td->td_pri / TDPRI_CRIT));
+#endif
+}
+
+void
+kern_trap(struct trapframe *frame)
+{
+       struct globaldata *gd = mycpu;
+       struct thread *td = gd->gd_curthread;
+       struct lwp *lp;
+       struct proc *p;
+       int i = 0, ucode = 0, type, code;
+#ifdef SMP
+       int have_mplock = 0;
+#endif
+#ifdef INVARIANTS
+       int crit_count = td->td_pri & ~TDPRI_MASK;
+#endif
+       vm_offset_t eva;
+
+       lp = td->td_lwp;
+       p = td->td_proc;
+
+       if (frame->tf_trapno == T_PAGEFLT)
+               eva = frame->tf_addr;
+       else
+               eva = 0;
+
+#ifdef DDB
+       if (db_active) {
+               ++gd->gd_trap_nesting_level;
+               MAKEMPSAFE(have_mplock);
+               trap_fatal(frame, FALSE, eva);
+               --gd->gd_trap_nesting_level;
+               goto out2;
+       }
+#endif
+
+       ++gd->gd_trap_nesting_level;
+
+#ifdef SMP
+       if (trap_mpsafe == 0)
+               MAKEMPSAFE(have_mplock);
+#endif
+
+       --gd->gd_trap_nesting_level;
+
+       type = frame->tf_trapno;
+       code = frame->tf_err;
+
+#if 0
+kernel_trap:
+#endif
+       /* kernel trap */
+
+       switch (type) {
+       case T_PAGEFLT:                 /* page fault */
+               MAKEMPSAFE(have_mplock);
+               trap_pfault(frame, FALSE, eva);
+               goto out2;
+
+       case T_DNA:
+               /*
+                * The kernel may be using npx for copying or other
+                * purposes.
+                */
+               panic("kernel NPX should not happen");
+               if (npxdna(frame))
+                       goto out2;
+               break;
+
+       case T_PROTFLT:         /* general protection fault */
+       case T_SEGNPFLT:        /* segment not present fault */
+               /*
+                * Invalid segment selectors and out of bounds
+                * %eip's and %esp's can be set up in user mode.
+                * This causes a fault in kernel mode when the
+                * kernel tries to return to user mode.  We want
+                * to get this fault so that we can fix the
+                * problem here and not have to check all the
+                * selectors and pointers when the user changes
+                * them.
+                */
+               if (mycpu->gd_intr_nesting_level == 0) {
+                       if (td->td_pcb->pcb_onfault) {
+                               frame->tf_rip =
+                                   (register_t)td->td_pcb->pcb_onfault;
+                               goto out2;
+                       }
+               }
+               break;
+
+       case T_TSSFLT:
+               /*
+                * PSL_NT can be set in user mode and isn't cleared
+                * automatically when the kernel is entered.  This
+                * causes a TSS fault when the kernel attempts to
+                * `iret' because the TSS link is uninitialized.  We
+                * want to get this fault so that we can fix the
+                * problem here and not every time the kernel is
+                * entered.
+                */
+               if (frame->tf_rflags & PSL_NT) {
+                       frame->tf_rflags &= ~PSL_NT;
+                       goto out2;
+               }
+               break;
+
+       case T_TRCTRAP:  /* trace trap */
+#if 0
+               if (frame->tf_eip == (int)IDTVEC(syscall)) {
+                       /*
+                        * We've just entered system mode via the
+                        * syscall lcall.  Continue single stepping
+                        * silently until the syscall handler has
+                        * saved the flags.
+                        */
+                       goto out2;
+               }
+               if (frame->tf_eip == (int)IDTVEC(syscall) + 1) {
+                       /*
+                        * The syscall handler has now saved the
+                        * flags.  Stop single stepping it.
+                        */
+                       frame->tf_eflags &= ~PSL_T;
+                       goto out2;
+               }
+#endif
+#if 0
+               /*
+                * Ignore debug register trace traps due to
+                * accesses in the user's address space, which
+                * can happen under several conditions such as
+                * if a user sets a watchpoint on a buffer and
+                * then passes that buffer to a system call.
+                * We still want to get TRCTRAPS for addresses
+                * in kernel space because that is useful when
+                * debugging the kernel.
+                */
+               if (user_dbreg_trap()) {
+                       /*
+                        * Reset breakpoint bits because the
+                        * processor doesn't
+                        */
+                       load_dr6(rdr6() & 0xfffffff0);
+                       goto out2;
+               }
+#endif
+               /*
+                * Fall through (TRCTRAP kernel mode, kernel address)
+                */
+       case T_BPTFLT:
+               /*
+                * If DDB is enabled, let it handle the debugger trap.
+                * Otherwise, debugger traps "can't happen".
+                */
+#ifdef DDB
+               MAKEMPSAFE(have_mplock);
+               if (kdb_trap (type, 0, frame))
+                       goto out2;
+#endif
+               break;
+       case T_DIVIDE:
+               MAKEMPSAFE(have_mplock);
+               trap_fatal(frame, FALSE, eva);
+               goto out2;
+       case T_NMI:
+               MAKEMPSAFE(have_mplock);
+               trap_fatal(frame, FALSE, eva);
+               goto out2;
+       case T_SYSCALL80:
+               /*
+                * Ignore this trap generated from a spurious SIGTRAP.
+                *
+                * single stepping in / syscalls leads to spurious / SIGTRAP
+                * so ignore
+                *
+                * Haiku (c) 2007 Simon 'corecode' Schubert
+                */
+               goto out2;
+       }
+
+       /*
+        * Translate fault for emulators (e.g. Linux)
+        */
+       if (*p->p_sysent->sv_transtrap)
+               i = (*p->p_sysent->sv_transtrap)(i, type);
+
+       MAKEMPSAFE(have_mplock);
+       trapsignal(lp, i, ucode);
+
+#ifdef DEBUG
+       if (type <= MAX_TRAP_MSG) {
+               uprintf("fatal process exception: %s",
+                       trap_msg[type]);
+               if ((type == T_PAGEFLT) || (type == T_PROTFLT))
+                       uprintf(", fault VA = 0x%lx", (u_long)eva);
+               uprintf("\n");
+       }
+#endif
+
+out2:
+       ;
+#ifdef SMP
+       if (have_mplock)
+               rel_mplock();
+#endif
+#ifdef INVARIANTS
+       KASSERT(crit_count == (td->td_pri & ~TDPRI_MASK),
+               ("syscall: critical section count mismatch! %d/%d",
+               crit_count / TDPRI_CRIT, td->td_pri / TDPRI_CRIT));
+#endif
+}
+
+int
+trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva)
+{
+       vm_offset_t va;
+       struct vmspace *vm = NULL;
+       vm_map_t map = 0;
+       int rv = 0;
+       vm_prot_t ftype;
+       thread_t td = curthread;
+       struct lwp *lp = td->td_lwp;
+
+       va = trunc_page(eva);
+       if (usermode == FALSE) {
+               /*
+                * This is a fault on kernel virtual memory.
+                */
+               map = &kernel_map;
+       } else {
+               /*
+                * This is a fault on non-kernel virtual memory.
+                * vm is initialized above to NULL. If curproc is NULL
+                * or curproc->p_vmspace is NULL the fault is fatal.
+                */
+               if (lp != NULL)
+                       vm = lp->lwp_vmspace;
+
+               if (vm == NULL)
+                       goto nogo;
+
+               map = &vm->vm_map;
+       }
+
+       if (frame->tf_err & PGEX_W)
+               ftype = VM_PROT_READ | VM_PROT_WRITE;
+       else
+               ftype = VM_PROT_READ;
+
+       if (map != &kernel_map) {
+               /*
+                * Keep swapout from messing with us during this
+                *      critical time.
+                */
+               PHOLD(lp->lwp_proc);
+
+               /*
+                * Grow the stack if necessary
+                */
+               /* grow_stack returns false only if va falls into
+                * a growable stack region and the stack growth
+                * fails.  It returns true if va was not within
+                * a growable stack region, or if the stack
+                * growth succeeded.
+                */
+               if (!grow_stack (lp->lwp_proc, va)) {
+                       rv = KERN_FAILURE;
+                       PRELE(lp->lwp_proc);
+                       goto nogo;
+               }
+
+               /* Fault in the user page: */
+               rv = vm_fault(map, va, ftype,
+                             (ftype & VM_PROT_WRITE) ? VM_FAULT_DIRTY
+                                                     : VM_FAULT_NORMAL);
+
+               PRELE(lp->lwp_proc);
+       } else {
+               /*
+                * Don't have to worry about process locking or stacks in the kernel.
+                */
+               rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL);
+       }
+
+       if (rv == KERN_SUCCESS)
+               return (0);
+nogo:
+       if (!usermode) {
+               if (td->td_gd->gd_intr_nesting_level == 0 &&
+                   td->td_pcb->pcb_onfault) {
+                       frame->tf_rip = (register_t)td->td_pcb->pcb_onfault;
+                       return (0);
+               }
+               trap_fatal(frame, usermode, eva);
+               return (-1);
+       }
+
+       /*
+        * NOTE: on amd64 we have a tf_addr field in the trapframe, no
+        * kludge is needed to pass the fault address to signal handlers.
+        */
+       struct proc *p = td->td_proc;
+       kprintf("seg-fault accessing address %p rip=%p pid=%d p_comm=%s\n",
+               (void *)va, (void *)frame->tf_rip, p->p_pid, p->p_comm);
+       /* Debugger("seg-fault"); */
+
+       return((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV);
+}
+
+static void
+trap_fatal(struct trapframe *frame, int usermode, vm_offset_t eva)
+{
+       int code, type, ss;
+       long rsp;
+
+       code = frame->tf_xflags;
+       type = frame->tf_trapno;
+
+       if (type <= MAX_TRAP_MSG) {
+               kprintf("\n\nFatal trap %d: %s while in %s mode\n",
+                       type, trap_msg[type],
+                       (usermode ? "user" : "kernel"));
+       }
+#ifdef SMP
+       /* two separate prints in case of a trap on an unmapped page */
+       kprintf("mp_lock = %08x; ", mp_lock);
+       kprintf("cpuid = %d\n", mycpu->gd_cpuid);
+#endif
+       if (type == T_PAGEFLT) {
+               kprintf("fault virtual address  = 0x%x\n", eva);
+               kprintf("fault code             = %s %s, %s\n",
+                       usermode ? "user" : "supervisor",
+                       code & PGEX_W ? "write" : "read",
+                       code & PGEX_P ? "protection violation" : "page not present");
+       }
+       kprintf("instruction pointer    = 0x%lx:0x%lx\n",
+              frame->tf_cs & 0xffff, frame->tf_rip);
+       if (usermode) {
+               ss = frame->tf_ss & 0xffff;
+               rsp = frame->tf_rsp;
+       } else {
+               ss = GSEL(GDATA_SEL, SEL_KPL);
+               rsp = (long)&frame->tf_rsp;
+       }
+       kprintf("stack pointer          = 0x%x:0x%lx\n", ss, rsp);
+       kprintf("frame pointer          = 0x%x:0x%lx\n", ss, frame->tf_rbp);
+       kprintf("processor eflags       = ");
+       if (frame->tf_rflags & PSL_T)
+               kprintf("trace trap, ");
+       if (frame->tf_rflags & PSL_I)
+               kprintf("interrupt enabled, ");
+       if (frame->tf_rflags & PSL_NT)
+               kprintf("nested task, ");
+       if (frame->tf_rflags & PSL_RF)
+               kprintf("resume, ");
+#if 0
+       if (frame->tf_eflags & PSL_VM)
+               kprintf("vm86, ");
+#endif
+       kprintf("IOPL = %d\n", (frame->tf_rflags & PSL_IOPL) >> 12);
+       kprintf("current process                = ");
+       if (curproc) {
+               kprintf("%lu (%s)\n",
+                   (u_long)curproc->p_pid, curproc->p_comm ?
+                   curproc->p_comm : "");
+       } else {
+               kprintf("Idle\n");
+       }
+       kprintf("current thread          = pri %d ", curthread->td_pri);
+       if (curthread->td_pri >= TDPRI_CRIT)
+               kprintf("(CRIT)");
+       kprintf("\n");
+#ifdef SMP
+/**
+ *  XXX FIXME:
+ *     we probably SHOULD have stopped the other CPUs before now!
+ *     another CPU COULD have been touching cpl at this moment...
+ */
+       kprintf(" <- SMP: XXX");
+#endif
+       kprintf("\n");
+
+#ifdef KDB
+       if (kdb_trap(&psl))
+               return;
+#endif
+#ifdef DDB
+       if ((debugger_on_panic || db_active) && kdb_trap(type, code, frame))
+               return;
+#endif
+       kprintf("trap number            = %d\n", type);
+       if (type <= MAX_TRAP_MSG)
+               panic("%s", trap_msg[type]);
+       else
+               panic("unknown/reserved trap");
+}
+
+/*
+ * Double fault handler. Called when a fault occurs while writing
+ * a frame for a trap/exception onto the stack. This usually occurs
+ * when the stack overflows (such is the case with infinite recursion,
+ * for example).
+ *
+ * XXX Note that the current PTD gets replaced by IdlePTD when the
+ * task switch occurs. This means that the stack that was active at
+ * the time of the double fault is not available at <kstack> unless
+ * the machine was idle when the double fault occurred. The downside
+ * of this is that "trace <ebp>" in ddb won't work.
+ */
+void
+dblfault_handler(void)
+{
+       struct mdglobaldata *gd = mdcpu;
+
+       kprintf("\nFatal double fault:\n");
+#if JG
+       kprintf("rip = 0x%lx\n", gd->gd_common_tss.tss_rip);
+       kprintf("rsp = 0x%lx\n", gd->gd_common_tss.tss_rsp);
+       kprintf("rbp = 0x%lx\n", gd->gd_common_tss.tss_rbp);
+#endif
+#ifdef SMP
+       /* two separate prints in case of a trap on an unmapped page */
+       kprintf("mp_lock = %08x; ", mp_lock);
+       kprintf("cpuid = %d\n", mycpu->gd_cpuid);
+#endif
+       panic("double fault");
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR).
+ * This is a little simpler than the pagefault handler in trap() because
+ * it the page tables have already been faulted in and high addresses
+ * are thrown out early for other reasons.
+ */
+int
+trapwrite(unsigned addr)
+{
+       struct lwp *lp;
+       vm_offset_t va;
+       struct vmspace *vm;
+       int rv;
+
+       va = trunc_page((vm_offset_t)addr);
+       /*
+        * XXX - MAX is END.  Changed > to >= for temp. fix.
+        */
+       if (va >= VM_MAX_USER_ADDRESS)
+               return (1);
+
+       lp = curthread->td_lwp;
+       vm = lp->lwp_vmspace;
+
+       PHOLD(lp->lwp_proc);
+
+       if (!grow_stack (lp->lwp_proc, va)) {
+               PRELE(lp->lwp_proc);
+               return (1);
+       }
+
+       /*
+        * fault the data page
+        */
+       rv = vm_fault(&vm->vm_map, va, VM_PROT_WRITE, VM_FAULT_DIRTY);
+
+       PRELE(lp->lwp_proc);
+
+       if (rv != KERN_SUCCESS)
+               return 1;
+
+       return (0);
+}
+
+/*
+ *     syscall2 -      MP aware system call request C handler
+ *
+ *     A system call is essentially treated as a trap except that the
+ *     MP lock is not held on entry or return.  We are responsible for
+ *     obtaining the MP lock if necessary and for handling ASTs
+ *     (e.g. a task switch) prior to return.
+ *
+ *     In general, only simple access and manipulation of curproc and
+ *     the current stack is allowed without having to hold MP lock.
+ *
+ *     MPSAFE - note that large sections of this routine are run without
+ *              the MP lock.
+ */
+void
+syscall2(struct trapframe *frame)
+{
+       struct thread *td = curthread;
+       struct proc *p = td->td_proc;
+       struct lwp *lp = td->td_lwp;
+       caddr_t params;
+       struct sysent *callp;
+       register_t orig_tf_rflags;
+       int sticks;
+       int error;
+       int narg;
+#ifdef INVARIANTS
+       int crit_count = td->td_pri & ~TDPRI_MASK;
+#endif
+#ifdef SMP
+       int have_mplock = 0;
+#endif
+       register_t *argp;
+       u_int code;
+       int reg, regcnt;
+       union sysunion args;
+       register_t *argsdst;
+
+       mycpu->gd_cnt.v_syscall++;
+
+       KTR_LOG(kernentry_syscall, lp->lwp_proc->p_pid, lp->lwp_tid,
+               frame->tf_eax);
+
+#ifdef SMP
+       KASSERT(td->td_mpcount == 0, ("badmpcount syscall2 from %p", (void *)frame->tf_rip));
+       if (syscall_mpsafe == 0)
+               MAKEMPSAFE(have_mplock);
+#endif
+       userenter(td);          /* lazy raise our priority */
+
+       reg = 0;
+       regcnt = 6;
+       /*
+        * Misc
+        */
+       sticks = (int)td->td_sticks;
+       orig_tf_rflags = frame->tf_rflags;
+
+       /*
+        * Virtual kernel intercept - if a VM context managed by a virtual
+        * kernel issues a system call the virtual kernel handles it, not us.
+        * Restore the virtual kernel context and return from its system
+        * call.  The current frame is copied out to the virtual kernel.
+        */
+       if (lp->lwp_vkernel && lp->lwp_vkernel->ve) {
+               error = vkernel_trap(lp, frame);
+               frame->tf_rax = error;
+               if (error)
+                       frame->tf_rflags |= PSL_C;
+               error = EJUSTRETURN;
+               goto out;
+       }
+
+       /*
+        * Get the system call parameters and account for time
+        */
+       lp->lwp_md.md_regs = frame;
+       params = (caddr_t)frame->tf_rsp + sizeof(register_t);
+       code = frame->tf_rax;
+
+       if (p->p_sysent->sv_prepsyscall) {
+               (*p->p_sysent->sv_prepsyscall)(
+                       frame, (int *)(&args.nosys.sysmsg + 1),
+                       &code, &params);
+       } else {
+               if (code == SYS_syscall || code == SYS___syscall) {
+                       code = frame->tf_rdi;
+                       reg++;
+                       regcnt--;
+               }
+       }
+
+       if (p->p_sysent->sv_mask)
+               code &= p->p_sysent->sv_mask;
+
+       if (code >= p->p_sysent->sv_size)
+               callp = &p->p_sysent->sv_table[0];
+       else
+               callp = &p->p_sysent->sv_table[code];
+
+       narg = callp->sy_narg & SYF_ARGMASK;
+
+       /*
+        * On amd64 we get up to six arguments in registers. The rest are
+        * on the stack. The first six members of 'struct trapframe' happen
+        * to be the registers used to pass arguments, in exactly the right
+        * order.
+        */
+       argp = &frame->tf_rdi;
+       argp += reg;
+       argsdst = (register_t *)(&args.nosys.sysmsg + 1);
+       /*
+        * JG can we overflow the space pointed to by 'argsdst'
+        * either with 'bcopy' or with 'copyin'?
+        */
+       bcopy(argp, argsdst, sizeof(register_t) * regcnt);
+       /*
+        * copyin is MP aware, but the tracing code is not
+        */
+       if (narg > regcnt) {
+               KASSERT(params != NULL, ("copyin args with no params!"));
+               error = copyin(params, &argsdst[regcnt],
+                       (narg - regcnt) * sizeof(register_t));
+               if (error) {
+#ifdef KTRACE
+                       if (KTRPOINT(td, KTR_SYSCALL)) {
+                               MAKEMPSAFE(have_mplock);
+
+                               ktrsyscall(lp, code, narg,
+                                       (void *)(&args.nosys.sysmsg + 1));
+                       }
+#endif
+                       goto bad;
+               }
+       }
+
+#ifdef KTRACE
+       if (KTRPOINT(td, KTR_SYSCALL)) {
+               MAKEMPSAFE(have_mplock);
+               ktrsyscall(lp, code, narg, (void *)(&args.nosys.sysmsg + 1));
+       }
+#endif
+
+       /*
+        * Default return value is 0 (will be copied to %rax).  Double-value
+        * returns use %rax and %rdx.  %rdx is left unchanged for system
+        * calls which return only one result.
+        */
+       args.sysmsg_fds[0] = 0;
+       args.sysmsg_fds[1] = frame->tf_rdx;
+
+       /*
+        * The syscall might manipulate the trap frame. If it does it
+        * will probably return EJUSTRETURN.
+        */
+       args.sysmsg_frame = frame;
+
+       STOPEVENT(p, S_SCE, narg);      /* MP aware */
+
+#ifdef SMP
+       /*
+        * Try to run the syscall without the MP lock if the syscall
+        * is MP safe.  We have to obtain the MP lock no matter what if
+        * we are ktracing
+        */
+       if ((callp->sy_narg & SYF_MPSAFE) == 0)
+               MAKEMPSAFE(have_mplock);
+#endif
+
+       error = (*callp->sy_call)(&args);
+
+#if 0
+       kprintf("system call %d returned %d\n", code, error);
+#endif
+
+out:
+       /*
+        * MP SAFE (we may or may not have the MP lock at this point)
+        */
+       switch (error) {
+       case 0:
+               /*
+                * Reinitialize proc pointer `p' as it may be different
+                * if this is a child returning from fork syscall.
+                */
+               p = curproc;
+               lp = curthread->td_lwp;
+               frame->tf_rax = args.sysmsg_fds[0];
+               frame->tf_rdx = args.sysmsg_fds[1];
+               frame->tf_rflags &= ~PSL_C;
+               break;
+       case ERESTART:
+               /*
+                * Reconstruct pc, we know that 'syscall' is 2 bytes.
+                * We have to do a full context restore so that %r10
+                * (which was holding the value of %rcx) is restored for
+                * the next iteration.
+                */
+               frame->tf_rip -= frame->tf_err;
+               frame->tf_r10 = frame->tf_rcx;
+               break;
+       case EJUSTRETURN:
+               break;
+       case EASYNC:
+               panic("Unexpected EASYNC return value (for now)");
+       default:
+bad:
+               if (p->p_sysent->sv_errsize) {
+                       if (error >= p->p_sysent->sv_errsize)
+                               error = -1;     /* XXX */
+                       else
+                               error = p->p_sysent->sv_errtbl[error];
+               }
+               frame->tf_rax = error;
+               frame->tf_rflags |= PSL_C;
+               break;
+       }
+
+       /*
+        * Traced syscall.  trapsignal() is not MP aware.
+        */
+       if (orig_tf_rflags & PSL_T) {
+               MAKEMPSAFE(have_mplock);
+               frame->tf_rflags &= ~PSL_T;
+               trapsignal(lp, SIGTRAP, 0);
+       }
+
+       /*
+        * Handle reschedule and other end-of-syscall issues
+        */
+       userret(lp, frame, sticks);
+
+#ifdef KTRACE
+       if (KTRPOINT(td, KTR_SYSRET)) {
+               MAKEMPSAFE(have_mplock);
+               ktrsysret(lp, code, error, args.sysmsg_result);
+       }
+#endif
+
+       /*
+        * This works because errno is findable through the
+        * register set.  If we ever support an emulation where this
+        * is not the case, this code will need to be revisited.
+        */
+       STOPEVENT(p, S_SCX, code);
+
+       userexit(lp);
+#ifdef SMP
+       /*
+        * Release the MP lock if we had to get it
+        */
+       KASSERT(td->td_mpcount == have_mplock,
+               ("badmpcount syscall2/end from %p", (void *)frame->tf_rip));
+       if (have_mplock)
+               rel_mplock();
+#endif
+       KTR_LOG(kernentry_syscall_ret, lp->lwp_proc->p_pid, lp->lwp_tid, error);
+#ifdef INVARIANTS
+       KASSERT(crit_count == (td->td_pri & ~TDPRI_MASK),
+               ("syscall: critical section count mismatch! %d/%d",
+               crit_count / TDPRI_CRIT, td->td_pri / TDPRI_CRIT));
+#endif
+}
+
+void
+fork_return(struct lwp *lp, struct trapframe *frame)
+{
+       frame->tf_rax = 0;              /* Child returns zero */
+       frame->tf_rflags &= ~PSL_C;     /* success */
+       frame->tf_rdx = 1;
+
+       generic_lwp_return(lp, frame);
+       KTR_LOG(kernentry_fork_ret, lp->lwp_proc->p_pid, lp->lwp_tid);
+}
+
+/*
+ * Simplified back end of syscall(), used when returning from fork()
+ * or lwp_create() directly into user mode.  MP lock is held on entry and
+ * should be released on return.  This code will return back into the fork
+ * trampoline code which then runs doreti.
+ */
+void
+generic_lwp_return(struct lwp *lp, struct trapframe *frame)
+{
+       struct proc *p = lp->lwp_proc;
+
+       /*
+        * Newly forked processes are given a kernel priority.  We have to
+        * adjust the priority to a normal user priority and fake entry
+        * into the kernel (call userenter()) to install a passive release
+        * function just in case userret() decides to stop the process.  This
+        * can occur when ^Z races a fork.  If we do not install the passive
+        * release function the current process designation will not be
+        * released when the thread goes to sleep.
+        */
+       lwkt_setpri_self(TDPRI_USER_NORM);
+       userenter(lp->lwp_thread);
+       userret(lp, frame, 0);
+#ifdef KTRACE
+       if (KTRPOINT(lp->lwp_thread, KTR_SYSRET))
+               ktrsysret(lp, SYS_fork, 0, 0);
+#endif
+       p->p_flag |= P_PASSIVE_ACQ;
+       userexit(lp);
+       p->p_flag &= ~P_PASSIVE_ACQ;
+#ifdef SMP
+       KKASSERT(lp->lwp_thread->td_mpcount == 1);
+       rel_mplock();
+#endif
+}
+
+/*
+ * doreti has turned into this.  The frame is directly on the stack.  We
+ * pull everything else we need (fpu and tls context) from the current
+ * thread.
+ *
+ * Note on fpu interactions: In a virtual kernel, the fpu context for
+ * an emulated user mode process is not shared with the virtual kernel's
+ * fpu context, so we only have to 'stack' fpu contexts within the virtual
+ * kernel itself, and not even then since the signal() contexts that we care
+ * about save and restore the FPU state (I think anyhow).
+ *
+ * vmspace_ctl() returns an error only if it had problems instaling the
+ * context we supplied or problems copying data to/from our VM space.
+ */
+void
+go_user(struct intrframe *frame)
+{
+       struct trapframe *tf = (void *)&frame->if_rdi;
+       int r;
+
+       /*
+        * Interrupts may be disabled on entry, make sure all signals
+        * can be received before beginning our loop.
+        */
+       sigsetmask(0);
+
+       /*
+        * Switch to the current simulated user process, then call
+        * user_trap() when we break out of it (usually due to a signal).
+        */
+       for (;;) {
+               /*
+                * Tell the real kernel whether it is ok to use the FP
+                * unit or not.
+                */
+               if (mdcpu->gd_npxthread == curthread) {
+                       tf->tf_xflags &= ~PGEX_FPFAULT;
+               } else {
+                       tf->tf_xflags |= PGEX_FPFAULT;
+               }
+
+               /*
+                * Run emulated user process context.  This call interlocks
+                * with new mailbox signals.
+                *
+                * Set PGEX_U unconditionally, indicating a user frame (the
+                * bit is normally set only by T_PAGEFLT).
+                */
+               r = vmspace_ctl(&curproc->p_vmspace->vm_pmap, VMSPACE_CTL_RUN,
+                               tf, &curthread->td_savevext);
+               frame->if_xflags |= PGEX_U;
+#if 0
+               kprintf("GO USER %d trap %ld EVA %08lx RIP %08lx RSP %08lx XFLAGS %02lx/%02lx\n",
+                       r, tf->tf_trapno, tf->tf_addr, tf->tf_rip, tf->tf_rsp,
+                       tf->tf_xflags, frame->if_xflags);
+#endif
+               if (r < 0) {
+                       if (errno != EINTR)
+                               panic("vmspace_ctl failed");
+               } else {
+                       if (tf->tf_trapno) {
+                               user_trap(tf);
+                       }
+               }
+               if (mycpu->gd_reqflags & RQF_AST_MASK) {
+                       tf->tf_trapno = T_ASTFLT;
+                       user_trap(tf);
+               }
+               tf->tf_trapno = 0;
+       }
+}
+
+/*
+ * If PGEX_FPFAULT is set then set FP_VIRTFP in the PCB to force a T_DNA
+ * fault (which is then passed back to the virtual kernel) if an attempt is
+ * made to use the FP unit.
+ *
+ * XXX this is a fairly big hack.
+ */
+void
+set_vkernel_fp(struct trapframe *frame)
+{
+       struct thread *td = curthread;
+
+       if (frame->tf_xflags & PGEX_FPFAULT) {
+               td->td_pcb->pcb_flags |= FP_VIRTFP;
+               if (mdcpu->gd_npxthread == td)
+                       npxexit();
+       } else {
+               td->td_pcb->pcb_flags &= ~FP_VIRTFP;
+       }
+}
diff --git a/sys/platform/vkernel64/amd64/userldt.c b/sys/platform/vkernel64/amd64/userldt.c
new file mode 100644 (file)
index 0000000..0b96665
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/i386/userldt.c,v 1.2 2007/01/07 08:37:35 dillon Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <machine/pcb.h>
+#include <machine/pcb_ext.h>
+
+void
+set_user_ldt (struct pcb *pcb)
+{
+       panic("set_user_ldt");
+}
+
+struct pcb_ldt *
+user_ldt_alloc (struct pcb *pcb, int len)
+{
+       panic("user_ldt_alloc");
+}
+
+void
+user_ldt_free (struct pcb *pcb)
+{
+       if (pcb->pcb_ldt)
+               panic("user_ldt_free");
+}
diff --git a/sys/platform/vkernel64/amd64/vm_machdep.c b/sys/platform/vkernel64/amd64/vm_machdep.c
new file mode 100644 (file)
index 0000000..8673ebc
--- /dev/null
@@ -0,0 +1,355 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * Copyright (c) 1989, 1990 William Jolitz
+ * Copyright (c) 1994 John Dyson
+ * Copyright (c) 2008 The DragonFly Project.
+ * 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.
+ *
+ *     from: @(#)vm_machdep.c  7.3 (Berkeley) 5/13/91
+ *     Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
+ * $FreeBSD: src/sys/i386/i386/vm_machdep.c,v 1.132.2.9 2003/01/25 19:02:23 dillon Exp $
+ * $DragonFly: src/sys/platform/pc64/amd64/vm_machdep.c,v 1.3 2008/08/29 17:07:10 dillon Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/interrupt.h>
+#include <sys/vnode.h>
+#include <sys/vmmeter.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/md_var.h>
+#include <machine/smp.h>
+#include <machine/pcb.h>
+#include <machine/pcb_ext.h>
+#include <machine/segments.h>
+#include <machine/globaldata.h>        /* npxthread */
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <sys/lock.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+
+#include <sys/thread2.h>
+
+#include <bus/isa/isa.h>
+
+char machine[] = MACHINE;
+SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
+             machine, 0, "Machine class");
+
+/*
+ * Finish a fork operation, with lwp lp2 nearly set up.
+ * Copy and update the pcb, set up the stack so that the child
+ * ready to run and return to user mode.
+ */
+void
+cpu_fork(struct lwp *lp1, struct lwp *lp2, int flags)
+{
+       struct pcb *pcb2;
+
+       if ((flags & RFPROC) == 0) {
+               if ((flags & RFMEM) == 0) {
+                       /* unshare user LDT */
+                       struct pcb *pcb1 = lp1->lwp_thread->td_pcb;
+                       struct pcb_ldt *pcb_ldt = pcb1->pcb_ldt;
+                       if (pcb_ldt && pcb_ldt->ldt_refcnt > 1) {
+                               pcb_ldt = user_ldt_alloc(pcb1,pcb_ldt->ldt_len);
+                               user_ldt_free(pcb1);
+                               pcb1->pcb_ldt = pcb_ldt;
+                               set_user_ldt(pcb1);
+                       }
+               }
+               return;
+       }
+
+       /* Ensure that lp1's pcb is up to date. */
+       if (mdcpu->gd_npxthread == lp1->lwp_thread)
+               npxsave(lp1->lwp_thread->td_savefpu);
+
+       /*
+        * Copy lp1's PCB.  This really only applies to the
+        * debug registers and FP state, but its faster to just copy the
+        * whole thing.  Because we only save the PCB at switchout time,
+        * the register state may not be current.
+        */
+       pcb2 = lp2->lwp_thread->td_pcb;
+       *pcb2 = *lp1->lwp_thread->td_pcb;
+
+       /*
+        * Create a new fresh stack for the new process.
+        * Copy the trap frame for the return to user mode as if from a
+        * syscall.  This copies the user mode register values.
+        *
+        * pcb_rsp must allocate an additional call-return pointer below
+        * the trap frame which will be restored by cpu_heavy_restore from
+        * PCB_RIP, and the thread's td_sp pointer must allocate an
+        * additonal two quadwords below the pcb_rsp call-return pointer to
+        * hold the LWKT restore function pointer and rflags.
+        *
+        * The LWKT restore function pointer must be set to cpu_heavy_restore,
+        * which is our standard heavy-weight process switch-in function.
+        * YYY eventually we should shortcut fork_return and fork_trampoline
+        * to use the LWKT restore function directly so we can get rid of
+        * all the extra crap we are setting up.
+        */
+       lp2->lwp_md.md_regs = (struct trapframe *)pcb2 - 1;
+       bcopy(lp1->lwp_md.md_regs, lp2->lwp_md.md_regs, sizeof(*lp2->lwp_md.md_regs));
+
+       /*
+        * Set registers for trampoline to user mode.  Leave space for the
+        * return address on stack.  These are the kernel mode register values.
+        */
+       pcb2->pcb_unused01 = 0;
+       pcb2->pcb_rbx = (unsigned long)fork_return;     /* fork_trampoline argument */
+       pcb2->pcb_rbp = 0;
+       pcb2->pcb_rsp = (unsigned long)lp2->lwp_md.md_regs - sizeof(void *);
+       pcb2->pcb_r12 = (unsigned long)lp2;             /* fork_trampoline argument */
+       pcb2->pcb_r13 = 0;
+       pcb2->pcb_r14 = 0;
+       pcb2->pcb_r15 = 0;
+       pcb2->pcb_rip = (unsigned long)fork_trampoline;
+       lp2->lwp_thread->td_sp = (char *)(pcb2->pcb_rsp - sizeof(void *));
+       *(u_int64_t *)lp2->lwp_thread->td_sp = PSL_USER;
+       lp2->lwp_thread->td_sp -= sizeof(void *);
+       *(void **)lp2->lwp_thread->td_sp = (void *)cpu_heavy_restore;
+
+       /*
+        * pcb2->pcb_ldt:       duplicated below, if necessary.
+        * pcb2->pcb_savefpu:   cloned above.
+        * pcb2->pcb_flags:     cloned above (always 0 here?).
+        * pcb2->pcb_onfault:   cloned above (always NULL here?).
+        */
+
+       /*
+        * XXX don't copy the i/o pages.  this should probably be fixed.
+        */
+       pcb2->pcb_ext = 0;
+
+        /* Copy the LDT, if necessary. */
+        if (pcb2->pcb_ldt != 0) {
+               if (flags & RFMEM) {
+                       pcb2->pcb_ldt->ldt_refcnt++;
+               } else {
+                       pcb2->pcb_ldt = user_ldt_alloc(pcb2,
+                               pcb2->pcb_ldt->ldt_len);
+               }
+        }
+       bcopy(&lp1->lwp_thread->td_tls, &lp2->lwp_thread->td_tls,
+             sizeof(lp2->lwp_thread->td_tls));
+       /*
+        * Now, cpu_switch() can schedule the new lwp.
+        * pcb_rsp is loaded pointing to the cpu_switch() stack frame
+        * containing the return address when exiting cpu_switch.
+        * This will normally be to fork_trampoline(), which will have
+        * %rbx loaded with the new lwp's pointer.  fork_trampoline()
+        * will set up a stack to call fork_return(lp, frame); to complete
+        * the return to user-mode.
+        */
+}
+
+/*
+ * Prepare new lwp to return to the address specified in params.
+ */
+int
+cpu_prepare_lwp(struct lwp *lp, struct lwp_params *params)
+{
+       struct trapframe *regs = lp->lwp_md.md_regs;
+       void *bad_return = NULL;
+       int error;
+
+       regs->tf_rip = (long)params->func;
+       regs->tf_rsp = (long)params->stack;
+       /* Set up argument for function call */
+       regs->tf_rdi = (long)params->arg; /* JG Can this be in userspace addresses? */
+       /*
+        * Set up fake return address.  As the lwp function may never return,
+        * we simply copy out a NULL pointer and force the lwp to receive
+        * a SIGSEGV if it returns anyways.
+        */
+       regs->tf_rsp -= sizeof(void *);
+       error = copyout(&bad_return, (void *)regs->tf_rsp, sizeof(bad_return));
+       if (error)
+               return (error);
+
+       cpu_set_fork_handler(lp,
+           (void (*)(void *, struct trapframe *))generic_lwp_return, lp);
+       return (0);
+}
+
+/*
+ * Intercept the return address from a freshly forked process that has NOT
+ * been scheduled yet.
+ *
+ * This is needed to make kernel threads stay in kernel mode.
+ */
+void
+cpu_set_fork_handler(struct lwp *lp, void (*func)(void *, struct trapframe *),
+                    void *arg)
+{
+       /*
+        * Note that the trap frame follows the args, so the function
+        * is really called like this:  func(arg, frame);
+        */
+       lp->lwp_thread->td_pcb->pcb_rbx = (long)func;   /* function */
+       lp->lwp_thread->td_pcb->pcb_r12 = (long)arg;    /* first arg */
+}
+
+void
+cpu_set_thread_handler(thread_t td, void (*rfunc)(void), void *func, void *arg)
+{
+       td->td_pcb->pcb_rbx = (long)func;
+       td->td_pcb->pcb_r12 = (long)arg;
+       td->td_switch = cpu_lwkt_switch;
+       td->td_sp -= sizeof(void *);
+       *(void **)td->td_sp = rfunc;    /* exit function on return */
+       td->td_sp -= sizeof(void *);
+       *(void **)td->td_sp = cpu_kthread_restore;
+}
+
+void
+cpu_lwp_exit(void)
+{
+       struct thread *td = curthread;
+       struct pcb *pcb;
+       npxexit();
+       pcb = td->td_pcb;
+       KKASSERT(pcb->pcb_ext == NULL); /* Some i386 functionality was dropped */
+        if (pcb->pcb_flags & PCB_DBREGS) {
+                /*
+                 * disable all hardware breakpoints
+                 */
+                reset_dbregs();
+                pcb->pcb_flags &= ~PCB_DBREGS;
+        }
+       td->td_gd->gd_cnt.v_swtch++;
+
+       crit_enter_quick(td);
+       lwkt_deschedule_self(td);
+       lwkt_remove_tdallq(td);
+       cpu_thread_exit();
+}
+
+/*
+ * Terminate the current thread.  The caller must have already acquired
+ * the thread's rwlock and placed it on a reap list or otherwise notified
+ * a reaper of its existance.  We set a special assembly switch function which
+ * releases td_rwlock after it has cleaned up the MMU state and switched
+ * out the stack.
+ *
+ * Must be caller from a critical section and with the thread descheduled.
+ */
+void
+cpu_thread_exit(void)
+{
+       curthread->td_switch = cpu_exit_switch;
+       curthread->td_flags |= TDF_EXITING;
+       lwkt_switch();
+       panic("cpu_thread_exit: lwkt_switch() unexpectedly returned");
+}
+
+/*
+ * Process Reaper.  Called after the caller has acquired the thread's
+ * rwlock and removed it from the reap list.
+ */
+void
+cpu_proc_wait(struct proc *p)
+{
+       /* drop per-process resources */
+       pmap_dispose_proc(p);
+}
+
+int
+grow_stack(struct proc *p, u_long sp)
+{
+       int rv;
+
+       rv = vm_map_growstack (p, sp);
+       if (rv != KERN_SUCCESS)
+               return (0);
+
+       return (1);
+}
+
+/*
+ * Tell whether this address is in some physical memory region.
+ * Currently used by the kernel coredump code in order to avoid
+ * dumping the ``ISA memory hole'' which could cause indefinite hangs,
+ * or other unpredictable behaviour.
+ */
+
+int
+is_physical_memory(vm_offset_t addr)
+{
+       return 1;
+}
+
+/*
+ * Used by /dev/kmem to determine if we can safely read or write
+ * the requested KVA range.  Some portions of kernel memory are
+ * not governed by our virtual page table.
+ */
+extern int64_t _end;
+extern void _start(void);
+
+int
+kvm_access_check(vm_offset_t saddr, vm_offset_t eaddr, int prot)
+{
+       vm_offset_t addr;
+
+       if (saddr >= trunc_page((vm_offset_t)&_start) && eaddr <= round_page((vm_offset_t)&_end))
+               return 0;
+       if (saddr < KvaStart)
+               return EFAULT;
+       if (eaddr >= KvaEnd)
+               return EFAULT;
+       for (addr = saddr; addr < eaddr; addr += PAGE_SIZE)  {
+               if (pmap_extract(&kernel_pmap, addr) == 0)
+                       return EFAULT;
+       }
+       if (!kernacc((caddr_t)saddr, eaddr - saddr, prot))
+               return EFAULT;
+       return 0;
+}
diff --git a/sys/platform/vkernel64/conf/Makefile b/sys/platform/vkernel64/conf/Makefile
new file mode 100644 (file)
index 0000000..8ac1446
--- /dev/null
@@ -0,0 +1,36 @@
+# $DragonFly: src/sys/platform/vkernel/conf/Makefile,v 1.7 2007/07/01 02:51:41 dillon Exp $
+#
+# Which version of config(8) is required.
+%VERSREQ=      400026
+
+.if !defined(S)
+.if exists(./@/.)
+S=     ./@
+.else
+S=     ../..
+.endif
+.endif
+
+.include "$S/conf/kern.pre.mk"
+
+# Override the normal kernel link and link as a normal user program
+#
+SYSTEM_LD= @${CC} -g -export-dynamic -o ${.TARGET} ${SYSTEM_OBJS} vers.o -pthread
+
+%BEFORE_DEPEND
+
+%OBJS
+
+%CFILES
+
+%SFILES
+
+%MFILES
+
+%CLEAN
+
+.include "$S/conf/kern.post.mk"
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
diff --git a/sys/platform/vkernel64/conf/files b/sys/platform/vkernel64/conf/files
new file mode 100644 (file)
index 0000000..b96e7fc
--- /dev/null
@@ -0,0 +1,66 @@
+# This file tells config what files go into building a kernel,
+# files marked standard are always included.
+#
+# $DragonFly: src/sys/platform/vkernel/conf/files,v 1.21 2008/03/20 02:14:52 dillon Exp $
+#
+emulation/dragonfly12/dfbsd12_getdirentries.c  nonoptional     compat_df12
+emulation/dragonfly12/dfbsd12_stat.c           nonoptional     compat_df12
+vfs/smbfs/smbfs_io.c           optional        smbfs
+vfs/smbfs/smbfs_node.c         optional        smbfs
+vfs/smbfs/smbfs_smb.c          optional        smbfs
+vfs/smbfs/smbfs_subr.c         optional        smbfs
+vfs/smbfs/smbfs_vfsops.c       optional        smbfs
+vfs/smbfs/smbfs_vnops.c                optional        smbfs
+cpu/amd64/misc/atomic.c                standard                                \
+       compile-with    "${CC} -c ${CFLAGS} ${DEFINED_PROF:S/^$/-fomit-frame-pointer/} ${.IMPSRC}"
+platform/vkernel64/amd64/autoconf.c    standard
+platform/vkernel64/amd64/mp.c          optional        smp             \
+       compile-with    "${CC} -c -pthread ${CFLAGS} -I/usr/include ${.IMPSRC}"
+platform/vkernel64/amd64/mplock.s              optional        smp
+#
+# DDB XXX
+cpu/amd64/misc/elf_machdep.c           standard
+cpu/amd64/misc/in_cksum2.s             optional        inet
+cpu/amd64/misc/ktr.c                   optional        ktr
+cpu/amd64/misc/db_disasm.c             optional        ddb
+cpu/amd64/misc/amd64-gdbstub.c         optional        ddb
+#
+# DOS mbr and gpt
+kern/subr_diskmbr.c                    standard
+kern/subr_diskgpt.c                    standard
+
+# DEVICES
+#
+dev/virtual/cdrom/vcd.c                        optional        vcd
+dev/virtual/disk/vdisk.c               optional        vkd
+dev/virtual/net/if_vke.c               optional        vke
+
+# PLATFORM FILES
+#
+platform/vkernel64/amd64/global.s              standard
+platform/vkernel64/amd64/swtch.s               standard
+platform/vkernel64/amd64/npx.c         standard
+platform/vkernel64/amd64/db_interface.c        optional        ddb
+platform/vkernel64/amd64/db_trace.c    optional        ddb
+platform/vkernel64/amd64/vm_machdep.c  standard
+platform/vkernel64/amd64/cpu_regs.c    standard
+platform/vkernel64/amd64/userldt.c             standard
+platform/vkernel64/amd64/tls.c         standard
+platform/vkernel64/amd64/trap.c                standard
+platform/vkernel64/amd64/exception.c   standard
+platform/vkernel64/amd64/procfs_machdep.c      standard
+platform/vkernel64/amd64/fork_tramp.s  standard
+platform/vkernel64/platform/init.c     standard
+platform/vkernel64/platform/globaldata.c       standard
+platform/vkernel64/platform/kqueue.c   standard
+platform/vkernel64/platform/shutdown.c standard
+platform/vkernel64/platform/machintr.c standard
+platform/vkernel64/platform/copyio.c   standard
+platform/vkernel64/platform/pmap.c     standard
+platform/vkernel64/platform/pmap_inval.c       standard
+platform/vkernel64/platform/busdma_machdep.c standard
+platform/vkernel64/platform/sysarch.c  standard
+platform/vkernel64/platform/systimer.c standard
+platform/vkernel64/platform/console.c  standard
+platform/vkernel64/platform/ipl_funcs.c        standard
+platform/vkernel64/platform/cothread.c standard
diff --git a/sys/platform/vkernel64/conf/kern.mk b/sys/platform/vkernel64/conf/kern.mk
new file mode 100644 (file)
index 0000000..39af0c8
--- /dev/null
@@ -0,0 +1,18 @@
+# $DragonFly: src/sys/platform/vkernel/conf/kern.mk,v 1.3 2007/01/06 08:57:30 dillon Exp $
+#
+#
+# Prohibit the use of FP registers in the kernel.  The user FP state is
+# only saved and restored under strictly managed conditions and mainline
+# kernel code cannot safely use the FP system.
+#
+CFLAGS+=       -mpreferred-stack-boundary=4
+CFLAGS+=       -fno-stack-protector
+CFLAGS+=       -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3
+CFLAGS+=       -D_KERNEL_VIRTUAL
+CFLAGS+=       -fno-omit-frame-pointer
+
+# Remove the dynamic library hack for now
+#
+SYSTEM_OBJS:= ${SYSTEM_OBJS:Nhack.So}
+
+INLINE_LIMIT=  8000
diff --git a/sys/platform/vkernel64/conf/ldscript.amd64 b/sys/platform/vkernel64/conf/ldscript.amd64
new file mode 100644 (file)
index 0000000..ce05503
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * $FreeBSD: src/sys/conf/ldscript.amd64,v 1.9 2004/05/29 01:09:00 tjr Exp $
+ * $DragonFly: src/sys/platform/pc64/conf/ldscript.amd64,v 1.1 2007/09/23 04:29:31 yanyh Exp $
+ */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(btext)
+SEARCH_DIR("/usr/lib");
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = kernbase + 0x00100000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata    : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss      : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x90909090
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x90909090
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x90909090
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = DATA_SEGMENT_ALIGN(0x100000, 0x1000);
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(64 / 8);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .eh_frame       : { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : { *(.gcc_except_table) }
+  .dynamic        : { *(.dynamic) }
+  _start_ctors = .;
+  PROVIDE (start_ctors = .);
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin.o(.ctors))
+    /* We don't want to include the .ctor section from
+       from the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  _stop_ctors = .;
+  PROVIDE (stop_ctors = .);
+  .dtors          :
+  {
+    KEEP (*crtbegin.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .got            : { *(.got.plt) *(.got) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(64 / 8);
+  }
+  . = ALIGN(64 / 8);
+  _end = .;
+  PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+}
diff --git a/sys/platform/vkernel64/conf/options b/sys/platform/vkernel64/conf/options
new file mode 100644 (file)
index 0000000..d695377
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# $DragonFly: src/sys/platform/vkernel/conf/options,v 1.2 2006/10/25 20:55:51 dillon Exp $
+#
+
+# The cpu type
+#
+HAMMER_CPU              opt_global.h
+
+#
+#
+SHOW_BUSYBUFS
+PANIC_REBOOT_WAIT_TIME  opt_panic.h
diff --git a/sys/platform/vkernel64/include/clock.h b/sys/platform/vkernel64/include/clock.h
new file mode 100644 (file)
index 0000000..6465b61
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Kernel interface to machine-dependent clock driver.
+ * Garrett Wollman, September 1994.
+ * This file is in the public domain.
+ *
+ * $FreeBSD: src/sys/i386/include/clock.h,v 1.38.2.1 2002/11/02 04:41:50 iwasaki Exp $
+ * $DragonFly: src/sys/platform/vkernel/include/clock.h,v 1.2 2008/05/10 17:24:11 dillon Exp $
+ */
+
+#ifndef _MACHINE_CLOCK_H_
+#define        _MACHINE_CLOCK_H_
+
+#ifdef _KERNEL
+
+#ifndef _SYS_TYPES_H_
+#include <sys/types.h>
+#endif
+
+/*
+ * i386 to clock driver interface.
+ * XXX large parts of the driver and its interface are misplaced.
+ */
+extern int     adjkerntz;
+extern int     disable_rtc_set;
+extern int     statclock_disable;
+extern u_int   timer_freq;
+extern int     timer0_max_count;
+extern int     tsc_present;
+extern int64_t tsc_frequency;
+extern int     tsc_is_broken;
+extern int     wall_cmos_clock;
+#ifdef APIC_IO
+extern int     apic_8254_intr;
+#endif
+
+/*
+ * Driver to clock driver interface.
+ */
+
+int    rtcin (int val);
+int    acquire_timer2 (int mode);
+int    release_timer2 (void);
+int    sysbeep (int pitch, int period);
+void   timer_restore (void);
+
+#endif /* _KERNEL */
+
+#endif /* !_MACHINE_CLOCK_H_ */
diff --git a/sys/platform/vkernel64/include/cothread.h b/sys/platform/vkernel64/include/cothread.h
new file mode 100644 (file)
index 0000000..7fd72a2
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/include/cothread.h,v 1.2 2008/03/27 04:28:07 dillon Exp $
+ */
+
+#ifndef _MACHINE_COTHREAD_H_
+#define _MACHINE_COTHREAD_H_
+
+#include <pthread.h>
+
+struct cothread {
+       pthread_t       pthr;
+       pthread_t       pintr;
+       void            *arg;
+       void            (*thr_func)(struct cothread *);
+       void            (*thr_intr)(struct cothread *);
+       void            *intr_id;
+       pthread_mutex_t mutex;
+       pthread_cond_t  cond;
+};
+
+typedef struct cothread *cothread_t;
+
+cothread_t cothread_create(void (*thr_func)(cothread_t cotd),
+                          void (*thr_intr)(cothread_t cotd),
+                          void *arg, const  char *name);
+void cothread_delete(cothread_t *cotdp);
+void cothread_intr(cothread_t cotd);
+void cothread_signal(cothread_t cotd);
+void cothread_wait(cothread_t cotd);
+void cothread_lock(cothread_t cotd, int is_cotd);
+void cothread_unlock(cothread_t cotd, int is_cotd);
+
+#endif
diff --git a/sys/platform/vkernel64/include/cpu.h b/sys/platform/vkernel64/include/cpu.h
new file mode 100644 (file)
index 0000000..c1d1373
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/include/cpu.h,v 1.3 2008/05/19 10:29:58 corecode Exp $
+ */
+
+#ifndef _MACHINE_CPU_H_
+#define _MACHINE_CPU_H_
+
+#include <cpu/cpu.h>
+
+#define CLKF_USERMODE(framep) ((framep)->if_xflags & PGEX_U)
+
+/* globals used in vkernel CPU to kernel CPU locking */
+#if defined(_KERNEL)
+
+extern int lwp_cpu_lock;
+extern int next_cpu;
+extern int real_ncpus;
+void setrealcpu(void);
+void identcpu(void);
+
+#endif
+
+#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
+
+#define LCL_NONE        0
+#define LCL_PER_CPU     1
+#define LCL_SINGLE_CPU  2
+
+#endif
+
+#endif
diff --git a/sys/platform/vkernel64/include/cpufunc.h b/sys/platform/vkernel64/include/cpufunc.h
new file mode 100644 (file)
index 0000000..4418245
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/include/cpufunc.h,v 1.2 2007/02/18 14:28:18 corecode Exp $
+ */
+#ifndef _MACHINE_CPUFUNC_H_
+#define        _MACHINE_CPUFUNC_H_
+
+#ifdef _KERNEL
+
+/*
+ * First declare our overriding functions.  We have to do this to prevent
+ * cpu/cpufunc.h to define inline assembler versions.  However, we need
+ * cpu/cpufunc.h to define other functions like ``ffs'', which will otherwise
+ * be defined by libkern (via sys/systm.h).  This is why the order needs to be:
+ *
+ * 1. Declare our overrides
+ * 2. include cpu/cpufunc.h
+ * 3. include the remaining needed headers for our overrides
+ */
+
+#define _CPU_ENABLE_INTR_DEFINED
+#define _CPU_DISABLE_INTR_DEFINED
+#define _CPU_INVLPG_DEFINED
+#define _CPU_INVLTLB_DEFINED
+
+void cpu_disable_intr(void);
+void cpu_enable_intr(void);
+void cpu_invlpg(void *addr);
+void cpu_invltlb(void);
+
+#endif
+
+#include <cpu/cpufunc.h>
+
+#ifdef _KERNEL
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <vm/pmap.h>
+
+#include <sys/mman.h>
+#include <signal.h>
+
+#endif /* _KERNEL */
+
+#endif /* !_MACHINE_CPUFUNC_H_ */
diff --git a/sys/platform/vkernel64/include/globaldata.h b/sys/platform/vkernel64/include/globaldata.h
new file mode 100644 (file)
index 0000000..113cc15
--- /dev/null
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) Peter Wemm <peter@netplex.com.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     Only machine-dependant code should ever include this file.  MI
+ *     code and header files do NOT include this file.  e.g. sys/globaldata.h
+ *     should not include this file.
+ *
+ * $FreeBSD: src/sys/i386/include/globaldata.h,v 1.11.2.1 2000/05/16 06:58:10 dillon Exp $
+ * $DragonFly: src/sys/platform/vkernel/include/globaldata.h,v 1.8 2008/04/28 07:05:07 dillon Exp $
+ */
+
+#ifndef _MACHINE_GLOBALDATA_H_
+#define _MACHINE_GLOBALDATA_H_
+
+#if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
+
+#ifndef _SYS_GLOBALDATA_H_
+#include <sys/globaldata.h>    /* struct globaldata */
+#endif
+#ifndef _SYS_THREAD_H_
+#include <sys/thread.h>                /* struct thread */
+#endif
+#ifndef _SYS_VKERNEL_H_
+#include <sys/vkernel.h>       /* vpte_t */
+#endif
+#ifndef _MACHINE_SEGMENTS_H_
+#include <machine/segments.h>  /* struct segment_descriptor */
+#endif
+#ifndef _MACHINE_TSS_H_
+#include <machine/tss.h>       /* struct i386tss */
+#endif
+#ifndef _MACHINE_NPX_H_
+#include <machine/npx.h>
+#endif
+
+/*
+ * Note on interrupt control.  Pending interrupts not yet dispatched are
+ * marked in gd_fpending, gd_ipending, or gd_spending.  Once dispatched
+ * the interrupt's pending bit is cleared and the interrupt is masked.
+ * Upon completion the interrupt is unmasked.
+ *
+ * For edge triggered interrupts interrupts may be enabled again at this
+ * point and if they occur before the interrupt service routine is complete
+ * the service routine will loop.
+ *
+ * The current thread's cpl is stored in the thread structure.
+ *
+ * Note: the embedded globaldata and/or the mdglobaldata structure
+ * may exceed the size of a page.
+ */
+struct mdglobaldata {
+       struct globaldata mi;
+       struct user_segment_descriptor gd_common_tssd;
+       struct user_segment_descriptor *gd_tss_gdt;
+       struct thread   *gd_npxthread;
+       struct amd64tss gd_common_tss;
+       union savefpu   gd_savefpu;     /* fast bcopy/zero temp fpu save area */
+       int             gd_fpu_lock;    /* fast bcopy/zero cpu lock */
+       int             gd_fpending;    /* fast interrupt pending */
+       int             gd_ipending;    /* normal interrupt pending */
+       int             gd_spending;    /* software interrupt pending */
+       int             gd_sdelayed;    /* delayed software ints */
+       int             gd_currentldt;
+       int             unused003;
+       int             unused002;
+       u_int           unused001;
+       u_int           gd_other_cpus;
+       u_int           gd_ss_eflags;
+};
+
+#define MDGLOBALDATA_BASEALLOC_SIZE    \
+       ((sizeof(struct mdglobaldata) + PAGE_MASK) & ~PAGE_MASK)
+#define MDGLOBALDATA_BASEALLOC_PAGES   \
+       (MDGLOBALDATA_BASEALLOC_SIZE / PAGE_SIZE)
+#define MDGLOBALDATA_PAD               \
+       (MDGLOBALDATA_BASEALLOC_SIZE - sizeof(struct mdglobaldata))
+
+/*
+ * This is the upper (0xff800000) address space layout that is per-cpu.
+ * It is setup in locore.s and pmap.c for the BSP and in mp_machdep.c for
+ * each AP.  genassym helps export this to the assembler code.
+ *
+ * WARNING!  This structure must be segment-aligned and portions within the
+ *           structure must also be segment-aligned.  The structure typically
+ *          takes 3 segments per cpu (12MB).
+ */
+#define PRIVATESPACE_SEGPAD    \
+       (SEG_SIZE -             \
+       ((sizeof(struct mdglobaldata) + MDGLOBALDATA_PAD + PAGE_SIZE * 4 +  \
+       UPAGES * PAGE_SIZE) % SEG_SIZE))                                    \
+
+struct privatespace {
+       /* main data page */
+       struct mdglobaldata mdglobaldata;
+       char            __filler0[MDGLOBALDATA_PAD];
+
+       /* idle stack (UPAGES pages) */
+       char            idlestack[UPAGES * PAGE_SIZE];
+};
+#define mdcpu                  ((struct mdglobaldata *)_get_mycpu())
+
+#endif
+
+#ifdef _KERNEL
+
+extern struct privatespace *CPU_prvspace;
+
+#endif
+
+#endif
diff --git a/sys/platform/vkernel64/include/lock.h b/sys/platform/vkernel64/include/lock.h
new file mode 100644 (file)
index 0000000..44e27c7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003-2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/include/lock.h,v 1.11.2.2 2000/09/30 02:49:34 ps Exp $
+ * $DragonFly: src/sys/platform/vkernel/include/lock.h,v 1.2 2008/06/19 21:32:55 aggelos Exp $
+ */
+
+#ifndef _MACHINE_LOCK_H_
+#define _MACHINE_LOCK_H_
+
+#ifndef _CPU_PSL_H_
+#include <machine/psl.h>
+#endif
+
+/*
+ * MP_FREE_LOCK is used by both assembly and C under SMP.
+ */
+#ifdef SMP
+#define MP_FREE_LOCK           0xffffffff      /* value of lock when free */
+#endif
+
+#ifndef LOCORE
+
+#if defined(_KERNEL) || defined(_UTHREAD)
+
+/*
+ * MP LOCK functions for SMP and UP.  Under UP the MP lock does not exist
+ * but we leave a few functions intact as macros for convenience.
+ */
+#ifdef SMP
+
+void   get_mplock(void);
+int    try_mplock(void);
+void   rel_mplock(void);
+int    cpu_try_mplock(void);
+void   cpu_get_initial_mplock(void);
+
+extern u_int   mp_lock;
+
+#define MP_LOCK_HELD()   (mp_lock == mycpu->gd_cpuid)
+#define ASSERT_MP_LOCK_HELD(td)   KASSERT(MP_LOCK_HELD(), ("MP_LOCK_HELD(): not held thread %p", td))
+
+static __inline void
+cpu_rel_mplock(void)
+{
+       mp_lock = MP_FREE_LOCK;
+}
+
+static __inline int
+owner_mplock(void)
+{
+       return (mp_lock);
+}
+
+#else
+
+#define get_mplock()
+#define try_mplock()   1
+#define rel_mplock()
+#define owner_mplock() 0       /* always cpu 0 */
+#define MP_LOCK_HELD() (!0)
+#define ASSERT_MP_LOCK_HELD(td)
+
+#endif /* SMP */
+#endif  /* _KERNEL || _UTHREAD */
+#endif /* LOCORE */
+#endif /* !_MACHINE_LOCK_H_ */
diff --git a/sys/platform/vkernel64/include/md_var.h b/sys/platform/vkernel64/include/md_var.h
new file mode 100644 (file)
index 0000000..cfa8d4a
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * 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 DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ *
+ * $DragonFly: src/sys/platform/vkernel/include/md_var.h,v 1.24 2008/03/20 02:14:54 dillon Exp $
+ */
+
+#ifndef _MACHINE_MD_VAR_H_
+#define _MACHINE_MD_VAR_H_
+
+#ifndef _SYS_TYPES_H_
+#include <sys/types.h>
+#endif
+#ifndef _SYS_VKERNEL_H_
+#include <sys/vkernel.h>
+#endif
+
+#define VKNETIF_MAX    16
+#define VKDISK_MAX     16
+
+struct vknetif_info {
+       int             tap_fd;
+       int             tap_unit;
+       in_addr_t       netif_addr;
+       in_addr_t       netif_mask;
+};
+
+struct vkdisk_info {
+        int fd;
+        int unit;
+       enum vkdisk_type { VKD_EMPTY, VKD_DISK, VKD_CD } type;
+        char fname[MAXPATHLEN];
+};
+
+extern char    sigcode[];
+extern int     szsigcode;
+extern vpte_t  *KernelPTA;     /* NOTE: Offset for direct VA translation */
+extern vpte_t  *KernelPTD;
+extern vm_offset_t crashdumpmap;
+extern  int    cpu_fxsr;
+
+extern  char    cpu_vendor[];  /* XXX belongs in i386 */
+extern  u_int   cpu_id;                /* XXX belongs in i386 */
+
+extern struct vkdisk_info DiskInfo[VKDISK_MAX];
+extern int     DiskNum;
+extern int     MemImageFd;
+extern struct vknetif_info NetifInfo[VKNETIF_MAX];
+extern int     NetifNum;
+extern int     _ucodesel, _udatasel;
+
+extern int     via_feature_xcrypt;
+extern int     via_feature_rng;
+
+struct mdglobaldata;
+struct __mcontext;
+
+vpte_t *pmap_kpte(vm_offset_t va);
+void cpu_gdinit (struct mdglobaldata *gd, int cpu);
+
+void cpu_heavy_restore(void);  /* cannot be called from C */
+void cpu_lwkt_restore(void);    /* cannot be called from C */
+void cpu_idle_restore(void);    /* cannot be called from C */
+void cpu_kthread_restore(void);        /* cannot be called from C */
+void cpu_exit_switch (struct thread *next);
+void cpu_setregs (void);
+void cpu_idle (void);
+void cpu_mask_all_signals (void);
+void cpu_unmask_all_signals (void);
+void go_user (struct intrframe *frame);
+
+void init_exceptions(void);
+void init_kqueue(void);
+void init_fpu(int supports_sse);
+void kern_trap(struct trapframe *);
+void user_trap(struct trapframe *);
+void syscall2 (struct trapframe *);
+void vcons_set_mode(int);
+int npxdna(struct trapframe *);
+void npxpush(struct __mcontext *mctx);
+void npxpop(struct __mcontext *mctx);
+
+void signalintr(int intr);
+
+struct kqueue_info;
+struct kqueue_info *kqueue_add(int, void (*)(void *, struct intrframe *), void *);
+void kqueue_del(struct kqueue_info *);
+struct kqueue_info *kqueue_add_timer(void (*func)(void *, struct intrframe *), void *data);
+void kqueue_reload_timer(struct kqueue_info *info, int ms);
+
+
+#endif
diff --git a/sys/platform/vkernel64/include/param.h b/sys/platform/vkernel64/include/param.h
new file mode 100644 (file)
index 0000000..d500d32
--- /dev/null
+++ b/