Merge branch 'arrakis'
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Fri, 14 Aug 2015 06:46:05 +0000 (08:46 +0200)
committerSimon Gerber <simon.gerber@inf.ethz.ch>
Fri, 14 Aug 2015 06:46:05 +0000 (08:46 +0200)
Signed-off-by: Simon Gerber <simon.gerber@inf.ethz.ch>

169 files changed:
AUTHORS
README
README_ARRAKIS [new file with mode: 0644]
devices/Hakefile
devices/e10k_vf.dev
devices/ia32.dev
devices/megaraid.dev [new file with mode: 0644]
devices/pci_sr_iov_cap.dev
devices/vtd.dev [new file with mode: 0644]
devices/vtd_iotlb.dev [new file with mode: 0644]
errors/errno.fugu
hake/Config.hs.template
hake/Main.hs [changed mode: 0644->0755]
hake/RuleDefs.hs
hake/symbolic_targets.mk
if/Hakefile
if/acpi.if
if/arrakis.if
if/e10k.if
if/e10k_vf.if
if/subways.if [new file with mode: 0644]
include/acpi_client/acpi_client.h
include/arch/x86_64/barrelfish/invocations_arch.h
include/arch/x86_64/barrelfish/lmp_chan_arch.h
include/arch/x86_64/barrelfish/syscall_arch.h
include/arranet.h
include/arranet_debug.h
include/arranet_impl.h
include/barrelfish/caddr.h
include/barrelfish/ump_impl.h
include/barrelfish/vregion.h
include/barrelfish_kpi/capabilities.h
include/barrelfish_kpi/vmkit.h
include/barrelfish_kpi/vmx_controls.h [new file with mode: 0644]
include/barrelfish_kpi/vmx_encodings.h [new file with mode: 0644]
include/barrelfish_kpi/vmx_exit_reasons.h [new file with mode: 0644]
include/net_queue_manager/net_queue_manager.h
include/pci/devids.h
include/poll.h [new file with mode: 0644]
include/signal.h
include/storage/storage.h [new file with mode: 0644]
include/storage/vsa.h [new file with mode: 0644]
include/storage/vsic.h [new file with mode: 0644]
include/sys/epoll.h
include/sys/poll.h [new file with mode: 0644]
include/sys/utsname.h [new file with mode: 0644]
include/target/x86_64/barrelfish_kpi/paging_target.h
include/tenaciousd/log.h [new file with mode: 0644]
include/tenaciousd/queue.h [new file with mode: 0644]
include/time.h
kernel/Hakefile
kernel/arch/x86_64/startup_arch.c
kernel/arch/x86_64/svm_vmkit.c [new file with mode: 0644]
kernel/arch/x86_64/syscall.c
kernel/arch/x86_64/vmkit.c
kernel/arch/x86_64/vmx_checks.c [new file with mode: 0644]
kernel/arch/x86_64/vmx_vmkit.c [new file with mode: 0644]
kernel/dispatch.c
kernel/include/arch/x86_64/svm_vmkit.h [new file with mode: 0644]
kernel/include/arch/x86_64/vmkit.h
kernel/include/arch/x86_64/vmx_checks.h [new file with mode: 0644]
kernel/include/arch/x86_64/vmx_vmkit.h [new file with mode: 0644]
kernel/include/target/x86_64/paging_kernel_target.h
lib/acpi_client/acpi_client.c
lib/ahci/Hakefile
lib/ahci/storage_vsic.c [new file with mode: 0644]
lib/arranet/Hakefile
lib/arranet/arranet.c
lib/barrelfish/capabilities.c
lib/barrelfish/debug.c
lib/barrelfish/domain.c
lib/bench/arch/arm/bench_arch.c
lib/bomp/backends/xomp_worker.c
lib/bulk_transfer/backends/net/bulk_net_e10k.c
lib/net_queue_manager/QM_benchmark.h
lib/net_queue_manager/net_soft_filters_srv_impl.c
lib/newlib/newlib/libc/sys/barrelfish/syscalls.c
lib/posixcompat/Hakefile
lib/posixcompat/epoll.c
lib/posixcompat/fsync.c
lib/posixcompat/poll.c [new file with mode: 0644]
lib/posixcompat/pthreads.c
lib/posixcompat/select.c
lib/posixcompat/sleep.c
lib/posixcompat/sockets.c
lib/posixcompat/syslog.c [new file with mode: 0644]
lib/posixcompat/uname.c [new file with mode: 0644]
lib/posixcompat/wait.c
lib/storage/Hakefile [new file with mode: 0644]
lib/storage/storage.c [new file with mode: 0644]
lib/storage/vsa.c [new file with mode: 0644]
lib/tenaciousd/Hakefile [new file with mode: 0644]
lib/tenaciousd/Makefile [new file with mode: 0644]
lib/tenaciousd/README [new file with mode: 0644]
lib/tenaciousd/aio_vsic.c [new file with mode: 0644]
lib/tenaciousd/build.sh [new file with mode: 0644]
lib/tenaciousd/log.c [new file with mode: 0644]
lib/tenaciousd/queue.c [new file with mode: 0644]
lib/tenaciousd/ram_vsic.c [new file with mode: 0644]
lib/vfs/Hakefile
lib/vfs/vfs.c
lib/vfs/vfs_blockdevfs.c
lib/vfs/vfs_blockdevfs.h
lib/vfs/vfs_blockdevfs_megaraid.c [new file with mode: 0644]
tools/arranet_e10k-cc-wrapper [new file with mode: 0644]
tools/arranet_qemu-cc-wrapper [new file with mode: 0644]
tools/binutils-2.24-barrelfish.patch [new file with mode: 0644]
tools/debugsim.sh [changed mode: 0644->0755]
tools/gcc-4.8.2-barrelfish.patch [new file with mode: 0644]
tools/harness/barrelfish.py
tools/harness/machines/__init__.py
tools/harness/machines/uw.py
tools/harness/machines/uw_machinedata.py
tools/harness/siteconfig/uw.py
tools/harness/tests/vmkit.py
usr/acpi/Hakefile
usr/acpi/README_VTD [new file with mode: 0644]
usr/acpi/acpi.c
usr/acpi/acpi_main.c
usr/acpi/acpi_service.c
usr/acpi/acpi_shared.h
usr/acpi/acpica/include/actbl2.h
usr/acpi/intel_vtd.c [new file with mode: 0644]
usr/acpi/intel_vtd.h [new file with mode: 0644]
usr/acpi/vtd_debug.h [new file with mode: 0644]
usr/acpi/vtd_domains.h [new file with mode: 0644]
usr/acpi/vtd_sl_paging.h [new file with mode: 0644]
usr/arrakismon/guest.c
usr/arrakismon/guest.h
usr/bench/tenaciousd_bench/Hakefile [new file with mode: 0644]
usr/bench/tenaciousd_bench/tenaciousd_bench.c [new file with mode: 0644]
usr/bench/udp_echo/Makefile
usr/bench/udp_echo/run_multiloop.sh [changed mode: 0644->0755]
usr/bench/udp_echo/udp_echo.c
usr/bench/udp_echo/udp_ipip_openloop.c [new file with mode: 0644]
usr/bench/udp_echo/udp_openloop.c
usr/drivers/e1000/e1000n_hwinit.c
usr/drivers/e10k/Hakefile
usr/drivers/e10k/e10k_cdriver.c
usr/drivers/e10k/e10k_qdriver.c
usr/drivers/e10k/e10k_vf.c
usr/drivers/megaraid/Hakefile [new file with mode: 0644]
usr/drivers/megaraid/Makefile [new file with mode: 0644]
usr/drivers/megaraid/linux_defs.h [new file with mode: 0644]
usr/drivers/megaraid/main.c [new file with mode: 0644]
usr/drivers/megaraid/megaraid.c [new file with mode: 0644]
usr/drivers/megaraid/megaraid.h [new file with mode: 0644]
usr/drivers/megaraid/megaraid_vsic.c [new file with mode: 0644]
usr/drivers/megaraid/queue.h [new file with mode: 0644]
usr/drivers/megaraid/vsic_vfs.c [new file with mode: 0644]
usr/pci/pci.c
usr/pci/pci_service.c
usr/pci/pcimain.c
usr/skb/programs/bridge_bios.pl
usr/skb/programs/bridge_fake_bigfish.pl
usr/skb/programs/pci_queries.pl
usr/tests/e10ktest/Hakefile
usr/tests/e10ktest/e10k_ctrl.c
usr/tests/e10ktest/e10ktest.c
usr/tests/e10ktest/e10ktest_latencies.c
usr/tests/e10ktest/subways.c [new file with mode: 0644]
usr/vmkitmon/README
usr/vmkitmon/README_VMX [new file with mode: 0644]
usr/vmkitmon/guest.c
usr/vmkitmon/guest.h
usr/vmkitmon/lpc.c
usr/vmkitmon/lpc.h
usr/vmkitmon/realmode.c
usr/vmkitmon/vmx.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index b6a651b..4049672 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -9,6 +9,7 @@ Justin Cappos <justin@cs.arizona.edu>
 Zaheer Chothia <zchothia@inf.ethz.ch>
 Andreas Dillier <dilliera@ethz.ch>
 Pierre-Evariste Dagand <pedagand@gmail.com>
+Oleg Godunok <ogodunok@gmail.com>
 Raphael Fuchs <fuchs.raphael@gmail.com>
 Simon Gerber <simon.gerber@inf.ethz.ch>
 David Gerhard <gerhardd@student.ethz.ch>
diff --git a/README b/README
index 05bc2d7..d3eadb1 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
 ##########################################################################
-Copyright (c) 2009-2013, ETH Zurich.
+Copyright (c) 2009-2014, ETH Zurich.
 All rights reserved.
 
 This file is distributed under the terms in the attached LICENSE file.
@@ -121,7 +121,6 @@ run ``make rehake`` to apply them.
 
     $ make sim
 
-
 Installing and Booting
 --------------------------------
 
@@ -233,7 +232,7 @@ A: http://www.barrelfish.org/
    http://wiki.barrelfish.org/
 
 Q: Can I contribute?
-A: We'd certainly like to hear from you. Feel free to send pateches (or even
+A: We'd certainly like to hear from you. Feel free to send patches (or even
    git merge requests) to the Barrelfish mailing list.
 
    To keep track of contributions to Barrelfish, we use a sign-off procedure
diff --git a/README_ARRAKIS b/README_ARRAKIS
new file mode 100644 (file)
index 0000000..aa470c5
--- /dev/null
@@ -0,0 +1,98 @@
+##########################################################################
+Copyright (c) 2013-2014, University of Washington.
+All rights reserved.
+
+This file is distributed under the terms in the attached LICENSE file.
+If you do not find this file, copies can be found by writing to:
+ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+##########################################################################
+
+Arrakis README Supplement
+--------------------------------
+
+This version of Arrakis is a fork of Barrelfish release
+2014-03-11. Arrakis contains many additions and fixes to the vanilla
+Barrelfish tree, notably:
+
+ * Boot directly via QEMU Multiboot support, instead of GRUB
+ * Arrakis domains: These run in guest ring 0, hardware-virtualized
+ * Parallel hake
+ * SR-IOV support
+ * Fixes to PCI bus enumeration
+ * Can use BIOS preset values to configure PCI (like Linux)
+ * Driver for 82599 virtual function
+ * More POSIX support, in particular pthreads, epoll, and sockets
+ * Intel performance monitoring counters support
+ * Arranet, the Arrakis network stack
+ * Support for advanced 82599 features, like weighted round-robin
+   scheduling and rate limiting
+ * TenaciousD, a persistent data structure library
+ * libstorage, a storage HAL
+ * Intel MegaRAID device driver
+ * Intel VT-d (IOMMU) driver
+
+Arrakis likely also contains bugs not present in Barrelfish. In some
+cases, there is likely to be some debug code left in this release,
+which might impact your experience. Don't despair! Just comment out
+suspicious-looking code and see if it makes Arrakis work for
+you. Unfortunately, we do not have the man or machine power to test
+Arrakis as extensively as the Barrelfish releases.
+
+We make an effort to back-port our changes to Barrelfish periodically,
+by which time they will have stabilized and tested on the broad range
+of machines that Barrelfish is usually expected to run on.
+
+.. _Arrakis: http://arrakis.cs.washington.edu/
+
+Supported PC hardware
+--------------------------------
+
+Arrakis has been tested on the following PC hardware:
+
+ * Dell PowerEdge R520 servers in x86-64 mode. Our server consists of
+   a 6-core Intel Xeon E5-2430 (Sandy Bridge) system at 2.2 GHz clock
+   frequency with 4GB of RAM. The tested peripherals are:
+
+   - Intel X520 dual-port 10Gb Ethernet adapter
+   - Intel MegaRAID RS3DC040 RAID controller
+
+Required Tools
+--------------------------------
+
+In addition to the tools required by Barrelfish, Arrakis requires the following:
+
+ * GHC Control.Parallel.Strategies library
+
+Building
+--------------------------------
+
+The build process (including required tools) is unchanged from
+Barrelfish. Please refer to the README file for instructions.
+
+Installing and Booting
+--------------------------------
+
+Installation and booting is also unchanged from Barrelfish and
+explained in the README file.
+
+A number of commandline options to system daemons and device drivers
+have been added:
+
+ * pci now supports an "skb_bridge_program=" option, to set which SKB
+   program to use to configure PCI bridges. "bridge_bios" will use the
+   BIOS preset values and might be preferable on some systems.
+
+ * pci now supports the "numvfs=" option to set the number of virtual
+   functions to configure (for every device that supports them).
+
+ * VT-d related commandline options have been added and are explained
+   in usr/acpi/README_VTD.
+
+ * The 82599 physical function driver supports a range of options to
+   configure advanced NIC features. "tx_rate[x]=y" is used to limit
+   the transmit rate of virtual function x to y
+   Mbps. credit_refill[x]=y" is used to set the number of credits for
+   weighted round-robin scheduling of queue x to y.
+
+ * The 82599 virtual function driver accepts an option "vf=x" to
+   configure the virtual function number to use.
index 4908375..8b42744 100644 (file)
            "xeon_phi/xeon_phi_dma_chan",
            "ioat_dma",
            "ioat_dma_chan",
-           "pci_sr_iov_cap"
+           "pci_sr_iov_cap",
+           "megaraid",
+          "vtd",
+          "vtd_iotlb"
          ], arch <- allArchitectures
 ] ++
 
index 51a44d3..46d13c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, ETH Zurich. All rights reserved.
+ * Copyright (c) 2013, University of Washington. All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
index 152ac4c..7e7d632 100644 (file)
@@ -87,6 +87,65 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
        _               48;
     };
 
+    register vmx_basic ro msr(0x480) "Basic VMX Capabilities" {
+        vmcs_rev_id    31 "VMCS Revision Identifier";
+       _              1 mbz;
+       region_size    13 "Bytes that should be allocated for VMXON and VMCS regions";
+       _              3;
+       paddr_width    1 "Physical address width Limited to 32 Bits";   
+       dual_mon       1 "Dual-monitor treatment supported";
+       mem_type       4 "Memory tpe used to access VMCS with VMREAD/VMWRITE";
+       instr_info_io  1 "INS/OUTS info is reported in VM-exit instruction-information";
+       ctls_clear     1 "Controls that default to 1 may be cleared to 0";
+       _              8;
+    };
+
+    // Capability Reporting Registers for VMX Controls
+    register vmx_pinbased_ctls ro msr(0x481) "Pin-based Controls" type(uint64);     
+    register vmx_ppbased_ctls ro msr(0x482) "Primary Processor-based Controls" type(uint64);
+    register vmx_exit_ctls ro msr(0x483) "VM-exit Controls" type(uint64);
+    register vmx_entry_ctls ro msr(0x484) "VM-entry Controls" type(uint64);
+    register vmx_spbased_ctls ro msr(0x48b) "Secondary Processor-based Controls" type(uint64);
+     
+    // Capability Reporting Registers for VMX Flex Controls
+    register vmx_true_pinbased_ctls ro msr(0x48d) "Pin-based Flex Controls" type(uint64);
+    register vmx_true_ppbased_ctls ro msr(0x48e) "Primary Processor-based Flex Controls" type(uint64);
+    register vmx_true_exit_ctls ro msr(0x48f) "VM-exit Flex Controls" type(uint64);
+    register vmx_true_entry_ctls ro msr(0x490) "VM-entry Flex Controls" type(uint64);
+
+    // Capability Reporting Registers of CR0 and CR4 bits
+    register vmx_cr0_fixed0 ro msr(0x486) "CR0 Bits Fixed to 0" type(uint64);
+    register vmx_cr0_fixed1 ro msr(0x487) "CR0 Bits Fixed to 1" type(uint64);
+    register vmx_cr4_fixed0 ro msr(0x488) "CR4 Bits Fixed to 0" type(uint64);
+    register vmx_cr4_fixed1 ro msr(0x489) "CR4 Bits Fixed to 1" type(uint64);
+
+    register vmx_ept_vpid ro msr(0x48c) "EPT and VPID Capabilities" {
+        eot            1 "Support execute-only translation";
+       _              5;
+       pwl4           1 "Support page-walk length of 4";
+       _              1;
+       ucmt           1 "Support uncacheable memory type";
+       _              5;
+       wbmt           1 "Support write-back memory type";
+       _              1;
+       ps21           1 "Support EPT PDE mapping to 2MB page";
+       ps30           1 "Support EPT PDE mapping to 1GB page";
+       _              2;
+       invept_instr   1 "Support the instruction INVEPT";
+       ept_adf        1 "Support EPT accessed and dirty flags";
+       _              3;
+       invept_sct     1 "Support single-context INVEPT type";
+       invept_act     1 "Support all-context INVEPT type";
+       _              5;
+       invvpid_instr  1 "Support the instruction INVVPID";
+       _              7;
+       invvpid_iat    1 "Support individual-address INVVPID type";
+       invvpid_sct    1 "Support single-context INVVPID type";
+       invvpid_act    1 "Support all-context INVVPID type";
+       invvpid_scrgt  1 "Support single-context-retaining-globals INVVPID type";
+       _              20; 
+    };        
+
     register bios_updt_trig rw msr(0x79) "BIOS update trigger" type(uint64);
     register bios_sign_id rw msr(0x8b) "BIOS update signature" type(uint64);
     register smm_monitor_ctl rw msr(0x9b) "SMM Monitor config" type(uint64);
@@ -342,6 +401,9 @@ device ia32 lsbfirst () "ia32 / Intel64 core architecture" {
     register lstar msr(0xc0000082) "Long mode Syscall target address" 
        type(uint64);
 
+    register cstar msr(0xc0000083) "Compatibility mode Syscall target address"
+        type(uint64);  
+
     register fmask msr(0xc0000084) "SYSCALL EFLAGS mask" {
        v       32 "Value";
        _       32;
diff --git a/devices/megaraid.dev b/devices/megaraid.dev
new file mode 100644 (file)
index 0000000..8879d89
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, University of Washington. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * megaraid.dev
+ *
+ * DESCRIPTION: LSI MegaRAID Controller
+ *
+ * From the FreeBSD driver.
+ */
+
+device megaraid msbfirst ( addr base ) "LSI MegaRAID Controller" {
+       register doorbell rw addr(base, 0x0) "Doorbell" type(uint32);
+       register fusion_seq_offset rw addr(base, 0x4) "Fusion SEQ Offset" type (uint32);
+       register fusion_host_diag rw addr(base, 0x8) "Fusion Host Diag" type (uint32);
+
+       register inbound_msg_0 rw addr(base, 0x10) "Inbound msg 0" type (uint32);
+       register inbound_msg_1 rw addr(base, 0x14) "Inbound msg 0" type (uint32);
+       register outbound_msg_0 rw addr(base, 0x18) "Outbound msg 0" type (uint32);
+       register outbound_msg_1 rw addr(base, 0x1c) "Outbound msg 1" type (uint32);
+
+       register inbound_doorbell rw addr(base, 0x20) "Inbound doorbell" type (uint32);
+       register inbound_intr_status rw addr(base, 0x24) "Inbound interrupt status" type (uint32);
+       register inbound_intr_mask rw addr(base, 0x28) "Inbound interrupt mask" type (uint32);
+       register outbound_doorbell rw addr(base, 0x2c) "Outbound doorbell" type (uint32);
+       register outbound_intr_status rw addr(base, 0x30) "Outbound interrupt status" type (uint32);
+       register outbound_intr_mask rw addr(base, 0x34) "Outbound interrupt mask" type (uint32);
+
+       register inbound_queue_port rw addr(base, 0x40) "Inbound queue port" type (uint32);
+       register outbound_queue_port rw addr(base, 0x44) "Outbound queue port" type (uint32);
+
+       register reply_post_host_index rw addr(base, 0x6c) "Reply post host index" type (uint32);
+
+       register outbound_doorbell_clear rw addr(base, 0xa0) "Outbound doorbell clear" type (uint32);
+
+       constants state "Controller state" {
+         state_undefined          = 0x0  "Undefined";
+        state_bb_init             = 0x1  "BB Init";
+        state_fw_init             = 0x4  "FW Init";
+        state_wait_handshake      = 0x6  "Wait handshake";
+        state_fw_init_2           = 0x7  "FW Init 2";
+        state_device_scane        = 0x8  "Device scan";
+        state_boot_msg_pending    = 0x9  "Boot message pending";
+        state_flush_cache         = 0xa  "Flush cache";
+        state_ready               = 0xb  "Ready";
+        state_operational         = 0xc  "Operational";
+        state_fault               = 0xf  "Fault";
+       };
+
+       register status ro addr(base, 0xb0) "Device status" {
+         state      4  type(state) "Controller status";
+        _           4;
+        sge         8;
+        max_cmds    16 "Max. # of commands";
+       };
+
+       register outbound_scratch_pad_2 rw addr(base, 0xb4) "Outbound scratch pad #2" type (uint32);
+
+       register inbound_low_queue_port rw addr(base, 0xc0) "Inbound low queue port" type (uint32);
+       register inbound_high_queue_port rw addr(base, 0xc4) "Inbound high queue port" type (uint32);
+};
index 144044d..f003420 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, ETH Zurich. All rights reserved.
+ * Copyright (c) 2013, University of Washington. All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
  * If you do not find this file, copies can be found by writing to:
diff --git a/devices/vtd.dev b/devices/vtd.dev
new file mode 100644 (file)
index 0000000..aea8ced
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+device vtd msbfirst ( addr base ) "VT-d" {
+       //////////////////////////// Translation Structure Formats ////////////////////////////
+
+       datatype root_entry "Root Entry" {
+           _   64 mbz;
+           ctp 52      "Context-table Pointer";
+           _   11 mbz;
+           p   1       "Present";
+       };
+
+       constants translation_type "Translation Type for requests-without-PASID" {
+           hmd = 0b00 "Host mode with Device-TLBs disabled";
+           hme = 0b01 "Host mode with Device-TLBs enabled";
+           ptm = 0b10 "Pass-through mode";
+           //0b011: reserved
+       };
+       
+       constants addr_width "Address Width" {
+           agaw30 = 0b000 "30-bit AGAW (2-level page table)";
+           agaw39 = 0b001 "39-bit AGAW (3-level page table)";
+           agaw48 = 0b010 "48-bit AGAW (4-level page table)";
+           agaw57 = 0b011 "57-bit AGAW (5-level page table)";
+           agaw64 = 0b100 "64-bit AGAW (6-level page table)";
+            // 0b101-0b111 are reserved
+       };
+       
+       // Context-entries have the same DID iff their SLPTPTR values are the same.
+       datatype context_entry "Context Entry" {
+           _       40 mbz;
+           did     16                       "Domain Identifier";
+           _       1 mbz;
+           _       4;
+           aw      3 type(addr_width)       "Address Width";
+           slptptr 52                       "Second Level Page Translation Pointer";
+           _       8 mbz;
+           t       2 type(translation_type) "Translation Type";
+           fpd     1                        "Fault Processing Disable";
+           p       1                        "Present";
+       };
+
+       //////////////////////////// Remapping Registers ////////////////////////////
+
+       register VER addr(base, 0x000) "Version Register" {
+           _   24 mbz;
+           max 4  ro   "Major Version number";
+           min 4  ro   "Minor Version number";
+       };
+
+
+       constants numdom "Number of domains supported" {
+           nd4  = 0b000 "Hardware supports 4-bit (16 domains)";
+           nd6  = 0b001 "Hardware supports 6-bit (64 domains)"; 
+           nd8  = 0b010 "Hardware supports 8-bit (256 domains)";
+           nd10 = 0b011 "Hardware supports 10-bit (1024 domains)";
+           nd12 = 0b100 "Hardware supports 12-bit (4096 domains)";
+            nd14 = 0b101 "Hardware supports 14-bit (16384 domains)";
+           nd16 = 0b110 "Hardware supports 16-bit (65536 domains)";
+           // 0b111 reserved
+       };
+
+       register CAP addr(base, 0x008) "Capability Register" {
+           _       7               mbz;
+           fl1gp   1               ro   "First Level 1-GByte Page Support";
+           drd     1               ro   "Read Draining";
+           dwd     1               ro   "Write Draining";
+           mamv    6               ro   "Maximum Address Mask Value";
+           nfr     8               ro   "Number of Fault-recording Registers";
+           psi     1               ro   "Page Selective Invalidation";
+           _       1               mbz;
+            _       2              mbz  "Second Level Large Page Support - Reserved";
+            sllps30 1                      ro   "Second Level Large Page Support - 1GB page size (30-bit offset to page frame)";
+           sllps21 1               ro   "Second Level Large Page Support - 2MB page size (21-bit offset to page frame)";
+           fro     10              ro   "Fault-recording Register offset";
+           _       1               rsvd;
+           zlr     1               ro   "Zero Length Read";
+           mgaw    6               ro   "Maximum Guest Address Width";
+           _       3               mbz;
+            _       2              mbz  "Supported Adjusted Guest Address Widths - reserved";
+           sagaw48 1               ro   "Supported Adjusted Guest Address Widths - 48-bit AGAW (4-level page-table)";
+                   sagaw39 1               ro   "Supported Adjusted Guest Address Widths - 39-bit AGAW (3-level page-table)";
+                   _       1               mbz  "Supported Adjusted Guest Address Widths - reserved";
+           cm      1               ro   "Caching Mode";
+           phmr    1               ro   "Protected High-Memory Region";
+           plmr    1               ro   "Protected Low-Memory Region";
+           rwbf    1               ro   "Required Write-Buffer Flushing";
+           afl     1               ro   "Advanced Fault Logging";
+           nd      3  ro type(numdom)    "Number of domains supported";
+       };      
+
+       register ECAP addr(base, 0x010) "Extended Capability Register" {
+           _     24 mbz;
+           pss   5  ro    "PASID Size Supported";
+           eafs  1  ro    "Extended Accessed Flag Support";
+           nwfs  1  ro    "No Write Flag Support";
+           pot   1  ro    "PASID-Only Translations";
+           srs   1  ro    "Supervisor Request Support";
+           ers   1  ro    "Execute Request Support";
+           prs   1  ro    "Page Request Support";
+           pasid 1  ro    "Process Address Space ID Support";
+           dis   1  ro    "Deferred Invalidate Support";
+           nest  1  ro    "Nested Translation Support";
+           mts   1  ro    "Memory Type Support";
+           ecs   1  ro    "Extended Context Support";
+           mhmv  4  ro    "Maximum Handle Mask Value";
+           _     2  mbz;
+           iro   10 ro    "IOTLB Register Offset";
+           sc    1  ro    "Snoop Control";
+           pt    1  ro    "Pass Through";
+           _     1  rsvd;
+           eim   1  ro    "Extended Interrupt Mode";
+           ir    1  ro    "Interrupt Remapping support";
+           dt    1  ro    "Device-TLB support";
+           qis   1  ro    "Queued Invalidation support";
+           pwc   1  ro    "Page-walk Coherency";
+       };
+
+       register GCMD addr(base, 0x018) "Global Command Register" {
+           te    1  wo   "Translation Enable";
+           srtp  1  wo   "Set Root Table Pointer";
+           sfl   1  wo   "Set Fault Log";
+           eafl  1  wo   "Enable Advanced Fault Logging";
+           wbf   1  wo   "Write Buffer Flush";
+           qie   1  wo   "Queued Invalidation Enable";
+           ire   1  wo   "Interrupt Remapping Enable";
+           sirtp 1  wo   "Set Interrupt Remap Table Pointer";
+           cfi   1  wo   "Compatibility Format Interrupt";
+           _     23 mbz;
+       };
+
+       register GSTS addr(base, 0x01C) "Global Status Register" {
+           tes   1  ro   "Translation Enable Status";
+           rtps  1  ro   "Root Table Pointer Status";
+           fls   1  ro   "Fault Log Status";
+           afls  1  ro   "Advanced Fault Logging Status";
+           wbfs  1  ro   "Write Buffer Flash Status";
+           qies  1  ro   "Queued Invalidation Enable Status";
+           ires  1  ro   "Interrupt Remapping Enable Status";
+           irtps 1  ro   "Interrupt Remaping Table Pointer Status";
+           cfis  1  ro   "Compatibility Format Interrupt Status";
+           _     23 mbz;
+       };
+       
+        constants rtt_ "Root Table Type" {
+           rt  = 0x0 "Root Table"; 
+           ert = 0x1 "Extended Root Table";
+       };
+
+       register RTADDR addr(base, 0x020) "Root Table Address Register" {
+           rta 52 rw   "Root Table Address";
+           rtt 1  rw   "Root Table Type";
+           _   11 mbz;
+               
+       };
+
+        constants cirg_ "Context Invalidation Request Granularity" {
+           rsvd_ir = 0b00 "Reserved";
+           gir     = 0b01 "Global Invalidation request";
+           domir   = 0b10 "Domain-selective invalidation request";
+           devir   = 0b11 "Device-selective invalidation request";
+       };
+
+       constants caig_ "Context Actual Request Granularity" {
+           rsvd_ip = 0b00 "Reserved";
+           gip     = 0b01 "Global Invalidation performed";
+           domip   = 0b10 "Domain-selective invalidation performed";
+           devip   = 0b11 "Device-selective invalidation performed";
+       };
+
+       constants functmask "Function Mask" {
+           nomask  = 0b00 "No bits in the SID field masked";
+           mask2   = 0b01 "Mask bit 2 in the SID field";
+           mask12  = 0b10 "Mask bits 2:1 in the SID field";
+           mask012 = 0b11 "Mask bits 2:0 in the SID field";
+       };
+
+       register CCMD addr(base, 0x028) "Context Command Register" {
+           icc  1                   rw   "Invalidate Context-Cache";
+           cirg 2   rw type(cirg_)       "Context Invalidation Request Granularity";
+           caig 2   ro type(caig_)       "Context Actual Invalidation Granularity";
+           _    25                  mbz;
+           fm   2   wo type(functmask)   "Function Mask";
+           sid  16                  wo   "Source-ID";
+           did  16                  rw   "Domain-ID";
+       };
+};
diff --git a/devices/vtd_iotlb.dev b/devices/vtd_iotlb.dev
new file mode 100644 (file)
index 0000000..9e5302e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+device vtd_iotlb msbfirst ( addr base ) "VT-d IOTLB Registers" { 
+       register iva_reg addr(base, 0x000) "Invalidate Address Register" {
+           addr        52 wo   "Address";
+          _    5  mbz; 
+          ih   1  wo   "Invalidation Hint";
+          am   6  wo   "Address Mask";
+       };
+
+       constants iirg_ "IOTLB Invalidation Request Granularity" {
+            rsvd_ir = 0b00 "Reserved";
+            gir     = 0b01 "Global Invalidation request";
+            domir   = 0b10 "Domain-selective invalidation request";
+            pir     = 0b11 "Page-selective-within-domain invalidation request";
+        };
+
+        constants iaig_ "IOTLB Actual Request Granularity" {
+            rsvd_ip = 0b00 "Reserved";
+            gip     = 0b01 "Global Invalidation performed";
+            domip   = 0b10 "Domain-selective invalidation performed";
+            devip   = 0b11 "Device-selective invalidation performed";
+        };
+
+       register iotlb_reg addr(base, 0x008) "IOTLB Invalidate Register" {
+           ivt  1  rw               "Invalidate IOTLB";
+           _    1  mbz;        
+           iirg 2  rw   type(iirg_) "IOTLB Invalidation Request Granularity";
+           _    1  mbz;
+           iaig 2  ro   type(iaig_) "IOTLB Actual Invalidation Granularity";
+           _    7  mbz;
+           dr   1  rw               "Drain Reads";
+           dw   1  rw               "Drain Writes";
+           did  16 rw               "Domain-ID";
+           _    32 mbz;
+       };
+};
index 82c08fc..e792e7a 100755 (executable)
@@ -122,6 +122,8 @@ errors kernel SYS_ERR_ {
     failure VMKIT_CTRL_INVALID          "Invalid frame capability passed for control structure",
     failure VMKIT_ENDPOINT              "Error setting monitor endpoint for dispatcher",
     failure VMKIT_ENDPOINT_INVALID      "Invalid monitor endpoint capability passed",
+    failure VMKIT_VMX_VMFAIL_INVALID   "The VMCS pointer is invalid", 
+    failure VMKIT_VMX_VMFAIL_VALID      "VMX instruction failed (VM-instruction error field = ErrorNumber)",
 
     // Serial port errors
     failure SERIAL_PORT_INVALID         "Invalid serial port",
@@ -795,6 +797,15 @@ errors acpi ACPI_ERR_ {
     failure NO_MADT_TABLE       "No APIC found in ACPI.",
 };
 
+errors vtd VTD_ERR_ {
+    failure INVALID_CAP     "Cap is not for a x86-64 PML4 VNode",
+    failure DOM_NOT_FOUND   "Domain for cap was not found",
+    failure DEV_NOT_FOUND   "Device does not belong to the domain",
+    failure DEV_USED        "The device is currently used by another domain",
+    failure FULL            "No more domains can be created",
+    failure NO_UNITS       "Hardware doesn't contain any VT-d hardware units",
+};
+
 // errors in the SKB
 errors skb SKB_ERR_ {
     failure CONVERSION_ERROR    "Conversion (parsing) of the result failed.",
@@ -941,7 +952,6 @@ errors kaluga  KALUGA_ERR_ {
 
 };
 
-
 // errors generated by THC
 errors thc THC_ {
     failure CANCELED            "Operation canceled",
index 80c3dd5..ef20408 100644 (file)
@@ -199,8 +199,8 @@ memserv_percore = False
 -- Lazy THC implementation (requires use_fp = True)
 lazy_thc :: Bool
 lazy_thc | elem "armv7" architectures   = False
-        | elem "armv5" architectures   = False
-        | elem "xscale" architectures  = False
+     | elem "armv5" architectures   = False
+     | elem "xscale" architectures  = False
          | otherwise                    = True
 
 -- Enable capability tracing debug facility
@@ -266,6 +266,16 @@ nxe_paging = False
 oneshot_timer :: Bool
 oneshot_timer = False
 
+-- Enable hardware VM support for AMD's Secure Virtual Machine (SVM)
+-- If disabled, Intel's VMX hardware is supported instead
+config_svm :: Bool
+config_svm = True
+
+-- Enable the use of only Arrakis domains (with arrakismon)
+-- If disabled, use normal VM-guests (with vmkitmon)
+config_arrakismon :: Bool
+config_arrakismon = True
+
 defines :: [RuleToken]
 defines = [ Str ("-D" ++ d) | d <- [  
              if microbenchmarks then "CONFIG_MICROBENCHMARKS" else "",
@@ -312,6 +322,8 @@ defines = [ Str ("-D" ++ d) | d <- [
              if nxe_paging then "CONFIG_NXE" else "",
              if libc == "oldc" then "CONFIG_OLDC" else "CONFIG_NEWLIB",
              if oneshot_timer then "CONFIG_ONESHOT_TIMER" else "",
+             if config_svm then "CONFIG_SVM" else "",
+             if config_arrakismon then "CONFIG_ARRAKISMON" else "",
              if use_kaluga_dvm then "USE_KALUGA_DVM" else "",
              if heteropanda then "HETEROPANDA" else "",
              if caps_trace then "TRACE_PMEM_CAPS" else ""
old mode 100644 (file)
new mode 100755 (executable)
index c745e5c..d8622cf
@@ -26,6 +26,7 @@ import Data.Dynamic
 import Data.Maybe
 import Data.List
 import Control.Monad
+import Control.Parallel.Strategies
 
 import RuleDefs
 import HakeTypes
@@ -211,7 +212,7 @@ resolveRelativePathName' d a f root =
 --
 makeDirectories :: [(String, HRule)] -> String
 makeDirectories r = 
-    let alldirs = makeDirs1 (Rules [ rl | (f,rl) <- r ])
+    let alldirs = makeDirs1 (Rules [ rl | (f,rl) <- r ]) `using` parListChunk 200 rdeepseq
         marker d = d ./. ".marker"
     in unlines ([ "# Directories follow" ] ++
                 [ "hake_dirs: " ++ (marker d) ++ "\n\n" ++
@@ -265,7 +266,7 @@ allowedArchs = all (\a -> a `elem` (Config.architectures ++ specialArchitectures
 --
 makeMakefile :: [(String, HRule)] -> String
 makeMakefile r = 
-  unlines $ intersperse "" [makeMakefileSection f rl | (f,rl) <- r]
+  unlines $ intersperse "" ([makeMakefileSection f rl | (f,rl) <- r] `using` parList rdeepseq)
 
 makeMakefileSection :: String -> HRule -> String
 makeMakefileSection fname rules = 
index 113b78d..b7a84fe 100644 (file)
@@ -1124,7 +1124,7 @@ vfsdeps :: [VFSModules] -> [LibDepTree]
 vfsdeps []                  = [LibDep "vfs"]
 vfsdeps (VFS_RamFS:xs)      = [] ++ vfsdeps xs
 vfsdeps (VFS_NFS:xs)        = [libnfs_deps] ++ vfsdeps xs
-vfsdeps (VFS_BlockdevFS:xs) = [LibDep "ahci" ] ++ vfsdeps xs
+vfsdeps (VFS_BlockdevFS:xs) = [LibDep "ahci", LibDep "megaraid"] ++ vfsdeps xs
 vfsdeps (VFS_FAT:xs)        = [] ++ vfsdeps xs
 
 libvfs_deps_all        = LibDeps $ vfsdeps [VFS_NFS, VFS_RamFS, VFS_BlockdevFS,
@@ -1164,6 +1164,7 @@ libDeps xs = [x | (LibDep x) <- (sortBy xcmp) . nub . flat $ map str2dep xs ]
                   , "term_server"
                   , "vfs"
                   , "ahci"
+                 , "megaraid"
                   , "nfs"
                   , "net_queue_manager"
                   , "bfdmuxvm"
index 3f1c589..c060e9e 100644 (file)
@@ -240,7 +240,9 @@ MODULES_x86_64= \
        sbin/block_server_client \
        sbin/bs_user \
        sbin/bulk_shm \
-       sbin/corectrl
+       sbin/corectrl \
+       sbin/megaraid \
+       lib/libmegaraid.a
 
 MODULES_k1om= \
        sbin/weever \
index 069a8b4..b43c90b 100644 (file)
@@ -85,7 +85,8 @@
                "arrakis",
                "e10k_vf",
                "flounderbootstrap",
-               "empty"
+               "empty",
+              "subways"
            ],
              arch <- allArchitectures
 ] ++
index a1b61a0..57b2cd5 100644 (file)
@@ -42,6 +42,16 @@ interface acpi "acpi RPC Interface" {
     // Kludge: retrieve frame cap to VBE BIOS;
     rpc get_vbe_bios_cap(out errval err, out cap cap, out uint32 size);
 
+    rpc create_domain(in cap pml4, out errval err);
+
+    rpc delete_domain(in cap pml4, out errval err);
+
+    rpc vtd_add_device(in uint32 seg, in uint32 bus, in uint32 dev, in uint32 funct, in cap pml4, out errval err);
+
+    rpc vtd_remove_device(in uint32 seg, in uint32 bus, in uint32 dev, in uint32 funct, in cap pml4, out errval err);
+
+    rpc vtd_id_dom_add_devices(out errval err);
+    
     // More Kludge; cap retrieval for pci
     // We need a designated service to maintain the physical address
     // space caps (to avoid sibling errors).
index bf7fc01..0c39156 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
+ * Copyright (c) 2013, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
index afda4ca..e767c76 100644 (file)
@@ -30,7 +30,10 @@ interface e10k "e10k queue management interface" {
                                int16  msix_intvec,
                                uint8  msix_intdest,
                                bool   use_irq,
-                               bool   use_rsc);
+                               bool   use_rsc,
+                              uint64 tx_va,
+                              uint64 rx_va,
+                              uint64 txhwb_va);
     response queue_memory_registered();
 
     /* Modify interrupt rate for a particular queue */
index f774eb7..a4d046c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011, 2013, ETH Zurich.
+ * Copyright (c) 2013, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
diff --git a/if/subways.if b/if/subways.if
new file mode 100644 (file)
index 0000000..8085b09
--- /dev/null
@@ -0,0 +1,18 @@
+/** \file
+ *  \brief Subways interface
+ */
+
+/*
+ * Copyright (c) 2012, 2014, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+interface subways "Subways interface" {
+       message startup(cap packets);
+       message send(genvaddr offset, uint32 len, uint64 opaque);
+       message tx_done(uint64 opaque);
+};
index fbbb7a3..9f249b4 100644 (file)
@@ -25,5 +25,10 @@ errval_t acpi_reset(void);
 errval_t acpi_sleep(int state);
 errval_t acpi_get_vbe_bios_cap(struct capref *retcap, size_t *retsize);
 
+errval_t vtd_create_domain(struct capref pml4);
+errval_t vtd_delete_domain(struct capref pml4);
+errval_t vtd_domain_add_device(int seg, int bus, int dev, int funct, struct capref pt_addr);
+errval_t vtd_domain_remove_device(int seg, int bus, int dev, int funct, struct capref pt_addr);
+errval_t vtd_add_devices(void);
 
 #endif /* ACPI_CLIENT_H_ */
index e3f6ec3..38ed895 100644 (file)
@@ -250,6 +250,23 @@ static inline errval_t invoke_frame_identify(struct capref frame,
     return sysret.error;
 }
 
+static inline errval_t invoke_vnode_identify(struct capref vnode,
+                                            struct vnode_identity *ret)
+{
+    struct sysret sysret = cap_invoke1(vnode, VNodeCmd_Identify);
+
+    assert(ret != NULL);
+    if (err_is_ok(sysret.error)) {
+        ret->base = sysret.value & (~BASE_PAGE_MASK);
+       ret->type = sysret.value & BASE_PAGE_MASK;
+        return sysret.error;
+    }
+
+    ret->base = 0;
+    ret->type = 0;
+    return sysret.error;
+}
+
 /**
  * \brief Modify mapping flags on parts of a mapped frame
  *
@@ -322,6 +339,61 @@ invoke_dispatcher(struct capref dispatcher, struct capref domdispatcher,
 }
 
 /**
+ * \brief Execute vmread on the VMCS of the VM guest DCB
+ *
+ * The VMCS must be current and active.
+ *
+ * \param dcb       Dispatcher capability
+ * \param encoding  Encoding of the field to read from the VMCS
+ * \param addr      The address to write the value of the field to.
+ */
+static inline errval_t invoke_dispatcher_vmread(struct capref dispatcher, 
+                                               uintptr_t encoding, 
+                                               lvaddr_t *addr)
+{
+    return cap_invoke3(dispatcher, DispatcherCmd_Vmread, 
+                      encoding, (uintptr_t)addr).error; 
+}
+
+/**
+ * \brief Execute vmwrite on the VMCS of the VM guest DCB
+ *
+ * The VMCS must be current and active.
+ *
+ * \param dcb       Dispatcher capability
+ * \param encoding  Encoding of the field to write to the VMCS.
+ * \param value     Value of the field to write.
+ */
+
+static inline errval_t invoke_dispatcher_vmwrite(struct capref dispatcher, 
+                                                uintptr_t encoding, 
+                                                uintptr_t value)
+{
+    return cap_invoke3(dispatcher, DispatcherCmd_Vmwrite, 
+                      encoding, value).error; 
+}
+
+/**
+ * \brief Execute vmptrld on the VMCS of the VM guest DCB
+ *
+ * \param dcb       Dispatcher capability
+ */
+static inline errval_t invoke_dispatcher_vmptrld(struct capref dispatcher)
+{
+    return cap_invoke1(dispatcher, DispatcherCmd_Vmptrld).error; 
+}
+
+/**
+ * \brief Execute vmclear on the VMCS of the VM guest DCB
+ *   
+ * \param dcb       Dispatcher capability
+ */
+static inline errval_t invoke_dispatcher_vmclear(struct capref dispatcher)
+{
+    return cap_invoke1(dispatcher, DispatcherCmd_Vmclear).error; 
+}
+
+/**
  * \brief Setup a VM guest DCB
  *
  * \param dcb       Dispatcher capability
index 559173d..12084cf 100644 (file)
@@ -42,6 +42,13 @@ static inline errval_t lmp_ep_send(struct capref ep, lmp_send_flags_t flags,
     uint8_t send_bits = get_cap_valid_bits(send_cap);
     capaddr_t send_cptr = get_cap_addr(send_cap) >> (CPTR_BITS - send_bits);
 
+    if(debug_notify_syscall) {
+        printf("memcached: lmp_ep_send while forbidden from %p, %p, %p\n",
+               __builtin_return_address(0),
+               __builtin_return_address(1),
+               __builtin_return_address(2));
+    }
+
 #ifndef TRACE_DISABLE_LRPC
     // Do an LRPC if possible
     if (send_cptr == 0 && send_bits == 0          // Not sending a cap
index 1bfa695..2aee469 100644 (file)
@@ -65,6 +65,7 @@
         : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
         : "r11");
 #else
+#ifdef CONFIG_SVM
 #  define BF_SYSCALL_ASM(arg11, label) \
     __asm volatile("pushq %%rbp             \n\t"   \
                    "movq %%rcx, %%rbp       \n\t"   \
           "+r" (a3), "+r" (a4), "+r" (a5), "+r" (syscall_num)  \
         : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
         : "r11");
+#else 
+#  define BF_SYSCALL_ASM(arg11, label) \
+    __asm volatile("pushq %%rbp             \n\t"   \
+                   "movq %%rcx, %%rbp       \n\t"   \
+                   "vmcall                 \n\t"    \
+                   label                            \
+                   "popq %%rbp              \n\t"   \
+        : "+a" (a10_ret1), "+c" (arg11), "+d" (a2_ret2), "+r" (a1), \
+          "+r" (a3), "+r" (a4), "+r" (a5), "+r" (syscall_num)  \
+        : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
+        : "r11");
+#endif
 #endif
 #endif
 
     BF_SYSCALL_ASM(arg11, label)
 
 
+extern bool debug_notify_syscall;
+
+#include <stdio.h>
+
 static inline struct sysret syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
                  uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
                  uint64_t arg7, uint64_t arg8, uint64_t arg9, uint64_t arg10,
                  uint64_t arg11, uint64_t arg12)
 {
+    if(debug_notify_syscall && num == SYSCALL_INVOKE) {
+        char str[256];
+        snprintf(str, 256, "Syscall while forbidden! from %p, %p, %p\n",
+                 __builtin_return_address(0),
+                 __builtin_return_address(1),
+                 __builtin_return_address(2));
+        BF_SYSCALL_BODY(SYSCALL_PRINT, (uint64_t)str, 256, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, "");
+    }
+
     BF_SYSCALL_BODY(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
                     arg10, arg11, arg12, "");
     return (struct sysret){/*error*/ a10_ret1, /*value*/ a2_ret2};
index b7178fc..6c1addd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ETH Zurich.
+ * Copyright (c) 2014, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
index c56f09f..f0160e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ETH Zurich.
+ * Copyright (c) 2014, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
index 9c36946..36aefdf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ETH Zurich.
+ * Copyright (c) 2014, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -114,8 +114,10 @@ PACK_STRUCT_END
 
 #define IP_HLEN 20
 
+#define IP_PROTO_IP      0
 #define IP_PROTO_ICMP    1
 #define IP_PROTO_IGMP    2
+#define IP_PROTO_IPENCAP 4
 #define IP_PROTO_UDP     17
 #define IP_PROTO_UDPLITE 136
 #define IP_PROTO_TCP     6
index ee17b07..b969c80 100644 (file)
@@ -65,7 +65,7 @@ extern struct cnoderef cnode_root, cnode_task, cnode_base,
 /* well-known capabilities */
 extern struct capref cap_root, cap_monitorep, cap_irq, cap_io, cap_dispatcher,
                      cap_selfep, cap_kernel, cap_initep, cap_perfmon, cap_dispframe,
-                     cap_sessionid, cap_ipi;
+                     cap_sessionid, cap_ipi, cap_vroot;
 
 /**
  * \brief Returns the number of valid bits in the CSpace address of a cap
index 4dcb8af..627d4fe 100644 (file)
@@ -200,6 +200,17 @@ static inline volatile struct ump_message *ump_impl_get_next(
     // construct header
     ctrl->epoch = c->epoch;
 
+    if(debug_notify_syscall) {
+        printf("ump_impl_get_next while forbidden from %p, %p, %p, %p, %p, %p, %p\n",
+               __builtin_return_address(0),
+               __builtin_return_address(1),
+               __builtin_return_address(2),
+               __builtin_return_address(3),
+               __builtin_return_address(4),
+               __builtin_return_address(5),
+               __builtin_return_address(6));
+    }
+
     volatile struct ump_message *msg = &c->buf[c->pos];
 
     // update pos
index 48c6f4b..486971e 100644 (file)
@@ -32,15 +32,16 @@ __BEGIN_DECLS
 #define VREGION_FLAGS_HUGE     0x80 // Map huge pages, if possible
 #define VREGION_FLAGS_WRITE_COMBINING   0x100 // Write-combining caching
 #define VREGION_FLAGS_MASK     0x1ff // Mask of all individual VREGION_FLAGS
+#define VREGION_FLAGS_VTD_SNOOP  0x800 // Snooping (for pages) allowed by VT-d
 
 #define VREGION_FLAGS_READ_WRITE \
-    (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE)
+    (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE | VREGION_FLAGS_VTD_SNOOP)
 #define VREGION_FLAGS_READ_EXECUTE \
-    (VREGION_FLAGS_READ | VREGION_FLAGS_EXECUTE)
+    (VREGION_FLAGS_READ | VREGION_FLAGS_EXECUTE | VREGION_FLAGS_VTD_SNOOP)
 #define VREGION_FLAGS_READ_WRITE_NOCACHE \
-    (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE | VREGION_FLAGS_NOCACHE)
+    (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE | VREGION_FLAGS_NOCACHE | VREGION_FLAGS_VTD_SNOOP)
 #define VREGION_FLAGS_READ_WRITE_MPB \
-    (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE | VREGION_FLAGS_MPB)
+    (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE | VREGION_FLAGS_MPB | VREGION_FLAGS_VTD_SNOOP)
 
 struct vspace;
 struct memobj;
index 41b30ed..b980be0 100644 (file)
@@ -166,6 +166,7 @@ enum cnode_cmd {
 enum vnode_cmd {
     VNodeCmd_Map,
     VNodeCmd_Unmap,
+    VNodeCmd_Identify,   ///< Return the physical address of the VNode
 };
 
 /**
@@ -220,6 +221,10 @@ enum dispatcher_cmd {
     DispatcherCmd_SetupGuest,       ///< Set up the DCB of a guest domain
     DispatcherCmd_DumpPTables,      ///< Dump hw page tables of dispatcher
     DispatcherCmd_DumpCapabilities  ///< Dump capabilities of dispatcher
+    DispatcherCmd_Vmread,           ///< Execute vmread on the current and active VMCS      
+    DispatcherCmd_Vmwrite,          ///< Execute vmwrite on the current and active VMCS
+    DispatcherCmd_Vmptrld,          ///< Make VMCS clear and inactive
+    DispatcherCmd_Vmclear           ///< Make VMCS current and active 
 };
 
 /**
@@ -270,6 +275,7 @@ enum perfmon_cmd {
     PerfmonCmd_Write        ///< Read current performance counter values
 };
 
+
 /**
  * ID capability commands.
  */
@@ -298,6 +304,14 @@ struct frame_identity {
     uint8_t bits;      ///< Size of frame, in bits
 };
 
+/**
+ * \brief Values returned from the VNode identify invocation
+ */
+struct vnode_identity {
+    genpaddr_t base;   ///< Physical base address of the VNode
+    uint8_t type;      ///< Type of VNode
+};
+
 #ifdef __scc__
 struct scc_frame_identity {
     uint8_t route, subdest;
index 4d9a76f..b9a0a2f 100644 (file)
 #ifndef KPI_VMKIT_H
 #define KPI_VMKIT_H
 
+struct msr_entry {
+    uint32_t index;
+    uint32_t reserved;
+    uint64_t val;
+} __attribute__ ((packed));
+
 /**
  * \brief A VMKit guest control and state structure.
  *
@@ -24,6 +30,9 @@
 struct guest_control {
     /// Space to store all regs not captured in the VMCB
     struct registers_x86_64 regs;
+    struct registers_x86_64 host_regs;
+    uint64_t guest_cr2;
+    uint64_t host_cr2;
     uint64_t        num_vm_exits_with_monitor_invocation;
     uint64_t        num_vm_exits_without_monitor_invocation;
 };
diff --git a/include/barrelfish_kpi/vmx_controls.h b/include/barrelfish_kpi/vmx_controls.h
new file mode 100644 (file)
index 0000000..a101712
--- /dev/null
@@ -0,0 +1,98 @@
+/**
+ * \file
+ * \brief Contains definitions of VMX controls along with the controls 
+ * that are desired to be used for each VMCS. 
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#ifndef VMX_CONTROLS_H
+#define VMX_CONTROLS_H
+
+typedef uint32_t vmx_controls;
+
+enum vmx_ctls_t {
+    VMX_CTLS_PIN_BASED              = 0,
+    VMX_CTLS_PRIMARY_PROCESSOR      = 1,
+    VMX_CTLS_SECONDARY_PROCESSOR    = 2,
+    VMX_CTLS_EXIT                   = 3,
+    VMX_CTLS_ENTRY                  = 4
+};
+
+// Pin-based VM-execution controls
+#define PIN_CTLS_EXT_INTR       (1 << 0)
+#define PIN_CTLS_NMI            (1 << 3)
+#define PIN_CTLS_VIRT_NMI       (1 << 5)
+#define PIN_CTLS_PREEMPT_TIMER  (1 << 6)
+#define PIN_CTLS_POSTED_INTR    (1 << 7)
+
+// Primary processor-based VM-execution controls 
+#define PP_CTLS_INTR_WINDOW     (1 << 2)
+#define PP_CLTS_TSC_OFF         (1 << 3)
+#define PP_CLTS_HLT             (1 << 7)
+#define PP_CLTS_INVLPG          (1 << 9)
+#define PP_CLTS_MWAIT           (1 << 10)
+#define PP_CLTS_RDPMC           (1 << 11)
+#define PP_CLTS_RDTSC           (1 << 12)
+#define PP_CLTS_C3_LOAD         (1 << 15)
+#define PP_CLTS_C3_STORE        (1 << 16)
+#define PP_CLTS_C8_LOAD         (1 << 19)
+#define PP_CLTS_C8_STORE        (1 << 20)
+#define PP_CLTS_TPR_SHADOW      (1 << 21)
+#define PP_CLTS_NMI_WINDOW      (1 << 22)
+#define PP_CLTS_MOVDR           (1 << 23)
+#define PP_CLTS_UNCOND_IO       (1 << 24)
+#define PP_CLTS_IOBMP           (1 << 25)
+#define PP_CLTS_MONITOR_TF      (1 << 27)
+#define PP_CLTS_MSRBMP          (1 << 28)
+#define PP_CLTS_MONITOR         (1 << 29)
+#define PP_CLTS_PAUSE           (1 << 30)
+#define PP_CLTS_SEC_CTLS        (1 << 31)
+
+// Secondary processor-based VM-execution controls
+#define SP_CLTS_VIRT_APIC       (1 << 0)
+#define SP_CLTS_ENABLE_EPT      (1 << 1)
+#define SP_CLTS_DESC_TABLE      (1 << 2)
+#define SP_CLTS_RDTSCP          (1 << 3)
+#define SP_CLTS_VIRT_X2APIC     (1 << 4)
+#define SP_CLTS_ENABLE_VPID     (1 << 5)
+#define SP_CLTS_WBINVD          (1 << 6)
+#define SP_CLTS_UNRSTD_GUEST    (1 << 7)
+#define SP_CLTS_VIRT_APIC_REG   (1 << 8)
+#define SP_CLTS_VIRQ_DEL        (1 << 9)
+#define SP_CLTS_PAUSE_LOOP      (1 << 10)
+#define SP_CLTS_RDRAND          (1 << 11)
+#define SP_CLTS_ENABLE_INVPCID  (1 << 12)
+#define SP_CLTS_VMFUNC          (1 << 13)
+#define SP_CLTS_VMCS_SHADOW     (1 << 14)
+#define SP_CLTS_EPT_VIOL        (1 << 18)
+
+// VM-exit controls
+#define EXIT_CLTS_SAVE_DBG      (1 << 2)
+#define EXIT_CLTS_HOST_SIZE     (1 << 9)
+#define EXIT_CLTS_LOAD_PGC      (1 << 12)
+#define EXIT_CLTS_ACK_INTR      (1 << 15)
+#define EXIT_CLTS_SAVE_PAT      (1 << 18)
+#define EXIT_CLTS_LOAD_PAT      (1 << 19)
+#define EXIT_CLTS_SAVE_EFER     (1 << 20)
+#define EXIT_CLTS_LOAD_EFER     (1 << 21)
+#define EXIT_CLTS_SAVE_PREEMPT  (1 << 22)
+
+// VM-entry controls
+#define ENTRY_CLTS_LOAD_DBG     (1 << 2)
+#define ENTRY_CLTS_IA32E_MODE   (1 << 9)
+#define ENTRY_CLTS_SMM          (1 << 10)
+#define ENTRY_CLTS_DUAL_MONITOR (1 << 11)
+#define ENTRY_CLTS_LOAD_PGC     (1 << 13)
+#define ENTRY_CLTS_LOAD_PAT     (1 << 14)
+#define ENTRY_CLTS_LOAD_EFER    (1 << 15)
+
+#endif // VMX_CONTROLS_H
diff --git a/include/barrelfish_kpi/vmx_encodings.h b/include/barrelfish_kpi/vmx_encodings.h
new file mode 100644 (file)
index 0000000..bca790e
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#ifndef VMX_ENCODINGS_H
+#define VMX_ENCODINGS_H
+
+// 16-bit field encodings
+
+// read-only data fields
+#define VMX_VPID 0x0 // Virtual-processor identifier (VPID)
+#define VMX_PINV 0x2 // Posted-interrupt notification vector
+#define VMX_EPTP 0x4 // EPTP index
+
+// guest-state fields
+#define VMX_GUEST_ES_SEL 0x800 // Guest ES selector
+#define VMX_GUEST_CS_SEL 0x802 // Guest CS selector
+#define VMX_GUEST_SS_SEL 0x804 // Guest SS selector
+#define VMX_GUEST_DS_SEL 0x806 // Guest DS selector
+#define VMX_GUEST_FS_SEL 0x808 // Guest FS selector
+#define VMX_GUEST_GS_SEL 0x80A // Guest GS selector
+#define VMX_GUEST_LDTR_SEL 0x80C // Guest LDTR selector
+#define VMX_GUEST_TR_SEL 0x80E // Guest TR selector
+#define VMX_GUEST_IS 0x810 // Guest interrupt status
+
+// host-state fields
+#define VMX_HOST_ES_SEL 0xC00 // Guest ES selector
+#define VMX_HOST_CS_SEL 0xC02 // Guest CS selector
+#define VMX_HOST_SS_SEL 0xC04 // Guest SS selector
+#define VMX_HOST_DS_SEL 0xC06 // Guest DS selector
+#define VMX_HOST_FS_SEL 0xC08 // Guest FS selector
+#define VMX_HOST_GS_SEL 0xC0A // Guest GS selector
+#define VMX_HOST_TR_SEL 0xC0C // Guest TR selector
+
+// 32-bit field encodings
+
+// control fields
+#define VMX_EXEC_PIN_BASED 0x4000 // Pin-based controls
+#define VMX_EXEC_PRIM_PROC 0x4002 // Primary processor-based controls
+#define VMX_EXCP_BMP 0x4004 // Exception bitmap
+#define VMX_PF_ERR_MASK 0x4006 // Page-fault error-code mask
+#define VMX_PF_ERR_MATCH 0x4008 // Page-fault error-code match
+#define VMX_CR3_TARGET_CNT 0x400A // CR3-target count
+#define VMX_EXIT_CONTROLS 0x400C // VM-exit controls
+#define VMX_EXIT_MSR_STORE_CNT 0x400E // VM-exit MSR-store count
+#define VMX_EXIT_MSR_LOAD_CNT 0x4010 // VM-exit MSR-load count
+#define VMX_ENTRY_CONTROLS 0x4012 // VM-entry controls
+#define VMX_ENTRY_MSR_LOAD_CNT 0x4014 // VM-entry MSR-load count
+#define VMX_ENTRY_INTR_INFO 0x4016 // VM-entry interruption-information field
+#define VMX_ENTRY_EXCP_ERR 0x4018 // VM-entry exception error code
+#define VMX_ENTRY_INSTR_LEN 0x401A // VM-entry instruction length
+#define VMX_TPR_THRESHOLD 0x401C // TPR threshold
+#define VMX_EXEC_SEC_PROC 0x401E // Secondary processor-based controls
+#define VMX_PLE_GAP 0x4020 // PLE_Gap
+#define VMX_PLE_WINDOW 0x4022 // PLE_Window
+
+// read-only data fields
+#define VMX_INSTR_ERROR 0x4400 // VM-instruction error
+#define VMX_EXIT_REASON 0x4402 // Exit reason
+#define VMX_EXIT_INTR_INFO 0x4404 // VM-exit interruption information
+#define VMX_EXIT_INTR_ERR 0x4406 // VM-exit interruption error code
+#define VMX_IDT_VEC_INFO 0x4408 // IDT-vectoring information field
+#define VMX_IDT_VEC_ERR 0x440A // IDT-vectoring error code
+#define VMX_EXIT_INSTR_LEN 0x440C // VM-exit instruction length
+#define VMX_EXIT_INSTR_INFO 0x440E // VM-exit instruction information
+
+// guest-state fields
+#define VMX_GUEST_ES_LIM 0x4800 // Guest ES limit
+#define VMX_GUEST_CS_LIM 0x4802 // Guest CS limit
+#define VMX_GUEST_SS_LIM 0x4804 // Guest SS limit
+#define VMX_GUEST_DS_LIM 0x4806 // Guest DS limit
+#define VMX_GUEST_FS_LIM 0x4808 // Guest FS limit
+#define VMX_GUEST_GS_LIM 0x480A // Guest GS limit
+#define VMX_GUEST_LDTR_LIM 0x480C // Guest LDTR limit
+#define VMX_GUEST_TR_LIM 0x480E // Guest TR limit
+#define VMX_GUEST_GDTR_LIM 0x4810 // Guest GDTR limit
+#define VMX_GUEST_IDTR_LIM 0x4812 // Guest IDTR limit
+#define VMX_GUEST_ES_ACCESS 0x4814 // Guest ES access rights
+#define VMX_GUEST_CS_ACCESS 0x4816 // Guest CS access rights
+#define VMX_GUEST_SS_ACCESS 0x4818 // Guest SS access rights
+#define VMX_GUEST_DS_ACCESS 0x481A // Guest DS access rights
+#define VMX_GUEST_FS_ACCESS 0x481C // Guest FS access rights
+#define VMX_GUEST_GS_ACCESS 0x481E // Guest GS access rights
+#define VMX_GUEST_LDTR_ACCESS 0x4820 // Guest LDTR access rights
+#define VMX_GUEST_TR_ACCESS 0x4822 // Guest TR access rights
+#define VMX_GUEST_INTR_STATE 0x4824 // Guest activity state
+#define VMX_GUEST_ACTIV_STATE 0x4826 // Guest activity state
+#define VMX_GUEST_SMBASE 0x4828 // Guest SMBASE
+#define VMX_GUEST_SYSENTER_CS 0x482A // Guest IA32_SYSENTER_CS
+#define VMX_GUEST_PREEMPT_TIMER 0x482E // VMX-preemption timer value
+
+// host-state fields
+#define VMX_HOST_SYSENTER_CS 0x4C00 // Host IA32_SYSENTER_CS
+
+// 64-bit field encodings
+
+// control fields
+#define VMX_IOBMP_A_F 0x2000 // Address of I/O bitmap A (full)
+#define VMX_IOBMP_A_H 0x2001 // Address of I/O bitmap A (high)
+#define VMX_IOBMP_B_F 0x2002 // Address of I/O bitmap B (full)
+#define VMX_IOBMP_B_H 0x2003 // Address of I/O bitmap B (high)
+#define VMX_MSRBMP_F 0x2004 // Address of MSR bitmaps (full)
+#define VMX_MSRBMP_H 0x2005 // Address of MSR bitmaps (high)
+#define VMX_EXIT_MSR_STORE_F 0x2006 // VM-exit MSR-store address (full)
+#define VMX_EXIT_MSR_STORE_H 0x2007 // VM-exit MSR-store address (high)
+#define VMX_EXIT_MSR_LOAD_F 0x2008 // VM-exit MSR-load address (full)
+#define VMX_EXIT_MSR_LOAD_H 0x2009 // VM-exit MSR-load address (high)
+#define VMX_ENTRY_MSR_LOAD_F 0x200A // VM-entry MSR-load address (full)
+#define VMX_ENTRY_MSR_LOAD_H 0x200B // VM-entry MSR-load address (high)
+#define VMX_EVMCS_PTR_F 0x200C // Executive-VMCS pointer (full)
+#define VMX_EVMCS_PTR_H 0x200D // Executive-VMCS pointer (high)
+#define VMX_TSC_OFF_F 0x2010 // TSC offset (full)
+#define VMX_TSC_OFF_H 0x2011 // TSC offset (high)
+#define VMX_VAPIC_F 0x2012 // Virtual-APIC address (full)
+#define VMX_VAPIC_H 0x2013 // Virtual-APIC address (high)
+#define VMX_APIC_ACC_F 0x2014 // APIC-access address (full)
+#define VMX_APIC_ACC_H 0x2015 // APIC-access address (high)
+#define VMX_PID_F 0x2016 // Posted-interrupt descriptor address (full)
+#define VMX_PID_H 0x2017 // Posted-interrupt descriptor address (high)
+#define VMX_VMFUNC_F 0x2018 // VM-function controls (full)
+#define VMX_VMFUNC_H 0x2019 // VM-function controls (high)
+#define VMX_EPTP_F 0x201A // EPT pointer (full)
+#define VMX_EPTP_H 0x201B // EPT pointer (high)
+#define VMX_EOI_EXIT_BMP0_F 0x201C // EOI-exit bitmap 0 (full)
+#define VMX_EOI_EXIT_BMP0_H 0x201D // EOI-exit bitmap 0 (high)
+#define VMX_EOI_EXIT_BMP1_F 0x201E // EOI-exit bitmap 1 (full)
+#define VMX_EOI_EXIT_BMP1_H 0x201F // EOI-exit bitmap 1 (high)
+#define VMX_EOI_EXIT_BMP2_F 0x2020 // EOI-exit bitmap 2 (full)
+#define VMX_EOI_EXIT_BMP2_H 0x2021 // EOI-exit bitmap 2 (high)
+#define VMX_EOI_EXIT_BMP3_F 0x2022 // EOI-exit bitmap 3 (full)
+#define VMX_EOI_EXIT_BMP3_H 0x2023 // EOI-exit bitmap 3 (high)
+#define VMX_EPTP_LIST_F 0x2024 // EPTP-list address (full)
+#define VMX_EPTP_LIST_H 0x2025 // EPTP-list address (high)
+#define VMX_VMREAD_BMP_F 0x2026 // VMREAD-bitmap address (full)
+#define VMX_VMREAD_BMP_H 0x2027 // VMREAD-bitmap address (high)
+#define VMX_VMWRITE_BMP_F 0x2028 // VMWRITE-bitmap address (full)
+#define VMX_VMWRITE_BMP_H 0x2029 // VMWRITE-bitmap address (high)
+#define VMX_VEXCP_INFO_F 0x202A // Virtualization-exception info. address (full)
+#define VMX_VEXCP_INFO_H 0x202B // Virtualization-exception info. address (high)
+
+// read-only data fields
+#define VMX_GPADDR_F 0x2400 // Guest-physical address (full)
+#define VMX_GPADDR_H 0x2401 // Guest-physical address (high)
+
+// guest-state fields
+#define VMX_GUEST_VMCS_LPTR_F 0x2800 // VMCS link pointer (full)
+#define VMX_GUEST_VMCS_LPTR_H 0x2801 // VMCS link pointer (high)
+#define VMX_GUEST_DCTL_F 0x2802 // Guest IA32_DEBUGCTL (full)
+#define VMX_GUEST_DCTL_H 0x2803 // Guest IA32_DEBUGCTL (high)
+#define VMX_GUEST_PAT_F 0x2804 // Guest IA32_PAT (full)
+#define VMX_GUEST_PAT_H 0x2805 // Guest IA32_PAT (high)
+#define VMX_GUEST_EFER_F 0x2806 // Guest IA32_EFER (full)
+#define VMX_GUEST_EFER_H 0x2807 // Guest IA32_EFER (high)
+#define VMX_GUEST_PGC_F 0x2808 // Guest IA32_PERF_GLOBAL_CTRL (full)
+#define VMX_GUEST_PGC_H 0x2809 // Guest IA32_PERF_GLOBAL_CTRL (high)
+#define VMX_GUEST_PDPTE0_F 0x280A // Guest PDPTE0 (full)
+#define VMX_GUEST_PDPTE0_H 0x280B // Guest PDPTE0 (high)
+#define VMX_GUEST_PDPTE1_F 0x280C // Guest PDPTE1 (full)
+#define VMX_GUEST_PDPTE1_H 0x280D // Guest PDPTE1 (high)
+#define VMX_GUEST_PDPTE2_F 0x280E // Guest PDPTE2 (full)
+#define VMX_GUEST_PDPTE2_H 0x280F // Guest PDPTE2 (high) 
+#define VMX_GUEST_PDPTE3_F 0x2810 // Guest PDPTE3 (full)
+#define VMX_GUEST_PDPTE3_H 0x2811 // Guest PDPTE3 (high)
+
+// host-state fields
+#define VMX_HOST_PAT_F 0x2C00 // Host IA32_PAT (full)
+#define VMX_HOST_PAT_H 0x2C01 // Host IA32_PAT (high)
+#define VMX_HOST_EFER_F 0x2C02 // Host IA32_EFER (full)
+#define VMX_HOST_EFER_H 0x2C03 // Host IA32_EFER (high)
+#define VMX_HOST_PGC_F 0x2C04 // Host IA32_PERF_GLOBAL_CTRL (full)
+#define VMX_HOST_PGC_H 0x2C05 // Host IA32_PERF_GLOBAL_CTRL (high)
+
+// Natural-width field encodings
+
+// control fields
+#define VMX_CR0_GH_MASK 0x6000 // CR0 guest/host mask
+#define VMX_CR4_GH_MASK 0x6002 // CR4 guest/host mask
+#define VMX_CR0_RD_SHADOW 0x6004 // CR0 read shadow 
+#define VMX_CR4_RD_SHADOW 0x6006 // CR4 read shadow
+#define VMX_CR3_T0 0x6008 // CR3-target value 0
+#define VMX_CR3_T1 0x600A // CR3-target value 1
+#define VMX_CR3_T2 0x600C // CR3-target value 2
+#define VMX_CR3_T3 0x600E // CR3-target value 3
+
+// read-only data fields
+#define VMX_EXIT_QUAL 0x6400 // Exit qualification
+#define VMX_IO_RCX 0x6402 // I/O RCX
+#define VMX_IO_RSI 0x6404 // I/O RSI
+#define VMX_IO_RDI 0x6406 // I/O RDI
+#define VMX_IO_RIP 0x6408 // I/O RIP
+#define VMX_GL_ADDR 0x640A // Guest-linear address
+
+// guest-state fields
+#define VMX_GUEST_CR0 0x6800 // Guest CR0
+#define VMX_GUEST_CR3 0x6802 // Guest CR3
+#define VMX_GUEST_CR4 0x6804 // Guest CR4
+#define VMX_GUEST_ES_BASE 0x6806 // Guest ES base
+#define VMX_GUEST_CS_BASE 0x6808 // Guest CS base
+#define VMX_GUEST_SS_BASE 0x680A // Guest SS base
+#define VMX_GUEST_DS_BASE 0x680C // Guest DS base
+#define VMX_GUEST_FS_BASE 0x680E // Guest FS base
+#define VMX_GUEST_GS_BASE 0x6810 // Guest GS base
+#define VMX_GUEST_LDTR_BASE 0x6812 // Guest LDTR base
+#define VMX_GUEST_TR_BASE 0x6814 // Guest TR base
+#define VMX_GUEST_GDTR_BASE 0x6816 // Guest GDTR base
+#define VMX_GUEST_IDTR_BASE 0x6818 // Guest IDTR base
+#define VMX_GUEST_DR7 0x681A // Guest DR7
+#define VMX_GUEST_RSP 0x681C // Guest RSP
+#define VMX_GUEST_RIP 0x681E // Guest RIP
+#define VMX_GUEST_RFLAGS 0x6820 // Guest RFLAGS
+#define VMX_GUEST_PDEXCP 0x6822 // Guest pending debug exceptions
+#define VMX_GUEST_SYSENTER_ESP  0x6824 // Guest IA32_SYSENTER_ESP
+#define VMX_GUEST_SYSENTER_EIP  0x6826 // Guest IA32_SYSENTER_EIP
+
+// host-state fields
+#define VMX_HOST_CR0 0x6C00 // Host CR0
+#define VMX_HOST_CR3 0x6C02 // Host CR3
+#define VMX_HOST_CR4 0x6C04 // Host CR4
+#define VMX_HOST_FS_BASE 0x6C06 // Host FS base
+#define VMX_HOST_GS_BASE 0x6C08 // Host GS base
+#define VMX_HOST_TR_BASE 0x6C0A // Host TR base
+#define VMX_HOST_GDTR_BASE 0x6C0C // Host GDTR base
+#define VMX_HOST_IDTR_BASE 0x6C0E // Host IDTR base
+#define VMX_HOST_SYSENTER_ESP 0x6C10 // Host IA32_SYSENTER_ESP
+#define VMX_HOST_SYSENTER_EIP 0x6C12 // Host IA32_SYSENTER_EIP
+#define VMX_HOST_RSP 0x6C14 // Host RSP
+#define VMX_HOST_RIP 0x6C16 // Host RIP
+
+#endif // VMX_ENCODINGS_H
diff --git a/include/barrelfish_kpi/vmx_exit_reasons.h b/include/barrelfish_kpi/vmx_exit_reasons.h
new file mode 100644 (file)
index 0000000..f0444f6
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#ifndef VMX_EXIT_REASONS_H
+#define VMX_EXIT_REASONS_H
+
+#define VMX_EXIT_REASON_EXCEPTION           0
+#define VMX_EXIT_REASON_EXT_INTR            1
+#define VMX_EXIT_REASON_TRIPLE_FAULT        2
+#define VMX_EXIT_REASON_INIT                3
+#define VMX_EXIT_REASON_SIPI                4
+#define VMX_EXIT_REASON_IO_SMI              5
+#define VMX_EXIT_REASON_SMI                 6
+#define VMX_EXIT_REASON_INTR_WINDOW         7
+#define VMX_EXIT_REASON_NMI_WINDOW          8
+#define VMX_EXIT_REASON_TASK_SWITCH         9
+#define VMX_EXIT_REASON_CPUID               10
+#define VMX_EXIT_REASON_GETSEC              11
+#define VMX_EXIT_REASON_HLT                 12
+#define VMX_EXIT_REASON_INVD                13
+#define VMX_EXIT_REASON_INVLPG              14
+#define VMX_EXIT_REASON_RDPMC               15
+#define VMX_EXIT_REASON_RDTSC               16
+#define VMX_EXIT_REASON_RSM                 17
+#define VMX_EXIT_REASON_VMCALL              18
+#define VMX_EXIT_REASON_VMCLEAR             19
+#define VMX_EXIT_REASON_VMLAUNCH            20
+#define VMX_EXIT_REASON_VMPTRLD             21
+#define VMX_EXIT_REASON_VMPTRST             22
+#define VMX_EXIT_REASON_VMREAD              23
+#define VMX_EXIT_REASON_VMRESUME            24
+#define VMX_EXIT_REASON_VMWRITE             25
+#define VMX_EXIT_REASON_VMXOFF              26
+#define VMX_EXIT_REASON_VMXON               27
+#define VMX_EXIT_REASON_CR_ACCESS           28
+#define VMX_EXIT_REASON_DR_ACCESS           29
+#define VMX_EXIT_REASON_INOUT               30
+#define VMX_EXIT_REASON_RDMSR               31
+#define VMX_EXIT_REASON_WRMSR               32
+#define VMX_EXIT_REASON_INVAL_VMCS          33
+#define VMX_EXIT_REASON_INVAL_MSR           34
+#define VMX_EXIT_REASON_MWAIT               36
+#define VMX_EXIT_REASON_MTF                 37
+#define VMX_EXIT_REASON_MONITOR             39
+#define VMX_EXIT_REASON_PAUSE               40
+#define VMX_EXIT_REASON_MCE                 41
+#define VMX_EXIT_REASON_TPR                 43
+#define VMX_EXIT_REASON_APIC_ACCESS         44
+#define VMX_EXIT_REASON_VIRTUALIZED_EOI     45
+#define VMX_EXIT_REASON_GDTR_IDTR           46
+#define VMX_EXIT_REASON_LDTR_TR             47
+#define VMX_EXIT_REASON_EPT_FAULT           48
+#define VMX_EXIT_REASON_EPT_MISCONFIG       49
+#define VMX_EXIT_REASON_INVEPT              50
+#define VMX_EXIT_REASON_RDTSCP              51
+#define VMX_EXIT_REASON_VMX_PREEMPT         52
+#define VMX_EXIT_REASON_INVVPID             53
+#define VMX_EXIT_REASON_WBINVD              54
+#define VMX_EXIT_REASON_XSETBV              55
+#define VMX_EXIT_REASON_APIC_WRITE          56
+
+#endif // VMX_EXIT_REASONS_H
index a9a12ba..556a04b 100644 (file)
@@ -20,7 +20,6 @@
 #include <contmng/contmng.h>
 #include <contmng/netbench.h>
 #include <procon/procon.h>
-#include <if/net_queue_manager_defs.h>
 #include <barrelfish/net_constants.h>
 #include <net_interfaces/flags.h>
 
index 3c39052..e60e41f 100644 (file)
 #define PCI_VENDOR_REALTEK      0x10ec
 #define PCI_VENDOR_AMD          0x1022
 #define PCI_VENDOR_ATI          0x1002
+#define PCI_VENDOR_LSI         0x1000
 #define PCI_VENDOR_FISH         0xdada
 
 #define PCI_CLASS_MASS_STORAGE  0x1
+#define PCI_SUB_RAID           0x4
 #define PCI_SUB_SATA            0x6
 
 #define PCI_CLASS_ETHERNET      0x2
diff --git a/include/poll.h b/include/poll.h
new file mode 100644 (file)
index 0000000..06fb41a
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/poll.h>
index bcc02c8..2f4fffb 100644 (file)
@@ -223,6 +223,7 @@ int __sigaction(int signum, const struct sigaction *act,
               struct sigaction *oldact);
 #define sigaction(a,b,c) __sigaction(a,b,c)
 int raise(int sig);
+int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
 __END_DECLS
 
 #endif // BARRELFISH_SIGNAL_H_
diff --git a/include/storage/storage.h b/include/storage/storage.h
new file mode 100644 (file)
index 0000000..3be7a8f
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef STORAGE_H
+#define STORAGE_H
+
+#include <storage/vsa.h>
+#include <storage/vsic.h>
+
+#define storage_alloca(vsic, size)             \
+  alloca(STORAGE_VSIC_ROUND(vsic, size))
+
+#define storage_malloc(vsic, size)             \
+  malloc(STORAGE_VSIC_ROUND(vsic, size))
+
+#define storage_realloc(vsic, ptr, size)               \
+  realloc(ptr, STORAGE_VSIC_ROUND(vsic, size))
+
+#define storage_free(vsic, ptr)                        \
+  free(ptr)
+
+errval_t storage_init(int argc, const char **argv);
+
+#endif
diff --git a/include/storage/vsa.h b/include/storage/vsa.h
new file mode 100644 (file)
index 0000000..61a27c3
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef STORAGE_VSA_H
+#define STORAGE_VSA_H
+
+#ifdef BARRELFISH
+#include <barrelfish/barrelfish.h>
+
+struct storage_vsa {
+    struct capref       vsacap;
+    size_t             size;
+};
+#elif defined(__linux__)
+struct storage_vsa {
+    int                 fd;
+    size_t             size;
+};
+#else
+#       error "Unknown operating system!"
+#endif
+
+/**
+ * \brief Allocates a virtual storage area (VSA).
+ *
+ * Allocates the next available VSA of the specified size. More
+ * specific functions may be provided in the future that allow
+ * allocating VSAs of specific characteristics (e.g., storage medium,
+ * access latency, controller). An example invocation might allocate 2
+ * VSAs on flash that have 2 different controllers for parallel
+ * access.
+ *
+ * \param size  Size (in bytes) of the VSA.
+ *
+ * \return Error code.
+ */
+errval_t storage_vsa_alloc(struct storage_vsa *vsa, size_t size);
+
+errval_t storage_vsa_acquire(struct storage_vsa *vsa, const char *name,
+                            size_t size);
+
+errval_t storage_vsa_resize(struct storage_vsa *vsa, size_t size);
+
+#endif
diff --git a/include/storage/vsic.h b/include/storage/vsic.h
new file mode 100644 (file)
index 0000000..25f7ab1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef STORAGE_VSIC_H
+#define STORAGE_VSIC_H
+
+// Roundup s to the next multiple of m
+#define STORAGE_ROUNDUP(s, m) \
+  ((s) % (m) != 0 ? (s) + ((m) - ((s) % (m))) : (s))
+
+// Round to VSIC block size
+#define STORAGE_VSIC_ROUND(vsic, s) \
+  STORAGE_ROUNDUP(s, (vsic)->blocksize)
+
+struct storage_vsic;
+struct storage_vsa;
+
+struct storage_vsic_ops {
+    errval_t (*write)(struct storage_vsic *vsic, struct storage_vsa *vsa,
+                      off_t offset, size_t size, void *buffer);
+    errval_t (*read)(struct storage_vsic *vsic, struct storage_vsa *vsa,
+                     off_t offset, size_t size, void *buffer);
+    errval_t (*flush)(struct storage_vsic *vsic, struct storage_vsa *vsa);
+    errval_t (*flush2)(struct storage_vsic *vsic, struct storage_vsa *vsa, void *handle);
+    errval_t (*wait)(struct storage_vsic *vsic);
+    errval_t (*poll)(struct storage_vsic *vsic, void **handle);
+};
+
+struct storage_vsic {
+    struct storage_vsic_ops     ops;
+    void                        *data;
+    size_t                     blocksize;
+};
+
+// XXX: Remove once we support multiple backend drivers
+errval_t storage_vsic_driver_init(int argc, const char **argv,
+                                 struct storage_vsic *vsic);
+
+#endif
index 952bf06..80e059c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, ETH Zurich.
+ * Copyright (c) 2013, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
diff --git a/include/sys/poll.h b/include/sys/poll.h
new file mode 100644 (file)
index 0000000..c955f32
--- /dev/null
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 1997 Peter Wemm <peter@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$
+ */
+
+#ifndef _SYS_POLL_H_
+#define        _SYS_POLL_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * This file is intended to be compatible with the traditional poll.h.
+ */
+
+typedef        unsigned int    nfds_t;
+
+/*
+ * This structure is passed as an array to poll(2).
+ */
+struct pollfd {
+       int     fd;             /* which file descriptor to poll */
+       short   events;         /* events we are interested in */
+       short   revents;        /* events found on return */
+};
+
+/*
+ * Requestable events.  If poll(2) finds any of these set, they are
+ * copied to revents on return.
+ * XXX Note that FreeBSD doesn't make much distinction between POLLPRI
+ * and POLLRDBAND since none of the file types have distinct priority
+ * bands - and only some have an urgent "mode".
+ * XXX Note POLLIN isn't really supported in true SVSV terms.  Under SYSV
+ * POLLIN includes all of normal, band and urgent data.  Most poll handlers
+ * on FreeBSD only treat it as "normal" data.
+ */
+#define        POLLIN          0x0001          /* any readable data available */
+#define        POLLPRI         0x0002          /* OOB/Urgent readable data */
+#define        POLLOUT         0x0004          /* file descriptor is writeable */
+#define        POLLRDNORM      0x0040          /* non-OOB/URG data available */
+#define        POLLWRNORM      POLLOUT         /* no write type differentiation */
+#define        POLLRDBAND      0x0080          /* OOB/Urgent readable data */
+#define        POLLWRBAND      0x0100          /* OOB/Urgent data can be written */
+
+#if __BSD_VISIBLE
+/* General FreeBSD extension (currently only supported for sockets): */
+#define        POLLINIGNEOF    0x2000          /* like POLLIN, except ignore EOF */
+#endif
+
+/*
+ * These events are set if they occur regardless of whether they were
+ * requested.
+ */
+#define        POLLERR         0x0008          /* some poll error occurred */
+#define        POLLHUP         0x0010          /* file descriptor was "hung up" */
+#define        POLLNVAL        0x0020          /* requested events "invalid" */
+
+#if __BSD_VISIBLE
+
+#define        POLLSTANDARD    (POLLIN|POLLPRI|POLLOUT|POLLRDNORM|POLLRDBAND|\
+                        POLLWRBAND|POLLERR|POLLHUP|POLLNVAL)
+
+/*
+ * Request that poll() wait forever.
+ * XXX in SYSV, this is defined in stropts.h, which is not included
+ * by poll.h.
+ */
+#define        INFTIM          (-1)
+
+#endif
+
+#ifndef _KERNEL
+
+__BEGIN_DECLS
+int    poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout);
+__END_DECLS
+
+#endif /* !_KERNEL */
+
+#endif /* !_SYS_POLL_H_ */
diff --git a/include/sys/utsname.h b/include/sys/utsname.h
new file mode 100644 (file)
index 0000000..410e065
--- /dev/null
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chuck Karish of Mindcraft, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *     @(#)utsname.h   8.1 (Berkeley) 1/4/94
+ * $FreeBSD$
+ */
+
+#ifndef        _SYS_UTSNAME_H
+#define        _SYS_UTSNAME_H
+
+#ifdef _KERNEL
+#define        SYS_NMLN        32              /* uname(2) for the FreeBSD 1.1 ABI. */
+#endif
+
+#ifndef SYS_NMLN
+#define        SYS_NMLN        256             /* User can override. */
+#endif
+
+struct utsname {
+       char    sysname[SYS_NMLN];      /* Name of this OS. */
+       char    nodename[SYS_NMLN];     /* Name of this network node. */
+       char    release[SYS_NMLN];      /* Release level. */
+       char    version[SYS_NMLN];      /* Version level. */
+       char    machine[SYS_NMLN];      /* Hardware type. */
+};
+
+#include <sys/cdefs.h>
+
+#ifndef _KERNEL
+__BEGIN_DECLS
+int    __xuname(int, void *);          /* Variable record size. */
+__END_DECLS
+
+static __inline int
+uname(struct utsname *name)
+{
+       return __xuname(SYS_NMLN, (void *)name);
+}
+#endif /* _KERNEL */
+
+#endif /* !_SYS_UTSNAME_H */
index 98c8d88..48bfd6f 100644 (file)
@@ -42,6 +42,7 @@ typedef uint64_t paging_x86_64_flags_t;
  * Bits within the various page directories and tables.
  */
 #define X86_64_PTABLE_EXECUTE_DISABLE  (((paging_x86_64_flags_t)1) << 63)
+#define X86_64_VTD_PAGE_SNOOP          (((paging_x86_64_flags_t)1) << 11)
 #define X86_64_PTABLE_GLOBAL_PAGE      (((paging_x86_64_flags_t)1) << 8)
 #define X86_64_PTABLE_ATTR_INDEX       (((paging_x86_64_flags_t)1) << 7)
 #define X86_64_PTABLE_DIRTY            (((paging_x86_64_flags_t)1) << 6)
diff --git a/include/tenaciousd/log.h b/include/tenaciousd/log.h
new file mode 100644 (file)
index 0000000..61eb25f
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef TENACIOUSD_LOG_H
+#define TENACIOUSD_LOG_H
+
+struct storage_vsa;
+struct storage_vsic;
+
+#define TENACIOUSD_LOG_MIN_ENTRY_SIZE(log)      \
+    (STORAGE_VSIC_ROUND(log->vsic, sizeof(struct tenaciousd_log_entry)) - sizeof(struct tenaciousd_log_entry))
+
+// sizeof(struct tenaciousd_log_entry) = on-disk size of header + footer
+struct tenaciousd_log_entry {
+  uint64_t     size;
+  uint64_t     next;           // Only valid on disk
+  uint8_t      data[0];
+  uint8_t      marker;         // Never valid
+} __attribute__ ((packed));
+
+struct tenaciousd_log_iter {
+  struct tenaciousd_log_entry  *entry;
+  struct tenaciousd_log_iter   *next;
+  uint64_t                     offset;
+};
+
+struct tenaciousd_log {
+    struct storage_vsa *vsa;
+    struct storage_vsic *vsic;
+    uint64_t entries;
+    uint64_t end;
+};
+
+struct tenaciousd_log *tenaciousd_log_new(struct storage_vsa *vsa,
+                                         struct storage_vsic *vsic);
+
+errval_t tenaciousd_log_delete(struct tenaciousd_log *log);
+
+errval_t tenaciousd_log_append(struct tenaciousd_log *log,
+                               struct tenaciousd_log_entry *entry);
+
+errval_t tenaciousd_log_trim(struct tenaciousd_log *log, int nentries);
+
+struct tenaciousd_log_iter tenaciousd_log_begin(struct tenaciousd_log *log);
+
+struct tenaciousd_log_iter tenaciousd_log_next(struct tenaciousd_log *log,
+                                              struct tenaciousd_log_iter iter);
+
+struct tenaciousd_log_entry *
+tenaciousd_log_entry_new(struct tenaciousd_log *log,
+                         size_t *size);
+
+struct tenaciousd_log_entry *
+tenaciousd_log_entry_resize(struct tenaciousd_log *log,
+                            struct tenaciousd_log_entry *entry,
+                            size_t *newsize);
+
+void tenaciousd_log_entry_delete(struct tenaciousd_log *log,
+                                struct tenaciousd_log_entry *entry);
+
+static inline bool tenaciousd_log_end(struct tenaciousd_log_iter iter)
+{
+  return iter.entry == NULL ? true : false;
+}
+
+static inline void *tenaciousd_log_iter_data(struct tenaciousd_log_iter iter)
+{
+    return (void *)iter.entry->data;
+}
+
+#endif
diff --git a/include/tenaciousd/queue.h b/include/tenaciousd/queue.h
new file mode 100644 (file)
index 0000000..8916ca1
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef TENACIOUSD_QUEUE_H
+#define TENACIOUSD_QUEUE_H
+
+struct storage_vsa;
+struct storage_vsic;
+
+struct tenaciousd_queue_element {
+  uint8_t      valid;
+  uint64_t     size;
+  uint64_t     prev;
+  uint64_t     next;           // Only valid on disk
+  uint8_t      data[0];
+  uint8_t      marker;         // Never valid
+} __attribute__ ((packed));
+
+struct tenaciousd_queue_iter {
+  struct tenaciousd_queue_element      *element;
+  struct tenaciousd_queue_iter         *next;
+};
+
+struct tenaciousd_queue {
+  struct storage_vsa *vsa;
+  struct storage_vsic *vsic;
+  uint64_t elements;
+  uint64_t last;
+  uint64_t end;
+};
+
+void tenaciousd_queue_delete_element(struct tenaciousd_queue *queue,
+                                    struct tenaciousd_queue_element *element);
+
+struct tenaciousd_queue *tenaciousd_queue_new(struct storage_vsa *vsa,
+                                         struct storage_vsic *vsic);
+
+errval_t tenaciousd_queue_delete(struct tenaciousd_queue *queue);
+
+struct tenaciousd_queue_element * 
+tenaciousd_queue_element_new(struct tenaciousd_queue *queue,
+                         size_t *size);
+
+errval_t tenaciousd_queue_add(struct tenaciousd_queue *log,
+                               struct tenaciousd_queue_element *element);
+
+struct tenaciousd_queue_element * 
+tenaciousd_queue_remove(struct tenaciousd_queue *queue);
+
+struct tenaciousd_queue_iter tenaciousd_queue_begin(struct tenaciousd_queue *log);
+
+struct tenaciousd_queue_iter tenaciousd_queue_next(struct tenaciousd_queue *log,
+                                                  struct tenaciousd_queue_iter iter);
+
+static inline bool tenaciousd_queue_end(struct tenaciousd_queue_iter iter)
+{
+  return iter.element == NULL ? true : false;
+}
+
+static inline void *tenaciousd_queue_iter_data(struct tenaciousd_queue_iter iter)
+{
+    return (void *)iter.element->data;
+}
+
+#endif
index e59683f..babc360 100644 (file)
@@ -15,4 +15,6 @@ time_t timegm(struct tm *);
 
 __END_DECLS
 
+int nanosleep(const struct timespec *req, struct timespec *rem);
+
 #endif /* __BF_TIME_H */
index d0324d1..de6f7d1 100644 (file)
@@ -105,6 +105,9 @@ let
                 "arch/x86_64/syscall.c",
                 "arch/x86_64/paging.c",
                 "arch/x86_64/vmkit.c" ,
+                "arch/x86_64/vmx_checks.c",
+                "arch/x86_64/vmx_vmkit.c",
+                "arch/x86_64/svm_vmkit.c",
                 "arch/x86_64/page_mappings_arch.c",
                 "arch/x86/apic.c",
                 "arch/x86/pic.c",
index c41bb5d..d9b267f 100644 (file)
@@ -190,10 +190,10 @@ static void create_phys_caps(lpaddr_t init_alloc_addr)
                 debug(SUBSYS_STARTUP, "RAM %lx--%lx\n", base_addr, end_addr);
                 err = create_caps_to_cnode(base_addr, end_addr - base_addr,
                                            RegionType_Empty, &spawn_state, bootinfo);
-                if (err_no(err) == SYS_ERR_SLOTS_IN_USE) {
-                    printk(LOG_WARN, "not able to create RAM caps for all physical memory in the system, CNode full\n");
+                if(err_is_fail(err)) {
+                   printk(LOG_WARN, "Skipping RAM %lx--%lx...\n", base_addr, end_addr);
                 }
-                assert(err_is_ok(err));
+                /* assert(err_is_ok(err)); */
             }
         } else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr)) {
             /* XXX: The multiboot spec just says that mapping types other than
diff --git a/kernel/arch/x86_64/svm_vmkit.c b/kernel/arch/x86_64/svm_vmkit.c
new file mode 100644 (file)
index 0000000..28e6468
--- /dev/null
@@ -0,0 +1,334 @@
+/**
+ * \file
+ * \brief Contains VMKit kernel interface for version using SVM extensions.
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#include <string.h>
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+#include <svm_vmkit.h>
+#include <x86.h>
+#include <dispatch.h>
+#include <exec.h>
+#include <barrelfish_kpi/vmkit.h>
+#include <barrelfish_kpi/syscalls.h>
+
+#include <dev/amd_vmcb_dev.h>
+
+/**
+ * \brief The storage area where SVM puts the host state during guest exec.
+ */
+static uint8_t host_save_area[BASE_PAGE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+/**
+ * \brief VMCB for the host to save its state.
+ */
+static uint8_t host_vmcb[BASE_PAGE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+static void
+vmkit_init (void)
+{
+    static bool executed = false;
+
+    if (executed) {
+        return;
+    }
+
+    executed = true;
+    memset(host_save_area, 0x0, BASE_PAGE_SIZE);
+    memset(host_vmcb, 0x0, BASE_PAGE_SIZE);
+}
+
+/**
+ * \brief Tries to enable hardware assisted virtualization.
+ *
+ * Checks whether hardware assisted virtualization is available on the platform
+ * and enables this feature.
+ *
+ * \Return Returns VMKIT_ERR_OK on successful initialization of the subsystem
+ *         or VMKIT_ERR_UNAVAIL if virtualization is unavailable.
+ */
+errval_t svm_enable_virtualization (void)
+{
+    vmkit_init ();
+
+    // first check what CPUID tells us about SVM support
+    uint32_t cpuid_ecx;
+    cpuid(CPUID_AMD_EXTFEAT, NULL, NULL, &cpuid_ecx, NULL);
+    if (!(cpuid_ecx & AMD_EXTFEAT_ECX_SVM)) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // check whether SVM support is deactivated
+    uint64_t msr_vmcr = rdmsr(MSR_AMD_VMCR);
+    if (msr_vmcr & AMD_VMCR_SVMDIS) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // from here on we assume that SVM is avail and may be enabled
+
+    // check whether SVM is already enabled
+    uint64_t msr_efer = rdmsr(MSR_IA32_EFER);
+    if (msr_efer & IA32_EFER_SVME) {
+        // SVM is already enabled
+        return SYS_ERR_OK;
+    }
+    // enable SVM
+    addmsr(MSR_IA32_EFER, IA32_EFER_SVME);
+    // check whether SVM is now enabled
+    msr_efer = rdmsr(MSR_IA32_EFER);
+    if (msr_efer & IA32_EFER_SVME) {
+        // SVM enabled
+        // set the host save area
+        wrmsr(MSR_AMD_VM_HSAVE, mem_to_local_phys((lvaddr_t)host_save_area));
+        return SYS_ERR_OK;
+    } else {
+        printk(LOG_WARN, "VMKit: Unable to enable SVM although the hardware "
+               "claims to support it.\n");
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+}
+
+static inline void
+vm_exec (struct dcb *dcb)
+{
+    lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
+    struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
+    register uintptr_t rbx __asm("rbx") = ctrl->regs.rbx;
+    register uintptr_t rcx __asm("rcx") = ctrl->regs.rcx;
+    register uintptr_t rdx __asm("rdx") = ctrl->regs.rdx;
+    register uintptr_t rsi __asm("rsi") = ctrl->regs.rsi;
+    register uintptr_t rdi __asm("rdi") = ctrl->regs.rdi;
+    register uintptr_t r8  __asm("r8")  = ctrl->regs.r8;
+    register uintptr_t r9  __asm("r9")  = ctrl->regs.r9;
+    register uintptr_t r10 __asm("r10") = ctrl->regs.r10;
+    register uintptr_t r11 __asm("r11") = ctrl->regs.r11;
+    register uintptr_t r12 __asm("r12") = ctrl->regs.r12;
+    register uintptr_t r13 __asm("r13") = ctrl->regs.r13;
+    register uintptr_t r14 __asm("r14") = ctrl->regs.r14;
+    register uintptr_t r15 __asm("r15") = ctrl->regs.r15;
+#ifdef NDEBUG
+    register uintptr_t rbp __asm("rbp") = ctrl->regs.rbp;
+
+    __asm volatile ("sti\n\t"       // allow intr to happen inside the host
+                    "vmrun\n\t"     // execute the guest
+                    "cli\n\t"       // disable intr in the host again
+                    "stgi\n\t"      // enable the global intr flag
+        : "+r" (rbx), "+r" (rcx), "+r" (rdx), "+r" (rbp), "+r" (rsi), "+r" (rdi),
+          "+r" (r8), "+r" (r9), "+r" (r10), "+r" (r11), "+r" (r12), "+r" (r13),
+          "+r" (r14), "+r" (r15)
+        : "a" (dcb->guest_desc.vmcb.cap.u.frame.base)
+        : "memory");
+#else
+    static uintptr_t rbp, srbp;
+
+    rbp = ctrl->regs.rbp;
+
+    __asm volatile ("mov %%rbp, %[srbp]\n\t" :: [srbp] "m" (srbp));
+
+    __asm volatile ("mov %[nrbp], %%rbp\n\t"
+                    "sti\n\t"       // allow intr to happen inside the host
+                    "vmrun\n\t"     // execute the guest
+                    "cli\n\t"       // disable intr in the host again
+                    "stgi\n\t"      // enable the global intr flag
+                    "mov %%rbp, %[nrbp]\n\t"
+        : "+r" (rbx), "+r" (rcx), "+r" (rdx), [nrbp] "+m" (rbp),
+                    "+r" (rsi), "+r" (rdi), "+r" (r8), "+r" (r9), "+r" (r10),
+                    "+r" (r11), "+r" (r12), "+r" (r13), "+r" (r14), "+r" (r15)
+        : "a" (dcb->guest_desc.vmcb.cap.u.frame.base)
+        : "memory");
+
+    __asm volatile ("mov %[srbp], %%rbp\n\t"
+                    : [srbp] "+m" (srbp));
+#endif
+
+    ctrl->regs.rbx = rbx;
+    ctrl->regs.rcx = rcx;
+    ctrl->regs.rdx = rdx;
+    ctrl->regs.rbp = rbp;
+    ctrl->regs.rsi = rsi;
+    ctrl->regs.rdi = rdi;
+    ctrl->regs.r8 = r8;
+    ctrl->regs.r9 = r9;
+    ctrl->regs.r10 = r10;
+    ctrl->regs.r11 = r11;
+    ctrl->regs.r12 = r12;
+    ctrl->regs.r13 = r13;
+    ctrl->regs.r14 = r14;
+    ctrl->regs.r15 = r15;
+}
+
+static inline void
+vmload (lpaddr_t vmcb) {
+    __asm volatile ("vmload" : : "a" (vmcb) : "memory");
+}
+
+static inline void
+vmsave (lpaddr_t vmcb) {
+    __asm volatile ("vmsave" : : "a" (vmcb) : "memory");
+}
+
+static inline void
+vmkit_switch_to (struct dcb *dcb)
+{
+    assert(dcb != NULL);
+    assert(dcb->is_vm_guest);
+
+    // save the host state
+    vmsave(mem_to_local_phys((lvaddr_t)host_vmcb));
+    // load the guest state
+    vmload(gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base));
+}
+
+static inline void
+vmkit_switch_from (struct dcb *dcb)
+{
+    assert(dcb != NULL);
+    assert(dcb->is_vm_guest);
+
+    // save the guest state
+    vmsave(gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base));
+    // load the host state
+    vmload(mem_to_local_phys((lvaddr_t)host_vmcb));
+}
+
+struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
+                          uint64_t *args, uint64_t rflags, uint64_t rip);
+
+extern uint64_t user_stack_save;
+
+void __attribute__ ((noreturn))
+svm_vmkit_vmenter (struct dcb *dcb)
+{
+    lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
+    struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
+
+    assert(dcb != NULL);
+    assert(dcb->vspace != 0);
+    assert(dcb->is_vm_guest);
+
+    lpaddr = gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base);
+    amd_vmcb_t vmcb;
+    amd_vmcb_initialize(&vmcb, (void *)local_phys_to_mem(lpaddr));
+
+    /* We need to set the page translation mode. If nested paging is disabled
+     * then we need to set the guest cr3 to the value of the domains vspace. If
+     * nested paging is enabled then we need to copy the domains vspace into the
+     * ncr3 field of the vmcb. */
+    if (amd_vmcb_np_rd(&vmcb).enable) {
+        amd_vmcb_ncr3_wr(&vmcb, dcb->vspace);
+    } else {
+        amd_vmcb_cr3_wr(&vmcb, dcb->vspace);
+    }
+
+ svm_vmenter_loop:
+
+    /* printf("vmenter IN\n"); */
+
+    // Enter the guest
+    vmkit_switch_to(dcb);
+    vm_exec(dcb);
+    vmkit_switch_from(dcb);
+
+    /* printf("vmenter OUT\n"); */
+
+    // Here we exited the guest due to some intercept triggered a vm exit
+    // our state is automatically restored by SVM
+
+    uint64_t ec = amd_vmcb_exitcode_rd(&vmcb);
+
+    /* We treat exits due to pysical interrupts (INTR, NMI, SMI) specially since
+     * they need to be processed by the kernel interrupt service routines */
+    switch(ec) {
+    case VMEXIT_INTR:
+    case VMEXIT_NMI:
+    case VMEXIT_SMI:
+      {
+       arch_registers_state_t *area = NULL;
+
+       /* printf("INT at %" PRIx64 "\n", amd_vmcb_rip_rd(&vmcb)); */
+
+        ctrl->num_vm_exits_without_monitor_invocation++;
+
+       // Store user state into corresponding save area
+       if(dispatcher_is_disabled_ip(dcb->disp, amd_vmcb_rip_rd(&vmcb))) {
+         area = dispatcher_get_disabled_save_area(dcb->disp);
+         dcb->disabled = true;
+       } else {
+         area = dispatcher_get_enabled_save_area(dcb->disp);
+         dcb->disabled = false;
+       }
+       memcpy(area, &ctrl->regs, sizeof(arch_registers_state_t));
+       area->rax = amd_vmcb_rax_rd(&vmcb);
+       area->rip = amd_vmcb_rip_rd(&vmcb);
+       area->rsp = amd_vmcb_rsp_rd(&vmcb);
+       area->eflags = amd_vmcb_rflags_rd_raw(&vmcb);
+       area->fs = amd_vmcb_fs_selector_rd(&vmcb);
+       area->gs = amd_vmcb_gs_selector_rd(&vmcb);
+
+        // wait for interrupt will enable interrupts and therefore trigger their
+        // corresponding handlers (which may be the monitor)
+        wait_for_interrupt();
+      }
+      break;
+
+    case VMEXIT_VMMCALL:
+      {
+       // Translate this to a SYSCALL
+       struct registers_x86_64 *regs = &ctrl->regs;
+       uint64_t args[10] = {
+         regs->r10, regs->r8, regs->r9, regs->r12, regs->r13, regs->r14,
+         regs->r15, amd_vmcb_rax_rd(&vmcb), regs->rbp, regs->rbx
+       };
+
+       /* printf("VMMCALL\n"); */
+
+       // Advance guest RIP to next instruction
+       amd_vmcb_rip_wr(&vmcb, amd_vmcb_rip_rd(&vmcb) + 3);
+       user_stack_save = amd_vmcb_rsp_rd(&vmcb);
+
+       struct sysret ret =
+         sys_syscall(regs->rdi, regs->rsi, regs->rdx, args,
+                     amd_vmcb_rflags_rd_raw(&vmcb),
+                     amd_vmcb_rip_rd(&vmcb));
+
+       amd_vmcb_rax_wr(&vmcb, ret.error);
+       regs->rdx = ret.value;
+      }
+      goto svm_vmenter_loop;
+
+    default:
+        ctrl->num_vm_exits_with_monitor_invocation++;
+        /* the guest exited not due to an interrupt but some condition the
+         * monitor has to handle, therefore notify the monitor */
+
+       /* printf("OTHER\n"); */
+
+        assert(dcb->is_vm_guest);
+
+        // disable the domain
+        scheduler_remove(dcb);
+
+        // call the monitor
+        errval_t err = lmp_deliver_notification(&dcb->guest_desc.monitor_ep.cap);
+        if (err_is_fail(err)) {
+            printk(LOG_ERR, "Unexpected error delivering VMEXIT");
+        }
+
+        // run the monitor
+        dispatch(dcb->guest_desc.monitor_ep.cap.u.endpoint.listener);
+       break;
+    }
+}
index 75bd149..8dd82b3 100644 (file)
@@ -481,6 +481,41 @@ static struct sysret handle_frame_identify(struct capability *to,
     };
 }
 
+static struct sysret handle_vnode_identify(struct capability *to,
+                                          int cmd, uintptr_t *args)
+{
+    // Return with physical base address of the VNode
+    // XXX: pack type into bottom bits of base address
+    assert(to->type == ObjType_VNode_x86_64_pml4 ||
+          to->type == ObjType_VNode_x86_64_pdpt ||
+          to->type == ObjType_VNode_x86_64_pdir ||
+          to->type == ObjType_VNode_x86_64_ptable);
+    
+    uint64_t base_addr = 0;
+    switch (to->type) {
+    case ObjType_VNode_x86_64_pml4:
+        base_addr = (uint64_t)(to->u.vnode_x86_64_pml4.base);
+       break;
+    case ObjType_VNode_x86_64_pdpt:
+       base_addr = (uint64_t)(to->u.vnode_x86_64_pdpt.base);
+       break;
+    case ObjType_VNode_x86_64_pdir:
+       base_addr = (uint64_t)(to->u.vnode_x86_64_pdir.base);
+       break;
+    case ObjType_VNode_x86_64_ptable:
+       base_addr = (uint64_t)(to->u.vnode_x86_64_ptable.base);
+       break;
+    default:
+        break;
+    }
+    assert((base_addr & BASE_PAGE_MASK) == 0);
+
+    return (struct sysret) {
+        .error = SYS_ERR_OK,
+        .value = (genpaddr_t)base_addr | ((uint8_t)to->type),
+    };
+}
+
 static struct sysret handle_frame_modify_flags(struct capability *to,
                                                int cmd, uintptr_t *args)
 {
@@ -502,6 +537,7 @@ static struct sysret handle_frame_modify_flags(struct capability *to,
     };
 }
 
+
 static struct sysret handle_io(struct capability *to, int cmd, uintptr_t *args)
 {
     uint64_t    port = args[0];
@@ -510,6 +546,70 @@ static struct sysret handle_io(struct capability *to, int cmd, uintptr_t *args)
     return sys_io(to, cmd, port, data);
 }
 
+static struct sysret handle_vmread(struct capability *to, 
+                                  int cmd, uintptr_t *args) 
+{
+#ifdef CONFIG_SVM
+    return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
+#else
+    errval_t err;
+    struct dcb *dcb = to->u.dispatcher.dcb;
+    lpaddr_t vmcs_base = dcb->guest_desc.vmcb.cap.u.frame.base;
+    if (vmcs_base != vmptrst()) {
+        err = SYS_ERR_VMKIT_VMX_VMFAIL_INVALID;
+    } else {
+        err = vmread(args[0], (lvaddr_t *)args[1]);
+    }
+    return SYSRET(err);
+#endif
+}
+
+static struct sysret handle_vmwrite(struct capability *to, 
+                                   int cmd, uintptr_t *args) 
+{
+#ifdef CONFIG_SVM
+    return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
+#else
+    errval_t err;
+    struct dcb *dcb = to->u.dispatcher.dcb;
+    lpaddr_t vmcs_base = dcb->guest_desc.vmcb.cap.u.frame.base;
+    if (vmcs_base != vmptrst()) {
+        err = SYS_ERR_VMKIT_VMX_VMFAIL_INVALID;
+    } else {
+        err = vmwrite(args[0], args[1]);
+    }
+    return SYSRET(err);
+#endif
+}
+
+static struct sysret handle_vmptrld(struct capability *to, 
+                                   int cmd, uintptr_t *args) 
+{
+#ifdef CONFIG_SVM
+    return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
+#else
+    errval_t err;
+    struct dcb *dcb = to->u.dispatcher.dcb;
+    lpaddr_t vmcs_base = dcb->guest_desc.vmcb.cap.u.frame.base;
+    err = vmptrld(vmcs_base);
+    return SYSRET(err);
+#endif
+}
+
+static struct sysret handle_vmclear(struct capability *to, 
+                                   int cmd, uintptr_t *args) 
+{
+#ifdef CONFIG_SVM
+    return SYSRET(SYS_ERR_VMKIT_UNAVAIL);
+#else
+    errval_t err;
+    struct dcb *dcb = to->u.dispatcher.dcb;
+    lpaddr_t vmcs_base = dcb->guest_desc.vmcb.cap.u.frame.base;
+    err = vmclear(vmcs_base);
+    return SYSRET(err);
+#endif
+}
+
 #ifndef __k1om__
 static struct sysret
 handle_dispatcher_setup_guest (struct capability *to, int cmd, uintptr_t *args)
@@ -590,6 +690,13 @@ handle_dispatcher_setup_guest (struct capability *to, int cmd, uintptr_t *args)
         return SYSRET(err_push(err, SYS_ERR_VMKIT_CTRL));
     }
 
+#ifndef CONFIG_SVM
+    // Initialize VMCS for the single virtual-CPU here instead of in 
+    // userspace, where the privilege level is not 0.
+    err = initialize_vmcs(vmcb_cte->cap.u.frame.base);
+    assert(err_is_ok(err));
+#endif
+
     // 2. Set up the target DCB
 /*     dcb->guest_desc.monitor_ep = ep_cap; */
     dcb->vspace = vnode_cap->u.vnode_x86_64_pml4.base;
@@ -928,6 +1035,10 @@ static invocation_handler_t invocations[ObjType_Num][CAP_MAX_CMD] = {
 #endif
         [DispatcherCmd_DumpPTables]  = dispatcher_dump_ptables,
         [DispatcherCmd_DumpCapabilities] = dispatcher_dump_capabilities
+       [DispatcherCmd_Vmread] = handle_vmread,
+       [DispatcherCmd_Vmwrite] = handle_vmwrite,
+       [DispatcherCmd_Vmptrld] = handle_vmptrld,
+       [DispatcherCmd_Vmclear] = handle_vmclear,
     },
     [ObjType_KernelControlBlock] = {
         [FrameCmd_Identify] = handle_kcb_identify,
@@ -950,18 +1061,22 @@ static invocation_handler_t invocations[ObjType_Num][CAP_MAX_CMD] = {
         [CNodeCmd_GetState] = handle_get_state,
     },
     [ObjType_VNode_x86_64_pml4] = {
+        [VNodeCmd_Identify] = handle_vnode_identify,
         [VNodeCmd_Map]   = handle_map,
         [VNodeCmd_Unmap] = handle_unmap,
     },
     [ObjType_VNode_x86_64_pdpt] = {
+        [VNodeCmd_Identify] = handle_vnode_identify,
         [VNodeCmd_Map]   = handle_map,
         [VNodeCmd_Unmap] = handle_unmap,
     },
     [ObjType_VNode_x86_64_pdir] = {
+        [VNodeCmd_Identify] = handle_vnode_identify,
         [VNodeCmd_Map]   = handle_map,
         [VNodeCmd_Unmap] = handle_unmap,
     },
     [ObjType_VNode_x86_64_ptable] = {
+        [VNodeCmd_Identify] = handle_vnode_identify,
         [VNodeCmd_Map]   = handle_map,
         [VNodeCmd_Unmap] = handle_unmap,
     },
@@ -1142,12 +1257,19 @@ struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
                         );
                } else {
 #ifndef __k1om__
+#ifdef CONFIG_SVM
                  lpaddr_t lpaddr = gen_phys_to_local_phys(dcb_current->guest_desc.vmcb.cap.u.frame.base);
                  amd_vmcb_t vmcb;
                  amd_vmcb_initialize(&vmcb, (void *)local_phys_to_mem(lpaddr));
                  save_area->fs = amd_vmcb_fs_selector_rd(&vmcb);
                  save_area->gs = amd_vmcb_gs_selector_rd(&vmcb);
 #else
+                  errval_t err;
+                  err = vmread(VMX_GUEST_FS_SEL, (uint64_t *)&save_area->fs);
+                  err += vmread(VMX_GUEST_GS_SEL, (uint64_t *)&save_area->gs);
+                  assert(err_is_ok(err));
+#endif
+#else
           panic("VM Guests not supported on Xeon Phi");
 #endif
                }
index 4f6ad5e..fcf30fb 100644 (file)
 
 #include <dev/amd_vmcb_dev.h>
 
-// SVM relevant CPUID info
-#define CPUID_AMD_EXTFEAT       0x80000001
-#define AMD_EXTFEAT_ECX_SVM     (1 << 2)
-
-// some EXITCODE values
-#define VMEXIT_INTR     0x60
-#define VMEXIT_NMI      0x61
-#define VMEXIT_SMI      0x62
-#define VMEXIT_VMMCALL  0x81
-
-/**
- * \brief The storage area where SVM puts the host state during guest exec.
- */
-static uint8_t host_save_area[BASE_PAGE_SIZE]
-__attribute__ ((aligned(BASE_PAGE_SIZE)));
-
-/**
- * \brief VMCB for the host to save its state.
- */
-static uint8_t host_vmcb[BASE_PAGE_SIZE]
-__attribute__ ((aligned(BASE_PAGE_SIZE)));
-
-static void
-vmkit_init (void)
-{
-    static bool executed = false;
-
-    if (executed) {
-        return;
-    }
-
-    executed = true;
-    memset(host_save_area, 0x0, BASE_PAGE_SIZE);
-    memset(host_vmcb, 0x0, BASE_PAGE_SIZE);
-}
-
-/**
- * \brief Tries to enable hardware assisted virtualization.
- *
- * Checks whether hardware assisted virtualization is available on the platform
- * and enables this feature.
- *
- * \Return Returns VMKIT_ERR_OK on successful initialization of the subsystem
- *         or VMKIT_ERR_UNAVAIL if virtualization is unavailable.
- */
 errval_t
 vmkit_enable_virtualization (void)
 {
-    vmkit_init ();
-
-    // first check what CPUID tells us about SVM support
-    uint32_t cpuid_ecx;
-    cpuid(CPUID_AMD_EXTFEAT, NULL, NULL, &cpuid_ecx, NULL);
-    if (!(cpuid_ecx & AMD_EXTFEAT_ECX_SVM)) {
-        return SYS_ERR_VMKIT_UNAVAIL;
-    }
-
-    // check whether SVM support is deactivated
-    uint64_t msr_vmcr = rdmsr(MSR_AMD_VMCR);
-    if (msr_vmcr & AMD_VMCR_SVMDIS) {
-        return SYS_ERR_VMKIT_UNAVAIL;
-    }
-
-    // from here on we assume that SVM is avail and may be enabled
-
-    // check whether SVM is already enabled
-    uint64_t msr_efer = rdmsr(MSR_IA32_EFER);
-    if (msr_efer & IA32_EFER_SVME) {
-        // SVM is already enabled
-        return SYS_ERR_OK;
-    }
-    // enable SVM
-    addmsr(MSR_IA32_EFER, IA32_EFER_SVME);
-    // check whether SVM is now enabled
-    msr_efer = rdmsr(MSR_IA32_EFER);
-    if (msr_efer & IA32_EFER_SVME) {
-        // SVM enabled
-        // set the host save area
-        wrmsr(MSR_AMD_VM_HSAVE, mem_to_local_phys((lvaddr_t)host_save_area));
-        return SYS_ERR_OK;
-    } else {
-        printk(LOG_WARN, "VMKit: Unable to enable SVM although the hardware "
-               "claims to support it.\n");
-        return SYS_ERR_VMKIT_UNAVAIL;
-    }
-}
-
-static inline void
-vm_exec (struct dcb *dcb)
-{
-    lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
-    struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
-    register uintptr_t rbx __asm("rbx") = ctrl->regs.rbx;
-    register uintptr_t rcx __asm("rcx") = ctrl->regs.rcx;
-    register uintptr_t rdx __asm("rdx") = ctrl->regs.rdx;
-    register uintptr_t rsi __asm("rsi") = ctrl->regs.rsi;
-    register uintptr_t rdi __asm("rdi") = ctrl->regs.rdi;
-    register uintptr_t r8  __asm("r8")  = ctrl->regs.r8;
-    register uintptr_t r9  __asm("r9")  = ctrl->regs.r9;
-    register uintptr_t r10 __asm("r10") = ctrl->regs.r10;
-    register uintptr_t r11 __asm("r11") = ctrl->regs.r11;
-    register uintptr_t r12 __asm("r12") = ctrl->regs.r12;
-    register uintptr_t r13 __asm("r13") = ctrl->regs.r13;
-    register uintptr_t r14 __asm("r14") = ctrl->regs.r14;
-    register uintptr_t r15 __asm("r15") = ctrl->regs.r15;
-#ifdef NDEBUG
-    register uintptr_t rbp __asm("rbp") = ctrl->regs.rbp;
-
-    __asm volatile ("sti\n\t"       // allow intr to happen inside the host
-                    "vmrun %%rax\n\t"     // execute the guest
-                    "cli\n\t"       // disable intr in the host again
-                    "stgi\n\t"      // enable the global intr flag
-        : "+r" (rbx), "+r" (rcx), "+r" (rdx), "+r" (rbp), "+r" (rsi), "+r" (rdi),
-          "+r" (r8), "+r" (r9), "+r" (r10), "+r" (r11), "+r" (r12), "+r" (r13),
-          "+r" (r14), "+r" (r15)
-        : "a" (dcb->guest_desc.vmcb.cap.u.frame.base)
-        : "memory");
+#ifdef CONFIG_SVM
+    return svm_enable_virtualization();
 #else
-    static uintptr_t rbp, srbp;
-
-    rbp = ctrl->regs.rbp;
-
-    __asm volatile ("mov %%rbp, %[srbp]\n\t" :: [srbp] "m" (srbp));
-
-    __asm volatile ("mov %[nrbp], %%rbp\n\t"
-                    "sti\n\t"       // allow intr to happen inside the host
-                    "vmrun %%rax\n\t"     // execute the guest
-                    "cli\n\t"       // disable intr in the host again
-                    "stgi\n\t"      // enable the global intr flag
-                    "mov %%rbp, %[nrbp]\n\t"
-        : "+r" (rbx), "+r" (rcx), "+r" (rdx), [nrbp] "+m" (rbp),
-                    "+r" (rsi), "+r" (rdi), "+r" (r8), "+r" (r9), "+r" (r10),
-                    "+r" (r11), "+r" (r12), "+r" (r13), "+r" (r14), "+r" (r15)
-        : "a" (dcb->guest_desc.vmcb.cap.u.frame.base)
-        : "memory");
-
-    __asm volatile ("mov %[srbp], %%rbp\n\t"
-                    : [srbp] "+m" (srbp));
+    return vmx_enable_virtualization();
 #endif
-
-    ctrl->regs.rbx = rbx;
-    ctrl->regs.rcx = rcx;
-    ctrl->regs.rdx = rdx;
-    ctrl->regs.rbp = rbp;
-    ctrl->regs.rsi = rsi;
-    ctrl->regs.rdi = rdi;
-    ctrl->regs.r8 = r8;
-    ctrl->regs.r9 = r9;
-    ctrl->regs.r10 = r10;
-    ctrl->regs.r11 = r11;
-    ctrl->regs.r12 = r12;
-    ctrl->regs.r13 = r13;
-    ctrl->regs.r14 = r14;
-    ctrl->regs.r15 = r15;
-}
-
-static inline void
-vmload (lpaddr_t vmcb) {
-    __asm volatile ("vmload %%rax" : : "a" (vmcb) : "memory");
-}
-
-static inline void
-vmsave (lpaddr_t vmcb) {
-    __asm volatile ("vmsave %%rax" : : "a" (vmcb) : "memory");
-}
-
-static inline void
-vmkit_switch_to (struct dcb *dcb)
-{
-    assert(dcb != NULL);
-    assert(dcb->is_vm_guest);
-
-    // save the host state
-    vmsave(mem_to_local_phys((lvaddr_t)host_vmcb));
-    // load the guest state
-    vmload(gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base));
-}
-
-static inline void
-vmkit_switch_from (struct dcb *dcb)
-{
-    assert(dcb != NULL);
-    assert(dcb->is_vm_guest);
-
-    // save the guest state
-    vmsave(gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base));
-    // load the host state
-    vmload(mem_to_local_phys((lvaddr_t)host_vmcb));
 }
 
 void __attribute__ ((noreturn))
 vmkit_vmexec (struct dcb *dcb, lvaddr_t entry)
 {
-  dispatcher_handle_t handle = dcb->disp;
-  struct dispatcher_shared_generic *disp = get_dispatcher_shared_generic(handle);
-  lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
-  struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
-  lpaddr = gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base);
-  amd_vmcb_t vmcb;
-  amd_vmcb_initialize(&vmcb, (void *)local_phys_to_mem(lpaddr));
-
-  memset(&ctrl->regs, 0, sizeof(struct registers_x86_64));
-  ctrl->regs.rdi = disp->udisp;
-  amd_vmcb_rip_wr(&vmcb, disp->dispatcher_run);
-  amd_vmcb_rsp_wr(&vmcb, 0);
-  amd_vmcb_rax_wr(&vmcb, 0);
-  amd_vmcb_rflags_wr_raw(&vmcb, USER_RFLAGS);
-  amd_vmcb_fs_selector_wr(&vmcb, 0);
-  amd_vmcb_gs_selector_wr(&vmcb, 0);
-  vmkit_vmenter(dcb);
-}
-
-struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
-                          uint64_t *args, uint64_t rflags, uint64_t rip);
-
-extern uint64_t user_stack_save;
-
-void __attribute__ ((noreturn))
-vmkit_vmenter (struct dcb *dcb)
-{
+    dispatcher_handle_t handle = dcb->disp;
+    struct dispatcher_shared_generic *disp = get_dispatcher_shared_generic(handle);
     lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
     struct guest_control *ctrl = (void *)local_phys_to_mem(lpaddr);
-
-    assert(dcb != NULL);
-    assert(dcb->vspace != 0);
-    assert(dcb->is_vm_guest);
-
+    memset(&ctrl->regs, 0, sizeof(struct registers_x86_64));
+    ctrl->regs.rdi = disp->udisp;
+#ifdef CONFIG_SVM
     lpaddr = gen_phys_to_local_phys(dcb->guest_desc.vmcb.cap.u.frame.base);
     amd_vmcb_t vmcb;
     amd_vmcb_initialize(&vmcb, (void *)local_phys_to_mem(lpaddr));
 
-    /* We need to set the page translation mode. If nested paging is disabled
-     * then we need to set the guest cr3 to the value of the domains vspace. If
-     * nested paging is enabled then we need to copy the domains vspace into the
-     * ncr3 field of the vmcb. */
-    if (amd_vmcb_np_rd(&vmcb).enable) {
-        amd_vmcb_ncr3_wr(&vmcb, dcb->vspace);
-    } else {
-        amd_vmcb_cr3_wr(&vmcb, dcb->vspace);
-    }
-
- vmenter_loop:
-
-    /* printf("vmenter IN\n"); */
-
-    // Enter the guest
-    vmkit_switch_to(dcb);
-    vm_exec(dcb);
-    vmkit_switch_from(dcb);
-
-    /* printf("vmenter OUT\n"); */
-
-    // Here we exited the guest due to some intercept triggered a vm exit
-    // our state is automatically restored by SVM
-
-    uint64_t ec = amd_vmcb_exitcode_rd(&vmcb);
-    /* We treat exits due to pysical interrupts (INTR, NMI, SMI) specially since
-     * they need to be processed by the kernel interrupt service routines */
-    switch(ec) {
-    case VMEXIT_INTR:
-    case VMEXIT_NMI:
-    case VMEXIT_SMI:
-      {
-       arch_registers_state_t *area = NULL;
-
-       /* printf("INT at %" PRIx64 "\n", amd_vmcb_rip_rd(&vmcb)); */
-
-        ctrl->num_vm_exits_without_monitor_invocation++;
-
-       // Store user state into corresponding save area
-       if(dispatcher_is_disabled_ip(dcb->disp, amd_vmcb_rip_rd(&vmcb))) {
-         area = dispatcher_get_disabled_save_area(dcb->disp);
-         dcb->disabled = true;
-       } else {
-         area = dispatcher_get_enabled_save_area(dcb->disp);
-         dcb->disabled = false;
-       }
-       memcpy(area, &ctrl->regs, sizeof(arch_registers_state_t));
-       area->rax = amd_vmcb_rax_rd(&vmcb);
-       area->rip = amd_vmcb_rip_rd(&vmcb);
-       area->rsp = amd_vmcb_rsp_rd(&vmcb);
-       area->eflags = amd_vmcb_rflags_rd_raw(&vmcb);
-       area->fs = amd_vmcb_fs_selector_rd(&vmcb);
-       area->gs = amd_vmcb_gs_selector_rd(&vmcb);
-
-        // wait for interrupt will enable interrupts and therefore trigger their
-        // corresponding handlers (which may be the monitor)
-        wait_for_interrupt();
-      }
-      break;
-
-    case VMEXIT_VMMCALL:
-      {
-       // Translate this to a SYSCALL
-       struct registers_x86_64 *regs = &ctrl->regs;
-       uint64_t args[10] = {
-         regs->r10, regs->r8, regs->r9, regs->r12, regs->r13, regs->r14,
-         regs->r15, amd_vmcb_rax_rd(&vmcb), regs->rbp, regs->rbx
-       };
-
-       /* printf("VMMCALL\n"); */
-
-       // Advance guest RIP to next instruction
-       amd_vmcb_rip_wr(&vmcb, amd_vmcb_rip_rd(&vmcb) + 3);
-       user_stack_save = amd_vmcb_rsp_rd(&vmcb);
-
-       struct sysret ret =
-         sys_syscall(regs->rdi, regs->rsi, regs->rdx, args,
-                     amd_vmcb_rflags_rd_raw(&vmcb),
-                     amd_vmcb_rip_rd(&vmcb));
-
-       amd_vmcb_rax_wr(&vmcb, ret.error);
-       regs->rdx = ret.value;
-      }
-      goto vmenter_loop;
-
-    default:
-        ctrl->num_vm_exits_with_monitor_invocation++;
-        /* the guest exited not due to an interrupt but some condition the
-         * monitor has to handle, therefore notify the monitor */
-
-       /* printf("OTHER\n"); */
-
-        assert(dcb->is_vm_guest);
-
-        // disable the domain
-        scheduler_remove(dcb);
-
-        // call the monitor
-        errval_t err = lmp_deliver_notification(&dcb->guest_desc.monitor_ep.cap);
-        if (err_is_fail(err)) {
-            printk(LOG_ERR, "Unexpected error delivering VMEXIT");
-        }
+    amd_vmcb_rip_wr(&vmcb, disp->dispatcher_run);
+    amd_vmcb_rsp_wr(&vmcb, 0);
+    amd_vmcb_rax_wr(&vmcb, 0);
+    amd_vmcb_rflags_wr_raw(&vmcb, USER_RFLAGS);
+    amd_vmcb_fs_selector_wr(&vmcb, 0);
+    amd_vmcb_gs_selector_wr(&vmcb, 0);
+    svm_vmkit_vmenter(dcb);
+#else
+    vmwrite(VMX_GUEST_RIP, disp->dispatcher_run);
+    vmwrite(VMX_GUEST_RSP, 0);
+    vmwrite(VMX_GUEST_RFLAGS, USER_RFLAGS);    
+    vmwrite(VMX_GUEST_FS_SEL, 0);
+    vmwrite(VMX_GUEST_GS_SEL, 0);
+    vmx_vmkit_vmenter(dcb);
+#endif
+}
 
-        // run the monitor
-        dispatch(dcb->guest_desc.monitor_ep.cap.u.endpoint.listener);
-       break;
-    }
+void __attribute__ ((noreturn))
+vmkit_vmenter (struct dcb *dcb)
+{
+#ifdef CONFIG_SVM
+    svm_vmkit_vmenter(dcb);
+#else
+    vmx_vmkit_vmenter(dcb);
+#endif
 }
diff --git a/kernel/arch/x86_64/vmx_checks.c b/kernel/arch/x86_64/vmx_checks.c
new file mode 100644 (file)
index 0000000..eaee702
--- /dev/null
@@ -0,0 +1,1326 @@
+/**
+ * \file
+ * \brief Before entry into a VM-guest commences, the state of logical processor
+ *  and VMCS are checked to ensure that the following will transpire successfully:
+ * 
+ *  - entry into the guest
+ *  - VMX non-root operation after entry
+ *  - exit from the guest  
+ *
+ * The guest-state area, host-state area, and VMX controls are checked using these
+ * functions to guarantee that these tests pass.
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+#include <vmkit.h>
+#include <vmx_checks.h>
+
+#include <dev/ia32_dev.h>
+
+static bool ia32e_guest, unrestricted_guest;
+
+static inline bool is_within_pa_width(uint64_t addr) 
+{
+    uint64_t phys_addr_width_mask = pa_width_mask();
+    return ((addr & ~phys_addr_width_mask) == 0);
+}
+
+static inline void check_guest_cr0(void)
+{
+    uint64_t pp_controls;
+    errval_t err = vmread(VMX_EXEC_PRIM_PROC, &pp_controls);
+
+    uint64_t cr0_fixed0 = ia32_vmx_cr0_fixed0_rd(NULL);
+    uint64_t cr0_fixed1 = ia32_vmx_cr0_fixed1_rd(NULL);
+    
+    // CR0.NW and CR0.CD are not changed by VM entry, so are not checked
+    cr0_fixed0 &= ~(CR0_NW | CR0_CD);
+    if (unrestricted_guest) {
+        bool sec_ctls_set = sec_ctls_used(pp_controls);
+        assert(sec_ctls_set == true);
+       cr0_fixed0 &= ~(CR0_PE | CR0_PG);
+    } 
+
+    uint64_t guest_cr0;
+    err += vmread(VMX_GUEST_CR0, &guest_cr0);
+    assert(err_is_ok(err));
+    assert(((guest_cr0 | cr0_fixed0) & cr0_fixed1) == guest_cr0);
+
+    if (guest_cr0 & CR0_PG) {
+        assert(guest_cr0 & CR0_PE);
+    }
+
+    if (ia32e_guest) {
+        assert(guest_cr0 & CR0_PG);
+    }
+}
+
+static inline void check_guest_cr3(void)
+{
+    uint64_t guest_cr3;
+    errval_t err = vmread(VMX_GUEST_CR3, &guest_cr3);
+    assert(err_is_ok(err));
+    bool within_pa_width = is_within_pa_width(guest_cr3);
+    assert(within_pa_width);
+}
+
+static inline void check_guest_cr4(void)
+{
+    uint64_t guest_cr4;
+    errval_t err = vmread(VMX_GUEST_CR4, &guest_cr4);
+    assert(err_is_ok(err));
+    uint32_t cr4_fixed0 = ia32_vmx_cr4_fixed0_rd(NULL);
+    uint32_t cr4_fixed1 = ia32_vmx_cr4_fixed1_rd(NULL);
+    assert(((guest_cr4 | cr4_fixed0) & cr4_fixed1) == guest_cr4);
+
+    if (ia32e_guest) {
+        assert(guest_cr4 & CR4_PAE);
+    } else {
+        assert((guest_cr4 & CR4_PCIDE) == 0);
+    }
+}
+
+static inline void check_guest_efer(void)
+{
+    uint64_t entry_controls;
+    errval_t err = vmread(VMX_ENTRY_CONTROLS, &entry_controls);
+
+    if (entry_controls & ENTRY_CLTS_LOAD_EFER) {
+        uint64_t guest_efer;
+       err += vmread(VMX_GUEST_EFER_F, &guest_efer);
+
+       // Bits reserved must be set to 0:
+       
+       // Bits 1:7
+       assert(((guest_efer >> 1) & 0x7F) == 0);
+       // Bit 9
+       assert(((guest_efer >> 9) & 0x1) == 0);
+       // Bits 12:63
+       assert((guest_efer & ~0xFFF) == 0);
+       
+        uint64_t guest_cr0;
+       err += vmread(VMX_GUEST_CR0, &guest_cr0);
+
+       bool lma_set = !!(guest_efer & EFER_LMA); 
+       assert(lma_set == ia32e_guest);
+       
+       if (guest_cr0 & CR0_PG) {
+           bool lme_set = !!(guest_efer & EFER_LME);
+           assert(lma_set == lme_set);
+       }
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_control_registers(void)
+{
+    check_guest_cr0();
+    check_guest_cr3();
+    check_guest_cr4();    
+}
+
+static void check_guest_seg_sel(void)
+{
+    // TR
+    uint64_t tr_sel;
+    errval_t err = vmread(VMX_GUEST_TR_SEL, &tr_sel);
+    assert((tr_sel & SEL_TI) == 0);
+
+    // LDTR
+    uint64_t ldtr_access_rights, ldtr_sel;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    err += vmread(VMX_GUEST_LDTR_SEL, &ldtr_sel);
+    if (seg_reg_usable(ldtr_access_rights)) {
+        assert((ldtr_sel & SEL_TI) == 0);
+    }
+    
+    // SS
+    // The guest will not be in virtual-8086 mode
+    if (!unrestricted_guest) {
+        uint64_t ss_sel, cs_sel;
+       err += vmread(VMX_GUEST_SS_SEL, &ss_sel);
+       err += vmread(VMX_GUEST_CS_SEL, &cs_sel);
+        int ss_rpl = (ss_sel & SEL_RPL);
+       int cs_rpl = (cs_sel & SEL_RPL);
+       assert(ss_rpl == cs_rpl);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_base(void)
+{
+    // TR, FS, GS
+    uint64_t tr_base, fs_base, gs_base;
+    errval_t err = vmread(VMX_GUEST_TR_BASE, &tr_base);
+    err += vmread(VMX_GUEST_FS_BASE, &fs_base);
+    err += vmread(VMX_GUEST_GS_BASE, &gs_base);
+    bool tr_base_canonical = is_canonical(tr_base);
+    assert(tr_base_canonical);
+
+    bool fs_base_canonical = is_canonical(fs_base);
+    assert(fs_base_canonical);
+
+    bool gs_base_canonical = is_canonical(gs_base);
+    assert(gs_base_canonical);
+
+    // LDTR
+    uint64_t ldtr_access_rights;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    if (seg_reg_usable(ldtr_access_rights)) {
+        uint64_t ldtr_base;
+       err += vmread(VMX_GUEST_LDTR_BASE, &ldtr_base);
+       bool ldtr_base_canonical = is_canonical(ldtr_base);
+       assert(ldtr_base_canonical);
+    }
+
+    // CS
+    uint64_t cs_base;
+    err += vmread(VMX_GUEST_CS_BASE, &cs_base);
+    assert((cs_base & ~0xFFFFFFFF) == 0);
+
+    // SS, DS, ES
+    uint64_t ss_access_rights, ds_access_rights, es_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    err += vmread(VMX_GUEST_ES_ACCESS, &es_access_rights);
+
+    if (seg_reg_usable(ss_access_rights)) {
+        uint64_t ss_base;
+       err += vmread(VMX_GUEST_SS_BASE, &ss_base);
+       bool ss_base_canonical = is_canonical(ss_base);
+       assert(ss_base_canonical);
+    }
+
+    if (seg_reg_usable(ds_access_rights)) {
+        uint64_t ds_base;
+       err += vmread(VMX_GUEST_DS_BASE, &ds_base);
+       bool ds_base_canonical = is_canonical(ds_base);
+       assert(ds_base_canonical);
+    }
+
+    if (seg_reg_usable(es_access_rights)) {
+        uint64_t es_base;
+       err += vmread(VMX_GUEST_ES_BASE, &es_base);
+       bool es_base_canonical = is_canonical(es_base);
+       assert(es_base_canonical);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_access_type(void) 
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_type = seg_access_type(cs_access_rights);
+    if (unrestricted_guest) {
+        assert(cs_type == 3 || cs_type == 9 || cs_type == 11 || 
+              cs_type == 13 || cs_type == 15);
+    } else {
+        assert(cs_type == 9 || cs_type == 11 || cs_type == 13 || 
+              cs_type == 15);
+    }
+
+    // SS
+    uint64_t ss_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    if (seg_reg_usable(ss_access_rights)) {
+        int ss_type = seg_access_type(ss_access_rights);
+       assert(ss_type == 3 || ss_type == 7);
+    }
+
+    // DS
+    uint64_t ds_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    if (seg_reg_usable(ds_access_rights)) {
+        int ds_type = seg_access_type(ds_access_rights);
+       assert(ds_type & SEG_TYPE_ACCESSED); 
+       if (ds_type & SEG_TYPE_CODE_SEGMENT) {
+           assert(ds_type & SEG_TYPE_READABLE);
+       }
+    }
+
+    // ES
+    uint64_t es_access_rights;
+    err += vmread(VMX_GUEST_ES_ACCESS, &es_access_rights);
+    if (seg_reg_usable(es_access_rights)) {
+        int es_type = seg_access_type(es_access_rights);
+       assert(es_type & SEG_TYPE_ACCESSED); 
+       if (es_type & SEG_TYPE_CODE_SEGMENT) {
+           assert(es_type & SEG_TYPE_READABLE);
+       }
+    }
+
+    // FS
+    uint64_t fs_access_rights;
+    err += vmread(VMX_GUEST_FS_ACCESS, &fs_access_rights);
+    if (seg_reg_usable(fs_access_rights)) {
+        int fs_type = seg_access_type(fs_access_rights);
+       assert(fs_type & SEG_TYPE_ACCESSED); 
+       if (fs_type & SEG_TYPE_CODE_SEGMENT) {
+           assert(fs_type & SEG_TYPE_READABLE);
+       }
+    }
+
+    // GS
+    uint64_t gs_access_rights;
+    err += vmread(VMX_GUEST_GS_ACCESS, &gs_access_rights);
+    if (seg_reg_usable(gs_access_rights)) {
+        int gs_type = seg_access_type(gs_access_rights);
+       assert(gs_type & SEG_TYPE_ACCESSED); 
+       if (gs_type & SEG_TYPE_CODE_SEGMENT) {
+           assert(gs_type & SEG_TYPE_READABLE);
+       }
+    }
+
+    // TR
+    uint64_t tr_access_rights;
+    err += vmread(VMX_GUEST_TR_ACCESS, &tr_access_rights);
+    int tr_type = seg_access_type(tr_access_rights);
+    if (ia32e_guest) {
+        assert(tr_type == 11);
+    } else {
+        assert(tr_type == 3 || tr_type == 11);
+    }
+
+    // LDTR
+    uint64_t ldtr_access_rights;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    if (seg_reg_usable(ldtr_access_rights)) {
+        int ldtr_type = seg_access_type(ldtr_access_rights);    
+        assert(ldtr_type == 2);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_access_s(void)
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_s = seg_access_s(cs_access_rights);
+    assert(cs_s == 1);
+
+    // SS
+    uint64_t ss_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    if (seg_reg_usable(ss_access_rights)) {
+        int ss_s = seg_access_s(ss_access_rights);
+       assert(ss_s == 1);
+    }
+
+    // DS
+    uint64_t ds_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    if (seg_reg_usable(ds_access_rights)) {
+        int ds_s = seg_access_s(ds_access_rights);
+       assert(ds_s == 1);
+    }
+
+    // ES
+    uint64_t es_access_rights;
+    err += vmread(VMX_GUEST_ES_ACCESS, &es_access_rights);
+    if (seg_reg_usable(es_access_rights)) {
+        int es_s = seg_access_s(es_access_rights);
+       assert(es_s == 1);
+    }
+
+    // FS
+    uint64_t fs_access_rights;
+    err += vmread(VMX_GUEST_FS_ACCESS, &fs_access_rights);
+    if (seg_reg_usable(fs_access_rights)) {
+        int fs_s = seg_access_s(fs_access_rights);
+       assert(fs_s == 1);
+    }
+
+    // GS
+    uint64_t gs_access_rights;
+    err += vmread(VMX_GUEST_GS_ACCESS, &gs_access_rights);
+    if (seg_reg_usable(gs_access_rights)) {
+        int gs_s = seg_access_s(gs_access_rights);
+       assert(gs_s == 1);
+    }
+  
+    // TR
+    uint64_t tr_access_rights;
+    err += vmread(VMX_GUEST_TR_ACCESS, &tr_access_rights);
+    int tr_s = seg_access_s(tr_access_rights);
+    assert(tr_s == 0);
+   
+    // LDTR
+    uint64_t ldtr_access_rights;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    if (seg_reg_usable(ldtr_access_rights)) {
+       int ldtr_s = seg_access_s(ldtr_access_rights);
+       assert(ldtr_s == 0);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_access_dpl(void)
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_dpl = seg_access_dpl(cs_access_rights);
+
+    int cs_type = seg_access_type(cs_access_rights);
+    if (cs_type == 3) {
+       assert(unrestricted_guest);
+       assert(cs_dpl == 0);
+    }
+
+    uint64_t ss_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    int ss_dpl = seg_access_dpl(ss_access_rights);
+
+    if (cs_type == 9 || cs_type == 11) {
+        assert(cs_dpl == ss_dpl);
+    }
+
+    if (cs_type == 13 || cs_type == 15) {
+        assert(cs_dpl <= ss_dpl);
+    }
+
+    // SS
+    if (!unrestricted_guest) {
+        uint64_t ss_sel;
+       err += vmread(VMX_GUEST_SS_SEL, &ss_sel);
+       int ss_rpl = (ss_sel & SEL_RPL);
+       assert(ss_rpl == ss_dpl);
+    }
+
+    uint64_t guest_cr0;
+    err += vmread(VMX_GUEST_CR0, &guest_cr0);
+
+    if (cs_type == 3 || (guest_cr0 & CR0_PE) == 0) {
+        assert(ss_dpl == 0);
+    }
+
+    // DS
+    uint64_t ds_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    bool ds_usable = seg_reg_usable(ds_access_rights);
+    int ds_type = seg_access_type(ds_access_rights);
+
+    if (!unrestricted_guest && ds_usable && (0 <= ds_type && ds_type <= 11)) {
+        uint64_t ds_sel;
+       err += vmread(VMX_GUEST_DS_SEL, &ds_sel);
+       int ds_rpl = (ds_sel & SEL_RPL);
+       int ds_dpl = seg_access_dpl(ds_access_rights);
+
+       assert(ds_dpl >= ds_rpl);
+    }
+
+    // ES
+    uint64_t es_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &es_access_rights);
+    bool es_usable = seg_reg_usable(es_access_rights);
+    int es_type = seg_access_type(es_access_rights);
+
+    if (!unrestricted_guest && es_usable && (0 <= es_type && es_type <= 11)) {
+        uint64_t es_sel;
+       err += vmread(VMX_GUEST_ES_SEL, &es_sel);
+       int es_rpl = (es_sel & SEL_RPL);
+       int es_dpl = seg_access_dpl(es_access_rights);
+
+       assert(es_dpl >= es_rpl);
+    }
+
+    // FS
+    uint64_t fs_access_rights;
+    err += vmread(VMX_GUEST_FS_ACCESS, &fs_access_rights);
+    bool fs_usable = seg_reg_usable(fs_access_rights);
+    int fs_type = seg_access_type(fs_access_rights);
+
+    if (!unrestricted_guest && fs_usable && (0 <= fs_type && fs_type <= 11)) {
+        uint64_t fs_sel;
+       err += vmread(VMX_GUEST_FS_SEL, &fs_sel);
+       int fs_rpl = (fs_sel & SEL_RPL);
+       int fs_dpl = seg_access_dpl(fs_access_rights);
+
+       assert(fs_dpl >= fs_rpl);
+    }
+
+    // GS
+    uint64_t gs_access_rights;
+    err += vmread(VMX_GUEST_GS_ACCESS, &gs_access_rights);
+    bool gs_usable = seg_reg_usable(gs_access_rights);
+    int gs_type = seg_access_type(gs_access_rights);
+
+    if (!unrestricted_guest && gs_usable && (0 <= gs_type && gs_type <= 11)) {
+        uint64_t gs_sel;
+       err += vmread(VMX_GUEST_GS_SEL, &gs_sel);
+       int gs_rpl = (gs_sel & SEL_RPL);
+       int gs_dpl = seg_access_dpl(gs_access_rights);
+
+       assert(gs_dpl >= gs_rpl);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_access_p(void)
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_p = seg_access_p(cs_access_rights);
+    assert(cs_p == 1);
+    
+    // SS
+    uint64_t ss_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    if (seg_reg_usable(ss_access_rights)) {
+        int ss_p = seg_access_p(ss_access_rights);
+       assert(ss_p == 1);
+    }
+
+    // DS
+    uint64_t ds_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    if (seg_reg_usable(ds_access_rights)) {
+        int ds_p = seg_access_p(ds_access_rights);
+       assert(ds_p == 1);
+    }
+
+    // ES
+    uint64_t es_access_rights;
+    err += vmread(VMX_GUEST_ES_ACCESS, &es_access_rights);
+    if (seg_reg_usable(es_access_rights)) {
+        int es_p = seg_access_p(es_access_rights);
+       assert(es_p == 1);
+    }
+
+    // FS
+    uint64_t fs_access_rights;
+    err += vmread(VMX_GUEST_FS_ACCESS, &fs_access_rights);
+    if (seg_reg_usable(fs_access_rights)) {
+        int fs_p = seg_access_p(fs_access_rights);
+       assert(fs_p == 1);
+    }
+    
+    // GS
+    uint64_t gs_access_rights;
+    err += vmread(VMX_GUEST_GS_ACCESS, &gs_access_rights);
+    if (seg_reg_usable(gs_access_rights)) {
+        int gs_p = seg_access_p(gs_access_rights);
+       assert(gs_p == 1);
+    }
+
+    // TR
+    uint64_t tr_access_rights;
+    err += vmread(VMX_GUEST_TR_ACCESS, &tr_access_rights);
+    int tr_p = seg_access_p(tr_access_rights);
+    assert(tr_p == 1);
+
+    // LDTR
+    uint64_t ldtr_access_rights;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    if (seg_reg_usable(ldtr_access_rights)) {  
+       int ldtr_p = seg_access_p(ldtr_access_rights);
+       assert(ldtr_p == 1);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_access_db(void)
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    assert(err_is_ok(err));
+    int cs_l = seg_access_l(cs_access_rights);
+    if (ia32e_guest && (cs_l == 1)) {
+        int cs_db = seg_access_db(cs_access_rights);
+       assert(cs_db == 0);
+    }
+}
+
+static void check_guest_seg_access_g(void)
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_g = seg_access_g(cs_access_rights);
+    
+    uint64_t cs_lim;
+    err += vmread(VMX_GUEST_CS_LIM, &cs_lim);
+    // If there is at least one bit in the range 0:11 that is set to 0
+    if ((cs_lim & 0xFFF) ^ 0xFFF) {
+        assert(cs_g == 0);
+    }
+    // If there is at least one bit in the range 20:31 that is set to 1
+    if ((cs_lim >> 20) & 0xFFF) {
+        assert(cs_g == 1);
+    }
+
+    // SS
+    uint64_t ss_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    if (seg_reg_usable(ss_access_rights)) {
+        int ss_g = seg_access_g(ss_access_rights);
+       uint64_t ss_lim;
+       err += vmread(VMX_GUEST_SS_LIM, &ss_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((ss_lim & 0xFFF) ^ 0xFFF) {
+           assert(ss_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((ss_lim >> 20) & 0xFFF) {
+           assert(ss_g == 1);
+       }       
+    }
+
+    // DS
+    uint64_t ds_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    if (seg_reg_usable(ds_access_rights)) {
+        int ds_g = seg_access_g(ds_access_rights);
+       uint64_t ds_lim;
+       err += vmread(VMX_GUEST_DS_LIM, &ds_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((ds_lim & 0xFFF) ^ 0xFFF) {
+           assert(ds_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((ds_lim >> 20) & 0xFFF) {
+           assert(ds_g == 1);
+       }       
+    }
+
+    // ES
+    uint64_t es_access_rights;
+    err += vmread(VMX_GUEST_ES_ACCESS, &es_access_rights);
+    if (seg_reg_usable(es_access_rights)) {
+        int es_g = seg_access_g(es_access_rights);
+       uint64_t es_lim;
+       err += vmread(VMX_GUEST_ES_LIM, &es_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((es_lim & 0xFFF) ^ 0xFFF) {
+           assert(es_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((es_lim >> 20) & 0xFFF) {
+           assert(es_g == 1);
+       }       
+    }
+
+    // FS
+    uint64_t fs_access_rights;
+    err += vmread(VMX_GUEST_FS_ACCESS, &fs_access_rights);
+    if (seg_reg_usable(fs_access_rights)) {
+        int fs_g = seg_access_g(fs_access_rights);
+       uint64_t fs_lim;
+       err += vmread(VMX_GUEST_FS_LIM, &fs_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((fs_lim & 0xFFF) ^ 0xFFF) {
+           assert(fs_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((fs_lim >> 20) & 0xFFF) {
+           assert(fs_g == 1);
+       }       
+    }
+    
+    // GS
+    uint64_t gs_access_rights;
+    err += vmread(VMX_GUEST_GS_ACCESS, &gs_access_rights);
+    if (seg_reg_usable(gs_access_rights)) {
+        int gs_g = seg_access_g(gs_access_rights);
+       uint64_t gs_lim;
+       err += vmread(VMX_GUEST_GS_LIM, &gs_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((gs_lim & 0xFFF) ^ 0xFFF) {
+           assert(gs_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((gs_lim >> 20) & 0xFFF) {
+           assert(gs_g == 1);
+       }       
+    }
+
+    // TR
+    uint64_t tr_access_rights;
+    err += vmread(VMX_GUEST_TR_ACCESS, &tr_access_rights);
+    if (seg_reg_usable(tr_access_rights)) {
+        int tr_g = seg_access_g(tr_access_rights);
+       uint64_t tr_lim;
+       err += vmread(VMX_GUEST_TR_LIM, &tr_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((tr_lim & 0xFFF) ^ 0xFFF) {
+           assert(tr_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((tr_lim >> 20) & 0xFFF) {
+           assert(tr_g == 1);
+       }       
+    }
+
+    // LDTR
+    uint64_t ldtr_access_rights;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    if (seg_reg_usable(ldtr_access_rights)) {
+        int ldtr_g = seg_access_g(ldtr_access_rights);
+       uint64_t ldtr_lim;
+       err += vmread(VMX_GUEST_LDTR_LIM, &ldtr_lim);
+       // If there is at least one bit in the range 0:11 that is set to 0
+       if ((ldtr_lim & 0xFFF) ^ 0xFFF) {
+           assert(ldtr_g == 0);
+       }
+       // If there is at least one bit in the range 20:31 that is set to 1
+       if ((ldtr_lim >> 20) & 0xFFF) {
+           assert(ldtr_g == 1);
+       }       
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_seg_access_rsvd(void)
+{
+    // CS
+    uint64_t cs_access_rights;
+    errval_t err = vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_rsvd_low = ((cs_access_rights >> 8) & 0xF);
+    int cs_rsvd_high = ((cs_access_rights >> 17) & 0x7FFF);
+    assert(cs_rsvd_low == 0);
+    assert(cs_rsvd_high == 0);
+
+    // SS
+    uint64_t ss_access_rights;
+    err += vmread(VMX_GUEST_SS_ACCESS, &ss_access_rights);
+    if (seg_reg_usable(ss_access_rights)) {
+        int ss_rsvd_low = ((ss_access_rights >> 8) & 0xF);
+       int ss_rsvd_high = ((ss_access_rights >> 17) & 0x7FFF);
+       assert(ss_rsvd_low == 0);
+       assert(ss_rsvd_high == 0);
+    }
+
+    // DS
+    uint64_t ds_access_rights;
+    err += vmread(VMX_GUEST_DS_ACCESS, &ds_access_rights);
+    if (seg_reg_usable(ds_access_rights)) {
+        int ds_rsvd_low = ((ds_access_rights >> 8) & 0xF);
+       int ds_rsvd_high = ((ds_access_rights >> 17) & 0x7FFF);
+       assert(ds_rsvd_low == 0);
+       assert(ds_rsvd_high == 0);
+    }
+
+    // ES
+    uint64_t es_access_rights;
+    err += vmread(VMX_GUEST_ES_ACCESS, &es_access_rights);
+    if (seg_reg_usable(es_access_rights)) {
+        int es_rsvd_low = ((es_access_rights >> 8) & 0xF);
+       int es_rsvd_high = ((es_access_rights >> 17) & 0x7FFF);
+       assert(es_rsvd_low == 0);
+       assert(es_rsvd_high == 0);
+    }
+
+    // FS
+    uint64_t fs_access_rights;
+    err += vmread(VMX_GUEST_FS_ACCESS, &fs_access_rights);
+    if (seg_reg_usable(fs_access_rights)) {
+        int fs_rsvd_low = ((fs_access_rights >> 8) & 0xF);
+       int fs_rsvd_high = ((fs_access_rights >> 17) & 0x7FFF);
+       assert(fs_rsvd_low == 0);
+       assert(fs_rsvd_high == 0);
+    }
+    
+    // GS
+    uint64_t gs_access_rights;
+    err += vmread(VMX_GUEST_GS_ACCESS, &gs_access_rights);
+    if (seg_reg_usable(gs_access_rights)) {
+        int gs_rsvd_low = ((gs_access_rights >> 8) & 0xF);
+       int gs_rsvd_high = ((gs_access_rights >> 17) & 0x7FFF);
+       assert(gs_rsvd_low == 0);
+       assert(gs_rsvd_high == 0);
+    }
+
+    // TR
+    uint64_t tr_access_rights;
+    err += vmread(VMX_GUEST_TR_ACCESS, &tr_access_rights);
+    int tr_rsvd_low = ((tr_access_rights >> 8) & 0xF);
+    int tr_rsvd_high = ((tr_access_rights >> 17) & 0x7FFF);
+    assert(tr_rsvd_low == 0);
+    assert(tr_rsvd_high == 0);
+
+    // LDTR
+    uint64_t ldtr_access_rights;
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &ldtr_access_rights);
+    if (seg_reg_usable(ldtr_access_rights)) {
+       int ldtr_rsvd_low = ((ldtr_access_rights >> 8) & 0xF);
+       int ldtr_rsvd_high = ((ldtr_access_rights >> 17) & 0x7FFF);
+       assert(ldtr_rsvd_low == 0);
+       assert(ldtr_rsvd_high == 0);
+    }
+    assert(err_is_ok(err));
+}
+
+// The guest will not be virtual-8086
+static void check_guest_seg_access_rights(void)
+{    
+    check_guest_seg_access_type();
+    check_guest_seg_access_s();
+    check_guest_seg_access_dpl();
+    check_guest_seg_access_p();
+    check_guest_seg_access_db();
+    check_guest_seg_access_g();
+    check_guest_seg_access_rsvd();
+}
+
+static void check_guest_seg_regs(void)
+{
+    check_guest_seg_sel();
+    check_guest_seg_base();
+    check_guest_seg_access_rights();
+}
+
+static void check_guest_desc_table_regs(void)
+{
+    uint64_t gdtr_base, idtr_base;
+    errval_t err = vmread(VMX_GUEST_GDTR_BASE, &gdtr_base);
+    err += vmread(VMX_GUEST_IDTR_BASE, &idtr_base);
+    bool gdtr_base_canonical = is_canonical(gdtr_base);
+    assert(gdtr_base_canonical);
+
+    bool idtr_base_canonical = is_canonical(idtr_base);
+    assert(idtr_base_canonical);
+
+    uint64_t gdtr_lim, idtr_lim;
+    err += vmread(VMX_GUEST_GDTR_LIM, &gdtr_lim);
+    err += vmread(VMX_GUEST_IDTR_LIM, &idtr_lim);
+    assert(err_is_ok(err));
+    assert((gdtr_lim & 0xFFFF0000) == 0);
+    assert((idtr_lim & 0xFFFF0000) == 0);
+}
+
+static void check_guest_rip(void)
+{
+    uint64_t guest_rip;
+    errval_t err = vmread(VMX_GUEST_RIP, &guest_rip);
+
+    // Guest RIP
+    uint64_t cs_access_rights;
+    err += vmread(VMX_GUEST_CS_ACCESS, &cs_access_rights);
+    int cs_l = seg_access_l(cs_access_rights);
+    if ((ia32e_guest == false) || (cs_l == 0)) {
+        assert((guest_rip & ~0xFFFFFFFF) == 0);
+    } else {
+      // bits N:63 must be identical, if the process supports N < 64 
+      // linear-address bits
+        assert((guest_rip & ~pa_width_mask()) == 0 ||
+              ~(guest_rip & ~pa_width_mask()) == pa_width_mask());
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_guest_rflags(void)
+{
+    // Guest RFLAGS
+    uint64_t guest_rflags;
+    errval_t err = vmread(VMX_GUEST_RFLAGS, &guest_rflags);
+
+    bool virtual_8086_guest = !!(guest_rflags & RFLAGS_VM);
+    assert(virtual_8086_guest == false);
+    
+    // Reserved bits 22:63 must be zero
+    assert((guest_rflags & ~0x3FFFFF) == 0); 
+    
+    // Bits 3, 5, and 15 must be zero
+    assert((guest_rflags & (1 << 3UL)) == 0);
+    assert((guest_rflags & (1 << 5UL)) == 0);
+    assert((guest_rflags & (1 << 15UL)) == 0);
+    
+    // Reserved bit 1 must be 1
+    assert(guest_rflags & (1 << 1UL));
+
+    uint64_t guest_cr0;
+    err += vmread(VMX_GUEST_CR0, &guest_cr0);
+    if (ia32e_guest || ((guest_rflags & CR0_PE) == 0)) {
+        assert((guest_rflags & RFLAGS_VM) == 0);
+    }
+
+    uint64_t intr_info;
+    err += vmread(VMX_EXIT_INTR_INFO, &intr_info);
+    bool intr_valid_bit = !!(intr_info & (1 << 31UL));
+    int intr_type = ((intr_info >> 8) & 0x3);
+    if (intr_valid_bit && intr_type == INTR_TYPE_EXT_INTR) {
+        assert(guest_rflags & RFLAGS_IF);
+    }
+    assert(err_is_ok(err));
+}
+
+void check_guest_state_area(void)
+{
+    uint64_t entry_controls, sec_ctls;
+    errval_t err = vmread(VMX_ENTRY_CONTROLS, &entry_controls);
+    err += vmread(VMX_EXEC_SEC_PROC, &sec_ctls);
+
+    ia32e_guest = !!(entry_controls & ENTRY_CLTS_IA32E_MODE);
+    unrestricted_guest = !!(sec_ctls & SP_CLTS_UNRSTD_GUEST);
+
+    check_guest_control_registers();
+
+    uint64_t sysenter_esp, sysenter_eip;
+    err += vmread(VMX_GUEST_SYSENTER_ESP, &sysenter_esp);
+    err += vmread(VMX_GUEST_SYSENTER_EIP, &sysenter_eip);
+    assert(err_is_ok(err));
+
+    bool sysenter_esp_canonical = is_canonical(sysenter_esp);
+    assert(sysenter_esp_canonical);
+    bool sysenter_eip_canonical = is_canonical(sysenter_eip);
+    assert(sysenter_eip_canonical);
+
+    check_guest_efer();
+    check_guest_seg_regs();
+    check_guest_desc_table_regs();
+
+    check_guest_rip();
+    check_guest_rflags();
+}
+
+static void check_host_cr0(void)
+{
+    uint64_t host_cr0;
+    errval_t err = vmread(VMX_HOST_CR0, &host_cr0);
+    assert(err_is_ok(err));
+
+    uint64_t cr0_fixed0 = ia32_vmx_cr0_fixed0_rd(NULL);
+    uint64_t cr0_fixed1 = ia32_vmx_cr0_fixed1_rd(NULL);
+    assert(((host_cr0 | cr0_fixed0) & cr0_fixed1) == host_cr0);
+}
+
+static void check_host_cr3(void)
+{
+    uint64_t host_cr3;
+    errval_t err = vmread(VMX_HOST_CR3, &host_cr3);
+    assert(err_is_ok(err));
+
+    bool within_pa_width = is_within_pa_width(host_cr3);
+    assert(within_pa_width);
+}
+
+static void check_host_cr4(void)
+{
+    uint64_t exit_controls;
+    errval_t err = vmread(VMX_EXIT_CONTROLS, &exit_controls);
+
+    uint64_t host_cr4;
+    err += vmread(VMX_HOST_CR4, &host_cr4);
+    assert(err_is_ok(err));
+
+    uint32_t cr4_fixed0 = ia32_vmx_cr4_fixed0_rd(NULL);
+    uint32_t cr4_fixed1 = ia32_vmx_cr4_fixed1_rd(NULL);
+    assert(((host_cr4 | cr4_fixed0) & cr4_fixed1) == host_cr4);
+
+    bool host_size_set = !!(exit_controls & EXIT_CLTS_HOST_SIZE);              
+    if (host_size_set) {
+        assert(host_cr4 & CR4_PAE);
+    } else {
+        assert((host_cr4 & CR4_PCIDE) == 0);
+    }
+}
+
+static void check_host_control_registers(void)
+{
+    check_host_cr0();
+    check_host_cr3();
+    check_host_cr4();    
+}
+
+static void check_host_efer(void)
+{
+    uint64_t exit_controls;
+    errval_t err = vmread(VMX_EXIT_CONTROLS, &exit_controls);
+    if (exit_controls & EXIT_CLTS_LOAD_EFER) {
+        uint64_t host_efer;
+       err += vmread(VMX_HOST_EFER_F, &host_efer);
+       // Bits reserved must be set to 0:
+
+       // Bits 1:7
+       assert(((host_efer >> 1) & 0x7F) == 0);
+       // Bit 9
+       assert(((host_efer >> 9) & 0x1) == 0);
+       // Bits 12:63
+       assert((host_efer & ~0xFFF) == 0);
+
+       bool host_size_set = !!(exit_controls & EXIT_CLTS_HOST_SIZE);           
+       bool lma_set = !!(host_efer & EFER_LMA); 
+       assert(lma_set == host_size_set);
+
+       bool lme_set = !!(host_efer & EFER_LME); 
+       assert(lme_set == host_size_set);
+    }
+    assert(err_is_ok(err));
+}
+
+static void check_host_seg_sel(void)
+{  
+    // CS
+    uint64_t cs_sel;
+    errval_t err = vmread(VMX_HOST_CS_SEL, &cs_sel);
+    int cs_rpl = (cs_sel & SEL_RPL);
+    int cs_ti = (cs_sel & SEL_TI);
+    assert(cs_rpl == 0);
+    assert(cs_ti == 0);
+    assert(cs_sel != 0);
+
+    // SS
+    uint64_t ss_sel;
+    err += vmread(VMX_HOST_SS_SEL, &ss_sel);
+    int ss_rpl = (ss_sel & SEL_RPL);
+    int ss_ti = (ss_sel & SEL_TI);
+    assert(ss_rpl == 0);
+    assert(ss_ti == 0);
+
+    uint64_t exit_controls;
+    err += vmread(VMX_EXIT_CONTROLS, &exit_controls);
+    bool host_size_set = !!(exit_controls & EXIT_CLTS_HOST_SIZE);              
+    if (!host_size_set) {
+        assert(ss_sel != 0);
+    }
+    
+    // DS
+    uint64_t ds_sel;
+    err += vmread(VMX_HOST_DS_SEL, &ds_sel);
+    int ds_rpl = (ds_sel & SEL_RPL);
+    int ds_ti = (ds_sel & SEL_TI);
+    assert(ds_rpl == 0);
+    assert(ds_ti == 0);
+
+    // ES
+    uint64_t es_sel;
+    err += vmread(VMX_HOST_ES_SEL, &es_sel);
+    int es_rpl = (es_sel & SEL_RPL);
+    int es_ti = (es_sel & SEL_TI);
+    assert(es_rpl == 0);
+    assert(es_ti == 0);
+
+    // FS
+    uint64_t fs_sel;
+    err += vmread(VMX_HOST_FS_SEL, &fs_sel);
+    int fs_rpl = (fs_sel & SEL_RPL);
+    int fs_ti = (fs_sel & SEL_TI);
+    assert(fs_rpl == 0);
+    assert(fs_ti == 0);
+
+    // GS
+    uint64_t gs_sel;
+    err += vmread(VMX_HOST_GS_SEL, &gs_sel);
+    int gs_rpl = (gs_sel & SEL_RPL);
+    int gs_ti = (gs_sel & SEL_TI);
+    assert(gs_rpl == 0);
+    assert(gs_ti == 0);
+
+    // TR
+    uint64_t tr_sel;
+    err += vmread(VMX_HOST_TR_SEL, &tr_sel);
+    assert(err_is_ok(err));
+
+    int tr_rpl = (tr_sel & SEL_RPL);
+    int tr_ti = (tr_sel & SEL_TI);
+    assert(tr_rpl == 0);
+    assert(tr_ti == 0);
+    assert(tr_sel != 0);
+}
+
+static void check_host_seg_base(void)
+{
+    uint64_t fs_base;
+    errval_t err = vmread(VMX_HOST_FS_BASE, &fs_base);
+    bool fs_base_canonical = is_canonical(fs_base);
+    assert(fs_base_canonical);
+
+    uint64_t gs_base;
+    err += vmread(VMX_GUEST_GS_BASE, &gs_base);
+    bool gs_base_canonical = is_canonical(gs_base);
+    assert(gs_base_canonical);
+
+    uint64_t tr_base;
+    err += vmread(VMX_GUEST_TR_BASE, &tr_base);
+    assert(err_is_ok(err));
+
+    bool tr_base_canonical = is_canonical(tr_base);
+    assert(tr_base_canonical);
+}
+
+static void check_host_seg_regs(void)
+{
+    check_host_seg_sel();
+    check_host_seg_base();
+}
+
+static void check_host_desc_table_regs(void)
+{
+    uint64_t idtr_base;
+    errval_t err = vmread(VMX_GUEST_IDTR_BASE, &idtr_base);
+    bool idtr_base_canonical = is_canonical(idtr_base);
+    assert(idtr_base_canonical);
+
+    uint64_t gdtr_base;
+    err += vmread(VMX_GUEST_GDTR_BASE, &gdtr_base);
+    assert(err_is_ok(err));
+
+    bool gdtr_base_canonical = is_canonical(gdtr_base);
+    assert(gdtr_base_canonical);
+}
+
+static void check_host_rip(void)
+{
+    uint64_t host_rip;
+    errval_t err = vmread(VMX_HOST_RIP, &host_rip);
+
+    uint64_t exit_controls;
+    err += vmread(VMX_EXIT_CONTROLS, &exit_controls);
+    assert(err_is_ok(err));
+
+    bool host_size_set = !!(exit_controls & EXIT_CLTS_HOST_SIZE);              
+    if (host_size_set) {
+        bool rip_canonical = is_canonical(host_rip);
+       assert(rip_canonical);
+    } else {
+        assert((host_rip & ~0xFFFFFFFF) == 0);
+    }
+}
+
+void check_host_state_area(void)
+{
+    check_host_control_registers();
+
+    uint64_t sysenter_esp, sysenter_eip;
+    errval_t err = vmread(VMX_HOST_SYSENTER_ESP, &sysenter_esp);
+    err += vmread(VMX_HOST_SYSENTER_EIP, &sysenter_eip);
+    assert(err_is_ok(err));
+
+    bool sysenter_esp_canonical = is_canonical(sysenter_esp);
+    assert(sysenter_esp_canonical);
+    bool sysenter_eip_canonical = is_canonical(sysenter_eip);
+    assert(sysenter_eip_canonical);
+
+    check_host_efer();
+    check_host_seg_regs();
+    check_host_desc_table_regs();
+
+    check_host_rip();
+}
+
+// Checks pertaining to the "Enable EPT" and "EPT-violation #VE" controls
+static void check_vmx_controls_ept(void)
+{
+    bool within_pa_width;
+    uint64_t pp_controls, sp_controls;
+    errval_t err = vmread(VMX_EXEC_PRIM_PROC, &pp_controls);
+    err += vmread(VMX_EXEC_SEC_PROC, &sp_controls);
+
+    if (unrestricted_guest) {
+        assert(sp_controls & SP_CLTS_ENABLE_EPT);
+    }
+
+    if (sp_controls & SP_CLTS_ENABLE_EPT) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+
+       uint64_t eptp;
+       err += vmread(VMX_EPTP_F, &eptp);
+
+       ia32_vmx_ept_vpid_t ept_vpid_msr = ia32_vmx_ept_vpid_rd(NULL); 
+       int set_ept_type = ept_type(eptp);
+       
+       switch(set_ept_type) {
+       case 0x0: // Uncacheable
+           assert(ia32_vmx_ept_vpid_ucmt_extract(ept_vpid_msr));
+           break;
+       case 0x4: // Execute-only
+           assert(ia32_vmx_ept_vpid_eot_extract(ept_vpid_msr));
+           break;
+       case 0x6: // Write-back
+           assert(ia32_vmx_ept_vpid_wbmt_extract(ept_vpid_msr));
+           break;
+       default:
+           assert(!"EPT type value is reserved");
+       }
+
+       assert(ia32_vmx_ept_vpid_pwl4_extract(ept_vpid_msr));
+       assert(ept_page_walk_length(eptp) == 3);
+
+       assert(((eptp >> 7) & 0x1F) == 0);
+        within_pa_width = is_within_pa_width(eptp);
+       assert(within_pa_width);
+
+       bool accessed_dirty = ia32_vmx_ept_vpid_ept_adf_extract(ept_vpid_msr);
+       if (!accessed_dirty) {
+           assert(ept_accessed_dirty_enable(eptp) == 0);
+       }
+    }
+
+    if (sp_controls & SP_CLTS_EPT_VIOL) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+       uint64_t vexcp_info_addr;
+       err += vmread(VMX_VEXCP_INFO_F, &vexcp_info_addr);
+       assert((vexcp_info_addr & BASE_PAGE_MASK) == 0);
+       within_pa_width = is_within_pa_width(vexcp_info_addr);
+       assert(within_pa_width); 
+    }
+    assert(err_is_ok(err));
+}
+
+// Checks related to address-space size
+static void check_vmx_controls_addr_space(void)
+{
+    uint64_t exit_controls;
+    errval_t err = vmread(VMX_EXIT_CONTROLS, &exit_controls);
+
+    bool host_size_set = !!(exit_controls & EXIT_CLTS_HOST_SIZE);              
+    
+    uint64_t host_efer;
+    err += vmread(VMX_HOST_EFER_F, &host_efer);
+    assert(err_is_ok(err));
+
+    if (host_efer & EFER_LMA) {
+        assert(host_size_set);
+    } else {
+        assert(!ia32e_guest);
+       assert(!host_size_set);
+    }
+
+    if (!host_size_set) {
+        assert(!ia32e_guest);
+    }
+}
+
+void check_vmx_controls(void)
+{
+    uint64_t msr_bitmap_addr;
+    errval_t err = vmread(VMX_MSRBMP_F, &msr_bitmap_addr); 
+    assert((msr_bitmap_addr & BASE_PAGE_MASK) == 0);
+    bool within_pa_width = is_within_pa_width(msr_bitmap_addr);
+    assert(within_pa_width);
+
+    uint64_t io_bitmap_a_addr, io_bitmap_b_addr;
+    err += vmread(VMX_IOBMP_A_F, &io_bitmap_a_addr);
+    assert((io_bitmap_a_addr & BASE_PAGE_MASK) == 0);
+    within_pa_width = is_within_pa_width(io_bitmap_a_addr);
+    assert(within_pa_width);
+
+    err += vmread(VMX_IOBMP_B_F, &io_bitmap_b_addr);
+    assert((io_bitmap_b_addr & BASE_PAGE_MASK) == 0);
+    within_pa_width = is_within_pa_width(io_bitmap_b_addr);
+    assert(within_pa_width);
+
+    uint64_t pin_controls, pp_controls, sp_controls;
+    err += vmread(VMX_EXEC_PIN_BASED, &pin_controls);
+    err += vmread(VMX_EXEC_PRIM_PROC, &pp_controls);
+    err += vmread(VMX_EXEC_SEC_PROC, &sp_controls);
+
+    uint64_t exit_controls;
+    err += vmread(VMX_EXIT_CONTROLS, &exit_controls);
+
+    if (pp_controls & PP_CLTS_TPR_SHADOW) {
+        uint64_t vapic_addr;
+       err += vmread(VMX_VAPIC_F, &vapic_addr);
+       assert((vapic_addr & BASE_PAGE_MASK) == 0);
+       within_pa_width = is_within_pa_width(vapic_addr);
+       assert(within_pa_width);      
+
+       uint64_t tpr_threshold;
+       err += vmread(VMX_TPR_THRESHOLD, &tpr_threshold);
+        if((sp_controls & SP_CLTS_VIRQ_DEL) == 0) {            
+           // Bits 4:31 must be 0
+           assert((tpr_threshold & 0xFFFFFFF0) == 0);
+       }
+
+       if ((sp_controls & SP_CLTS_VIRQ_DEL) == 0 && 
+           (sp_controls & SP_CLTS_VIRT_APIC) == 0) {
+           lvaddr_t vapic_page = local_phys_to_mem((lpaddr_t)vapic_addr);
+           assert(vapic_page != 0);
+           // virtual task-priority register is at offset 0x80
+           lvaddr_t vtpr_addr = vapic_page + 0x80;
+           uint32_t vtpr = *((uint32_t *)vtpr_addr);
+           assert((tpr_threshold & 0xF) <= ((vtpr >> 4) & 0xF));
+       }
+    } else {
+        assert((sp_controls & SP_CLTS_VIRT_X2APIC) == 0);
+       assert((sp_controls & SP_CLTS_VIRT_APIC_REG) == 0);
+       assert((sp_controls & SP_CLTS_VIRQ_DEL) == 0);
+    }
+
+    if ((pin_controls & PIN_CTLS_NMI) == 0) {
+        assert((pin_controls & PIN_CTLS_VIRT_NMI) == 0);
+    }
+
+    if ((pin_controls & PIN_CTLS_VIRT_NMI) == 0) {
+        assert((pp_controls & PP_CLTS_NMI_WINDOW) == 0);
+    }
+
+    if (sp_controls & SP_CLTS_VIRT_APIC) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+       uint64_t apic_access_addr;
+       err += vmread(VMX_APIC_ACC_F, &apic_access_addr);
+       assert((apic_access_addr & BASE_PAGE_MASK) == 0);
+       within_pa_width = is_within_pa_width(apic_access_addr);
+       assert(within_pa_width);
+    }
+
+    if (sp_controls & SP_CLTS_VIRT_X2APIC) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+       assert((sp_controls & SP_CLTS_VIRT_APIC) == 0);
+    }
+
+    if (sp_controls & SP_CLTS_VIRQ_DEL) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+        assert(pin_controls & PIN_CTLS_EXT_INTR);
+    }
+
+    if (pin_controls & PIN_CTLS_POSTED_INTR) {
+        assert(sp_controls & SP_CLTS_VIRQ_DEL);
+       assert(exit_controls & EXIT_CLTS_ACK_INTR);
+       
+       uint64_t pinv;
+       err += vmread(VMX_PINV, &pinv);
+       // The posted-interrupt notification vector must be in the 
+       // range 0-255
+       assert((pinv & 0xFF00) == 0);
+
+       uint64_t pid_addr;
+       err += vmread(VMX_PID_F, &pid_addr);
+       assert((pid_addr & 0x3F) == 0);
+       within_pa_width = is_within_pa_width(pid_addr);
+       assert(within_pa_width);
+    }
+
+    if (sp_controls & SP_CLTS_ENABLE_VPID) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+       
+       uint64_t vpid;
+       err += vmread(VMX_VPID, &vpid);
+       assert(vpid != 0);
+    }
+
+    if (sp_controls & SP_CLTS_VMCS_SHADOW) {
+        assert(pp_controls & PP_CLTS_SEC_CTLS);
+       uint64_t vmread_bitmap_addr, vmwrite_bitmap_addr;
+       err += vmread(VMX_VMREAD_BMP_F, &vmread_bitmap_addr);
+       err += vmread(VMX_VMWRITE_BMP_F, &vmwrite_bitmap_addr);
+
+       assert((vmread_bitmap_addr & BASE_PAGE_MASK) == 0);
+       within_pa_width = is_within_pa_width(vmread_bitmap_addr);
+       assert(within_pa_width); 
+
+       assert((vmwrite_bitmap_addr & BASE_PAGE_MASK) == 0);
+       within_pa_width = is_within_pa_width(vmwrite_bitmap_addr);
+       assert(within_pa_width);        
+    }
+    assert(err_is_ok(err));
+
+    check_vmx_controls_ept();
+    check_vmx_controls_addr_space();
+}
diff --git a/kernel/arch/x86_64/vmx_vmkit.c b/kernel/arch/x86_64/vmx_vmkit.c
new file mode 100644 (file)
index 0000000..fc0a453
--- /dev/null
@@ -0,0 +1,1056 @@
+/**
+ * \file
+ * \brief Contains VMKit kernel interface for version using VMX extensions.
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#include <string.h>
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+#include <vmx_vmkit.h>
+#include <vmx_checks.h>
+#include <x86.h>
+#include <dispatch.h>
+#include <exec.h>
+#include <irq.h>
+#include <barrelfish_kpi/vmkit.h>
+#include <barrelfish_kpi/syscalls.h>
+
+#include <dev/ia32_dev.h>
+
+// Execution, entry, and exit controls that we want to use 
+// for each VM
+#ifdef CONFIG_ARRAKISMON
+#define GUEST_PIN_BASE_CTLS_ENABLE \
+    (PIN_CTLS_EXT_INTR | PIN_CTLS_NMI | PIN_CTLS_VIRT_NMI)
+
+#define GUEST_PIN_BASE_CTLS_DISABLE \
+    (0)
+
+#define GUEST_PP_CTLS_ENABLE \
+    (PP_CLTS_MSRBMP | PP_CLTS_IOBMP | PP_CLTS_HLT)
+
+#define GUEST_PP_CTLS_DISABLE \
+    (0)
+
+#define GUEST_SP_CTLS_ENABLE \
+    (0)
+     
+#define GUEST_SP_CTLS_DISABLE \
+    (0)
+
+#define GUEST_EXIT_CTLS_ENABLE \
+    (EXIT_CLTS_HOST_SIZE | EXIT_CLTS_SAVE_EFER | EXIT_CLTS_LOAD_EFER)
+
+#define GUEST_EXIT_CTLS_DISABLE \
+    (0)
+
+#define GUEST_ENTRY_CTLS_ENABLE \
+    (ENTRY_CLTS_LOAD_EFER | ENTRY_CLTS_LOAD_DBG | ENTRY_CLTS_IA32E_MODE)
+
+#define GUEST_ENTRY_CTLS_DISABLE \
+    (0)
+#else
+#define GUEST_PIN_BASE_CTLS_ENABLE \
+    (PIN_CTLS_EXT_INTR | PIN_CTLS_NMI | PIN_CTLS_VIRT_NMI)
+
+#define GUEST_PIN_BASE_CTLS_DISABLE \
+    (0)
+
+#define GUEST_PP_CTLS_ENABLE \
+    (PP_CLTS_MSRBMP | PP_CLTS_IOBMP | PP_CLTS_HLT | PP_CLTS_SEC_CTLS)
+
+#define GUEST_PP_CTLS_DISABLE \
+    (0)
+
+#define GUEST_SP_CTLS_ENABLE \
+    (SP_CLTS_ENABLE_EPT | SP_CLTS_UNRSTD_GUEST)
+     
+#define GUEST_SP_CTLS_DISABLE \
+    (0)
+
+#define GUEST_EXIT_CTLS_ENABLE \
+    (EXIT_CLTS_HOST_SIZE | EXIT_CLTS_SAVE_EFER | EXIT_CLTS_LOAD_EFER | \
+     EXIT_CLTS_SAVE_PAT  | EXIT_CLTS_LOAD_PAT)
+
+#define GUEST_EXIT_CTLS_DISABLE \
+    (0)
+
+#define GUEST_ENTRY_CTLS_ENABLE \
+    (ENTRY_CLTS_LOAD_EFER)
+
+#define GUEST_ENTRY_CTLS_DISABLE \
+    (0)
+#endif
+
+extern void *vmx_return_func;
+
+static struct guest_control *ctrl = NULL;
+
+static int launched = 0;
+
+#ifndef CONFIG_ARRAKISMON
+// List of MSRs that are loaded on VM-exit.
+static uint32_t msr_list[VMX_MSR_COUNT] = 
+    {MSR_KERNEL_GS_BASE, MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SFMASK};
+
+// VM-exit MSR-load area that contains host MSR values that are saved prior
+// to VM-entry and loaded on VM exit.  
+static struct msr_entry host_msr_area[VMX_MSR_COUNT]
+__attribute__ ((aligned(16)));
+#endif
+
+// VMX controls that are written to the VMCS. In addition to the controls 
+// that are requested, these values may have bits that are reserved set.
+vmx_controls pin_based_ctls = 0, pp_based_ctls = 0, sp_based_ctls = 0,
+    entry_ctls = 0, exit_ctls = 0; 
+
+static uint8_t vmxon_region[BASE_PAGE_SIZE]
+__attribute__ ((aligned(BASE_PAGE_SIZE)));
+
+// Returns true if extended page tables (EPT) are enabled.
+static inline int ept_enabled(void)
+{
+    return ((GUEST_SP_CTLS_ENABLE & SP_CLTS_ENABLE_EPT) != 0);
+}
+
+static inline errval_t instr_err(void)
+{
+    errval_t err;
+    __asm volatile("jnc vmx_err_check_zf%=\n\t"
+                  "mov %[VMfailInvalid], %[err]\n\t"
+                  "jmp vmx_err_done%=\n\t"
+                  "vmx_err_check_zf%=:\n\t"
+                  "jnz vmx_err_succeed%=\n\t"
+                  "mov %[VMfailValid], %[err]\n\t"
+                  "jmp vmx_err_done%=\n\t"
+                  "vmx_err_succeed%=:\n\t"
+                  "mov %[VMsucceed], %[err]\n\t"
+                  "vmx_err_done%=:\n\t"
+                  : [err] "=r" (err)
+                  : [VMfailInvalid] "i" (SYS_ERR_VMKIT_VMX_VMFAIL_INVALID),
+                    [VMfailValid] "i" (SYS_ERR_VMKIT_VMX_VMFAIL_VALID),
+                    [VMsucceed] "i" (SYS_ERR_OK)
+                  : "memory");
+    return err;
+}
+
+// Executes the vmptrld instruction, which makes the VMCS referenced by
+// 'vmcs_base' active and current.
+errval_t vmptrld(lpaddr_t vmcs_base)
+{
+    __asm volatile("vmptrld %[vmcs_base]\n\t"
+                  :
+                  : [vmcs_base] "m" (vmcs_base)
+                  : "memory");
+    return instr_err();
+}
+
+// Returns the physical address base of the current VMCS.
+lpaddr_t vmptrst(void)
+{
+   lpaddr_t dest_addr;
+    __asm volatile("vmptrst %[dest_addr]\n\t"
+                  :
+                  : [dest_addr] "m" (dest_addr)
+                  : "memory");
+    return dest_addr;
+}
+
+// Executes the vmclear instruction, which makes the VMCS referenced 
+// by 'vmcs_base' clear and inactive. This instruction also ensures 
+// that the referenced VMCS data is saved.
+errval_t vmclear(lpaddr_t vmcs_base)
+{
+    __asm volatile("vmclear %[vmcs_base]\n\t"
+                  :
+                  : [vmcs_base] "m" (vmcs_base)
+                  : "memory");
+    return instr_err();
+}
+
+// Reads a component with a specified encoding from the current VMCS
+// to an address dest_addr using the vmread instruction.
+errval_t vmread(uintptr_t encoding, lvaddr_t *dest_addr)
+{
+    __asm volatile("vmread %[encoding], %[dest_addr]\n\t"
+                  :
+                  : [encoding] "r" (encoding), [dest_addr] "m" (*dest_addr)
+                  : "memory");
+    return instr_err();
+}
+
+// Writes a component with a specifed encoding and value to the current
+// VMCS using the vmwrite instruction.
+errval_t vmwrite(uintptr_t encoding, uintptr_t value)
+{
+    __asm volatile("vmwrite %[value], %[encoding]\n\t"
+                  :
+                  : [encoding] "r" (encoding), [value] "r" (value)
+                  : "memory");
+    return instr_err();
+}
+
+// Using a provided VMXON region, causes the logical processor to enter 
+// into root-mode by executing the vmxon instruction.
+errval_t vmxon(lpaddr_t base_addr) 
+{
+    __asm volatile("vmxon %[base_addr]\n\t"
+                  :
+                  : [base_addr] "m" (base_addr)
+                  : "memory");
+    return instr_err();
+}
+
+// Exits VMX operation by executing the vmxoff instruction.
+errval_t vmxoff(void)
+{
+    __asm volatile("vmxoff");
+    return instr_err();
+}
+
+// Reads and returns the MSR that reports the allowed settings
+// for ALL of the bits of the controls indicated by 'type.'
+static uint64_t msr_ctls_true(enum vmx_ctls_t type)
+{
+    uint64_t true_msr = 0;
+    switch(type) {
+    case VMX_CTLS_PIN_BASED: 
+        true_msr = ia32_vmx_true_pinbased_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_PRIMARY_PROCESSOR: 
+        true_msr = ia32_vmx_true_ppbased_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_SECONDARY_PROCESSOR: 
+        assert(!"No such MSR for secondary processor controls!\n");
+       break;
+    case VMX_CTLS_EXIT: 
+        true_msr = ia32_vmx_true_exit_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_ENTRY: 
+        true_msr = ia32_vmx_true_entry_ctls_rd(NULL);
+       break;
+    }
+    return true_msr;
+}
+
+// Reads and returns the MSR that reports the allowed settings
+// for MOST of the bits of the controls indicated by 'type.'
+static uint64_t msr_ctls(enum vmx_ctls_t type)
+{
+    uint64_t msr = 0;
+    switch(type) {
+    case VMX_CTLS_PIN_BASED: 
+        msr = ia32_vmx_pinbased_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_PRIMARY_PROCESSOR: 
+        msr = ia32_vmx_ppbased_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_SECONDARY_PROCESSOR: 
+        msr = ia32_vmx_spbased_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_EXIT: 
+        msr = ia32_vmx_exit_ctls_rd(NULL);
+       break;
+    case VMX_CTLS_ENTRY: 
+        msr = ia32_vmx_entry_ctls_rd(NULL);
+       break;
+    }
+    return msr;
+}
+
+// Writes the controls indicated by 'type' to the VMCS using 'mask_1s'
+// and 'mask_0s', which correspond to the controls that should be enabled 
+// and disabled, respectively.  
+static uint32_t set_vmx_controls(uint32_t mask_1s, 
+    uint32_t mask_0s, enum vmx_ctls_t type)
+{
+    uint32_t controls = 0;
+    
+    ia32_vmx_basic_t vmx_basic = ia32_vmx_basic_rd(NULL);
+    bool true_ctls = !!(ia32_vmx_basic_ctls_clear_extract(vmx_basic));   
+    if (true_ctls && (type != VMX_CTLS_SECONDARY_PROCESSOR)) {
+        uint64_t true_msr = msr_ctls_true(type);
+       controls = ((DWORD_LS(true_msr) | mask_1s) & DWORD_MS(true_msr));
+    } else {
+        uint64_t msr = msr_ctls(type);
+       controls = ((DWORD_LS(msr) | mask_1s) & DWORD_MS(msr));
+    }
+    assert((mask_1s & (~controls)) == 0);
+    assert((mask_0s & controls) == 0);
+    return controls;
+}
+
+/**
+ * \brief Tries to enable hardware assisted virtualization.
+ *
+ * Checks whether hardware assisted virtualization is available on the platform
+ * and enables this feature.
+ *
+ * \Return Returns VMKIT_ERR_OK on successful initialization of the subsystem
+ *         or VMKIT_ERR_UNAVAIL if virtualization is unavailable.
+ */
+errval_t vmx_enable_virtualization (void)
+{
+    uint32_t cpuid_ecx;
+    cpuid(CPUID_VMX, NULL, NULL, &cpuid_ecx, NULL);
+    if (!(cpuid_ecx & VMX_SUPPORT)) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // The 'lock' and 'enable VMXON outside' bits of the IA32_FEATURE_CONTROL_MSR 
+    // must be set
+    ia32_feature_cntl_t feat_cntl_msr;
+    feat_cntl_msr = ia32_feature_cntl_rd(NULL);
+    if (!ia32_feature_cntl_lock_extract(feat_cntl_msr) || 
+       !ia32_feature_cntl_vmxoutsmx_extract(feat_cntl_msr)) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    pin_based_ctls = set_vmx_controls(
+        GUEST_PIN_BASE_CTLS_ENABLE, GUEST_PIN_BASE_CTLS_DISABLE, VMX_CTLS_PIN_BASED);
+
+    pp_based_ctls = set_vmx_controls(
+       GUEST_PP_CTLS_ENABLE, GUEST_PP_CTLS_DISABLE, VMX_CTLS_PRIMARY_PROCESSOR);
+         
+    sp_based_ctls = set_vmx_controls(
+       GUEST_SP_CTLS_ENABLE, GUEST_SP_CTLS_DISABLE, VMX_CTLS_SECONDARY_PROCESSOR);
+
+    entry_ctls = set_vmx_controls(
+        GUEST_ENTRY_CTLS_ENABLE, GUEST_ENTRY_CTLS_DISABLE, VMX_CTLS_ENTRY);
+
+    exit_ctls = set_vmx_controls(
+        GUEST_EXIT_CTLS_ENABLE, GUEST_EXIT_CTLS_DISABLE, VMX_CTLS_EXIT);
+
+    // Initialize the VMXON region
+    memset(vmxon_region, 0x0, BASE_PAGE_SIZE);
+    ia32_vmx_basic_t vmx_basic;
+    vmx_basic = ia32_vmx_basic_rd(NULL);
+    uint32_t vmcs_rev_id = ia32_vmx_basic_vmcs_rev_id_extract(vmx_basic);
+    vmxon_region[0] = vmcs_rev_id;
+
+    // The logical processor must use PAE paging
+    uint64_t cr0 = rdcr0();
+    if ((cr0 & CR0_PE) == 0 || (rdcr0() & CR0_PG) == 0) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // The CR0 register value has to support all of the CR0 fixed bits
+    if (cr0 != vmx_fixed_cr0()) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+
+    // Enable virtualization, if not already enabled
+    if (!vmx_enabled()) {
+        enable_vmx();
+    }
+    // The CR4 register value has to support all of the CR4 fixed bits
+    if (rdcr4() != vmx_fixed_cr4()) {
+        return SYS_ERR_VMKIT_UNAVAIL;
+    }
+         
+    // Execute VMXON to place processor into VMX root operation
+    errval_t err = vmxon(mem_to_local_phys((lvaddr_t)vmxon_region));
+    assert(err_is_ok(err));
+
+    return SYS_ERR_OK;
+}
+
+static inline void vmx_set_exception_bitmap(void)
+{
+    errval_t err = vmwrite(VMX_EXCP_BMP, ~(1UL << 7)); 
+    assert(err_is_ok(err));
+}
+
+#ifndef CONFIG_ARRAKISMON
+static uint64_t vmx_read_msr(uint32_t index) {
+    uint64_t val;
+    switch (index) { 
+    case MSR_KERNEL_GS_BASE:
+        val = ia32_kernel_gs_base_rd(NULL);
+       break;
+    case MSR_STAR:
+        val = ia32_star_rd(NULL);
+       break;
+    case MSR_LSTAR:
+        val = ia32_lstar_rd(NULL);
+       break;
+    case MSR_CSTAR:
+        val = ia32_cstar_rd(NULL);
+       break;
+    case MSR_SFMASK:
+        val = ia32_fmask_rd(NULL);
+       break;
+    default:
+        assert(!"MSR index not supported");
+    }
+    return val;
+}
+
+static void vmx_host_msr_area_init(struct msr_entry *msr_area)
+{ 
+    for (int i = 0; i < VMX_MSR_COUNT; i++) {
+        msr_area[i].index = msr_list[i];
+       msr_area[i].val = vmx_read_msr(msr_list[i]);
+    }
+}
+#endif
+
+// Writes the host state, which is used after a VM-exit, to the
+// current VMCS
+static void vmx_set_host_state(void)
+{    
+    // On a page-fault the processor checks whether:
+    // (#PF error-code) & (#PF error-code mask) = (#PF error-code match)
+    
+    // Setting the mask to 0, the match to 0xFFFFFFFF, and bit 14 in the 
+    // exception bitmap results in no VM-exits on guest page-faults.
+    errval_t err = vmwrite(VMX_PF_ERR_MASK, 0);
+    err += vmwrite(VMX_PF_ERR_MATCH, 0xFFFFFFFF);
+    err += vmwrite(VMX_CR3_TARGET_CNT, 0);
+
+    uint64_t cr0 = rdcr0(), cr3 = rdcr3(), cr4 = rdcr4();
+
+    uint64_t cr0_fixed0 = ia32_vmx_cr0_fixed0_rd(NULL);
+    uint64_t cr0_fixed1 = ia32_vmx_cr0_fixed1_rd(NULL);
+    uint64_t cr4_fixed0 = ia32_vmx_cr4_fixed0_rd(NULL);
+    uint64_t cr4_fixed1 = ia32_vmx_cr4_fixed1_rd(NULL);
+
+    assert((~cr0 & cr0_fixed0) == 0); 
+    assert((cr0 & ~cr0_fixed1) == 0);
+    assert((~cr4 & cr4_fixed0) == 0);
+    assert((cr4 & ~cr4_fixed1) == 0);
+
+    assert(((cr0 | cr0_fixed0) & cr0_fixed1) == cr0);
+    assert(((cr4 | cr4_fixed0) & cr4_fixed1) == cr4);
+    assert(rdcr4() & CR4_PAE);
+    
+    err += vmwrite(VMX_HOST_CR0, cr0); 
+    err += vmwrite(VMX_HOST_CR3, cr3);
+    err += vmwrite(VMX_HOST_CR4, cr4);
+    
+    err += vmwrite(VMX_HOST_ES_SEL, rd_es() & ~0x7);
+    err += vmwrite(VMX_HOST_CS_SEL, rd_cs() & ~0x7);
+    err += vmwrite(VMX_HOST_SS_SEL, rd_ss() & ~0x7);
+    err += vmwrite(VMX_HOST_DS_SEL, rd_ds() & ~0x7);
+    err += vmwrite(VMX_HOST_TR_SEL, rd_tr() & ~0x7);
+
+    err += vmwrite(VMX_HOST_TR_BASE, tr_addr(rd_tr(), gdtr_addr(rd_gdtr())));
+    err += vmwrite(VMX_HOST_GDTR_BASE, gdtr_addr(rd_gdtr()));
+    err += vmwrite(VMX_HOST_IDTR_BASE, idtr_addr(rd_idtr()));
+    err += vmwrite(VMX_HOST_SYSENTER_CS, 0);
+    err += vmwrite(VMX_HOST_SYSENTER_ESP, 0);
+    err += vmwrite(VMX_HOST_SYSENTER_EIP, 0);
+    err += vmwrite(VMX_HOST_PAT_F, ia32_cr_pat_rd(NULL));
+
+    ia32_efer_t efer_msr = ia32_efer_rd(NULL);    
+    err += vmwrite(VMX_HOST_EFER_F, efer_msr);
+    assert(ia32_efer_lme_extract(efer_msr));
+    assert(ia32_efer_lma_extract(efer_msr));
+
+    err += vmwrite(VMX_HOST_GS_SEL, 0x0);
+    err += vmwrite(VMX_HOST_GS_BASE, 0x0);       
+    
+    err += vmwrite(VMX_HOST_FS_SEL, 0x0);
+    err += vmwrite(VMX_HOST_FS_BASE, 0x0);
+
+    err += vmwrite(VMX_HOST_RIP, (uint64_t)(&vmx_return_func));
+#ifndef CONFIG_ARRAKISMON
+    vmx_host_msr_area_init(host_msr_area);
+
+    lpaddr_t msr_area_base = mem_to_local_phys((lvaddr_t)host_msr_area);
+    err += vmwrite(VMX_EXIT_MSR_LOAD_F, canonical_form(msr_area_base));
+    err += vmwrite(VMX_EXIT_MSR_LOAD_CNT, VMX_MSR_COUNT);
+#endif
+    assert(err_is_ok(err));
+}
+
+// Writes the VMX controls to the current VMCS. 
+void vmx_set_exec_ctls(void)
+{
+    // VM-execution controls
+    errval_t err = vmwrite(VMX_EXEC_PIN_BASED, pin_based_ctls); 
+    err += vmwrite(VMX_EXEC_PRIM_PROC, pp_based_ctls); 
+    err += vmwrite(VMX_EXEC_SEC_PROC, sp_based_ctls);
+    
+    // VM-entry and VM-exit control fields
+    err += vmwrite(VMX_EXIT_CONTROLS, exit_ctls); 
+    err += vmwrite(VMX_ENTRY_CONTROLS, entry_ctls); 
+
+    vmx_set_exception_bitmap();
+
+    err += vmwrite(VMX_ENTRY_INTR_INFO, 0);
+    err += vmwrite(VMX_ENTRY_EXCP_ERR, 0);
+    err += vmwrite(VMX_ENTRY_INSTR_LEN, 0);
+    assert(err_is_ok(err));
+}
+
+errval_t initialize_vmcs(lpaddr_t vmcs_paddr)
+{
+    struct vmcs *vmcs = (struct vmcs *)local_phys_to_mem(vmcs_paddr);
+
+    ia32_vmx_basic_t vmx_basic;
+    vmx_basic = ia32_vmx_basic_rd(NULL);
+    uint32_t vmcs_rev_id = ia32_vmx_basic_vmcs_rev_id_extract(vmx_basic);
+
+    memset(vmcs, 0x0, BASE_PAGE_SIZE);
+    vmcs->prelude.p.revision_id = vmcs_rev_id;
+    vmcs->prelude.p.shadow = 0;
+    errval_t err = vmclear(vmcs_paddr);
+    err += vmptrld(vmcs_paddr);
+
+    err += vmwrite(VMX_GUEST_VMCS_LPTR_F, ~0x0);
+    err += vmwrite(VMX_GUEST_VMCS_LPTR_H, ~0x0);
+    err += vmwrite(VMX_GUEST_SYSENTER_CS, 0x0);
+    err += vmwrite(VMX_GUEST_SYSENTER_ESP, 0x0);
+    err += vmwrite(VMX_GUEST_SYSENTER_EIP, 0x0);
+#ifdef CONFIG_ARRAKISMON
+    err += vmwrite(VMX_GUEST_DR7, 0x0);
+    err += vmwrite(VMX_GUEST_EFER_F, ia32_efer_rd(NULL) | EFER_LME | EFER_LMA);
+
+    err += vmwrite(VMX_GUEST_ACTIV_STATE, 0x0);
+    err += vmwrite(VMX_GUEST_INTR_STATE, 0x0);
+
+    err += vmwrite(VMX_GUEST_CS_LIM, 0xFFFFFFFF);
+    err += vmwrite(VMX_GUEST_DS_LIM, 0xFFFFFFFF);
+    err += vmwrite(VMX_GUEST_ES_LIM, 0xFFFFFFFF);
+    err += vmwrite(VMX_GUEST_SS_LIM, 0xFFFFFFFF);
+    err += vmwrite(VMX_GUEST_FS_LIM, 0xFFFFFFFF);
+    err += vmwrite(VMX_GUEST_GS_LIM, 0xFFFFFFFF);
+    err += vmwrite(VMX_GUEST_TR_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_LDTR_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_GDTR_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_IDTR_LIM, 0xFFFF);
+
+    err += vmwrite(VMX_GUEST_CS_ACCESS, 0xA09B);
+    err += vmwrite(VMX_GUEST_DS_ACCESS, 0xC093);
+    err += vmwrite(VMX_GUEST_ES_ACCESS, 0xC093);
+    err += vmwrite(VMX_GUEST_FS_ACCESS, 0xC093);
+    err += vmwrite(VMX_GUEST_GS_ACCESS, 0xC093);
+    err += vmwrite(VMX_GUEST_SS_ACCESS, 0xC093);
+    err += vmwrite(VMX_GUEST_TR_ACCESS, 0x8B);
+    err += vmwrite(VMX_GUEST_LDTR_ACCESS, 0x82);
+
+    err += vmwrite(VMX_GUEST_CS_SEL, 0x8);
+    err += vmwrite(VMX_GUEST_SS_SEL, 0x10);
+    err += vmwrite(VMX_GUEST_DS_SEL, 0x10);
+    err += vmwrite(VMX_GUEST_ES_SEL, 0x10); 
+    err += vmwrite(VMX_GUEST_FS_SEL, 0x10);
+    err += vmwrite(VMX_GUEST_GS_SEL, 0x10);
+    err += vmwrite(VMX_GUEST_TR_SEL, 0x10); 
+    err += vmwrite(VMX_GUEST_LDTR_SEL, 0x10);
+    
+    err += vmwrite(VMX_GUEST_CS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_SS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_DS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_ES_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_FS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_GS_BASE, 0x0);    
+    err += vmwrite(VMX_GUEST_TR_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_LDTR_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_GDTR_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_IDTR_BASE, 0x0);
+
+    uint64_t guest_cr0 = 0x60000010 | CR0_PE | CR0_PG;
+    err += vmwrite(VMX_GUEST_CR0, (uint32_t)(guest_cr0 | ia32_vmx_cr0_fixed0_rd(NULL)) & 
+                  ia32_vmx_cr0_fixed1_rd(NULL));
+
+    uint64_t guest_cr4 = CR4_PAE;
+    err += vmwrite(VMX_GUEST_CR4, (guest_cr4 | ia32_vmx_cr4_fixed0_rd(NULL)) & 
+                  ia32_vmx_cr4_fixed1_rd(NULL));
+
+    err += vmwrite(VMX_CR0_GH_MASK, 0UL);
+    err += vmwrite(VMX_CR4_GH_MASK, 0UL);
+#else
+    err += vmwrite(VMX_GUEST_DR7, 0x400);
+    err += vmwrite(VMX_GUEST_EFER_F, 0x0);
+    err += vmwrite(VMX_GUEST_PAT_F, 0x0007040600070406ul);
+
+    err += vmwrite(VMX_GUEST_ACTIV_STATE, 0x0);
+    err += vmwrite(VMX_GUEST_INTR_STATE, 0x0);
+
+    err += vmwrite(VMX_GUEST_CS_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_DS_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_ES_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_FS_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_GS_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_SS_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_TR_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_LDTR_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_GDTR_LIM, 0xFFFF);
+    err += vmwrite(VMX_GUEST_IDTR_LIM, 0xFFFF);
+
+    err += vmwrite(VMX_GUEST_CS_ACCESS, 0x9B);
+    err += vmwrite(VMX_GUEST_DS_ACCESS, 0x93);
+    err += vmwrite(VMX_GUEST_ES_ACCESS, 0x93);
+    err += vmwrite(VMX_GUEST_FS_ACCESS, 0x93);
+    err += vmwrite(VMX_GUEST_GS_ACCESS, 0x93);
+    err += vmwrite(VMX_GUEST_SS_ACCESS, 0x93);
+    err += vmwrite(VMX_GUEST_TR_ACCESS, 0x8B);
+    err += vmwrite(VMX_GUEST_LDTR_ACCESS, 0x82);
+
+    err += vmwrite(VMX_GUEST_CS_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_DS_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_ES_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_FS_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_GS_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_SS_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_TR_SEL, 0x0);
+    err += vmwrite(VMX_GUEST_LDTR_SEL, 0x0);
+
+    err += vmwrite(VMX_GUEST_CS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_DS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_ES_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_FS_BASE, 0x0);    
+    err += vmwrite(VMX_GUEST_GS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_SS_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_TR_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_LDTR_BASE, 0x0);    
+    err += vmwrite(VMX_GUEST_GDTR_BASE, 0x0);
+    err += vmwrite(VMX_GUEST_IDTR_BASE, 0x0);
+
+    err += vmwrite(VMX_GUEST_RFLAGS, 0x200002);
+    err += vmwrite(VMX_GUEST_RIP, 0xFFF0);
+    err += vmwrite(VMX_GUEST_RSP, 0x0);
+
+    uint64_t guest_cr0 = (0x60000010 | ia32_vmx_cr0_fixed0_rd(NULL)) & 
+        ia32_vmx_cr0_fixed1_rd(NULL);
+    err += vmwrite(VMX_GUEST_CR0, guest_cr0 & ~(CR0_PE | CR0_PG));
+
+    uint64_t guest_cr4 = ia32_vmx_cr4_fixed0_rd(NULL) &
+        ia32_vmx_cr4_fixed1_rd(NULL);
+    assert((guest_cr4 & CR4_PCIDE) == 0);
+    err += vmwrite(VMX_GUEST_CR4, guest_cr4);
+        
+    uint64_t cr0_shadow;
+    err += vmread(VMX_GUEST_CR0, &cr0_shadow);
+
+    err += vmwrite(VMX_CR0_RD_SHADOW, cr0_shadow);
+    err += vmwrite(VMX_CR0_GH_MASK, CR0_PE);
+    err += vmwrite(VMX_CR4_GH_MASK, 0x0);
+#endif
+    assert(err_is_ok(err));
+
+    vmx_set_exec_ctls();
+    
+    return SYS_ERR_OK;
+}
+
+static uint32_t fail = 0;
+
+static inline void enter_guest(void)
+{
+    // Set the host state prior to every VM-entry in case the values 
+    // written to the VMCS change. 
+    vmx_set_host_state();
+
+    // This is necessary or else a #GPF will be incurred in the 
+    // monitor domain.
+    uint16_t ldtr_sel = rd_ldtr();
+
+    // Perform most checks that are performed by the processor
+    if (!launched) {
+        check_guest_state_area();
+       check_host_state_area();
+       check_vmx_controls();
+    }
+
+    __asm volatile("mov %[ctrl], %%rdi\n\t"
+                  
+                  // save host host
+                  "mov %%rsp, %%r8\n\t"
+                  "mov %[host_rsp_encoding], %%r9\n\t"
+                  "vmwrite %%r8, %%r9\n\t"
+                  
+                  "mov %%rbx, (148 + 1*8)(%%rdi)\n\t"
+                  "mov %%rbp, (148 + 6*8)(%%rdi)\n\t"
+                  "mov %%r12, (148 + 12*8)(%%rdi)\n\t"
+                  "mov %%r13, (148 + 13*8)(%%rdi)\n\t"
+                  "mov %%r14, (148 + 14*8)(%%rdi)\n\t"
+                  "mov %%r15, (148 + 15*8)(%%rdi)\n\t"
+                  "mov %%cr2, %%rsi\n\t"
+                  "mov %%rsi, 38*8(%%rdi)\n\t"
+
+                  // load guest state             
+                  "mov 37*8(%%rdi), %%rsi\n\t"
+                  "mov %%rsi, %%cr2\n\t"                  
+
+                  "mov 0*8(%%rdi), %%rax\n\t"
+                  "mov 1*8(%%rdi), %%rbx\n\t"
+                  "mov 2*8(%%rdi), %%rcx\n\t"
+                  "mov 3*8(%%rdi), %%rdx\n\t"
+                  "mov 4*8(%%rdi), %%rsi\n\t"
+                  "mov 6*8(%%rdi), %%rbp\n\t"
+                  "mov 8*8(%%rdi), %%r8\n\t"
+                  "mov 9*8(%%rdi), %%r9\n\t"
+                  "mov 10*8(%%rdi), %%r10\n\t"
+                  "mov 11*8(%%rdi), %%r11\n\t"
+                  "mov 12*8(%%rdi), %%r12\n\t"
+                  "mov 13*8(%%rdi), %%r13\n\t"
+                  "mov 14*8(%%rdi), %%r14\n\t"
+                  "mov 15*8(%%rdi), %%r15\n\t"
+                  "mov 5*8(%%rdi), %%rdi\n\t"
+                  
+                  // enter the guest VM
+                  "cmpl $0, %[launched]\n\t"
+                  "jne 1f\n\t"
+                  "sti\n\t"
+                  "vmlaunch\n\t"
+                  "jmp 2f\n\t"
+                  "1: "
+                  "sti\n\t"
+                  "vmresume\n\t"
+                  "2: "
+                  "setbe %[fail]\n\t"
+                  "vmx_return_func:\n\t"
+                  "cli\n\t"
+                  
+                  "push %%rdi\n\t"
+                  "mov %[ctrl], %%rdi\n\t"
+
+                  // save guest state
+                  "mov %%rax, 0*8(%%rdi)\n\t"
+                  "mov %%rbx, 1*8(%%rdi)\n\t"
+                  "mov %%rcx, 2*8(%%rdi)\n\t"
+                  "mov %%rdx, 3*8(%%rdi)\n\t"
+                  "mov %%rsi, 4*8(%%rdi)\n\t"
+                  "mov %%rbp, 6*8(%%rdi)\n\t"
+                  "mov %%r8, 8*8(%%rdi)\n\t"
+                  "mov %%r9, 9*8(%%rdi)\n\t"
+                  "mov %%r10, 10*8(%%rdi)\n\t"
+                  "mov %%r11, 11*8(%%rdi)\n\t"
+                  "mov %%r12, 12*8(%%rdi)\n\t"
+                  "mov %%r13, 13*8(%%rdi)\n\t"
+                  "mov %%r14, 14*8(%%rdi)\n\t"
+                  "mov %%r15, 15*8(%%rdi)\n\t"
+                  
+                  "mov %%cr2, %%rsi\n\t"
+                  "mov %%rsi, 37*8(%%rdi)\n\t"
+
+                  "pop %%rsi\n\t"
+                  "mov %%rsi, 5*8(%%rdi)\n\t"
+
+                  // load host state
+                  "mov (148 + 1*8)(%%rdi), %%rbx\n\t"
+                  "mov (148 + 6*8)(%%rdi), %%rbp\n\t"
+                  "mov (148 + 12*8)(%%rdi), %%r12\n\t"
+                  "mov (148 + 13*8)(%%rdi), %%r13\n\t"
+                  "mov (148 + 14*8)(%%rdi), %%r14\n\t"
+                  "mov (148 + 15*8)(%%rdi), %%r15\n\t"
+                  "mov 38*8(%%rdi), %%rsi\n\t"
+                  "mov %%rsi, %%cr2\n\t"
+                  : [fail] "=m" (fail)  
+                  : [ctrl] "m" (ctrl), [launched] "m" (launched),
+                    [host_rsp_encoding] "i" (VMX_HOST_RSP)
+                  : "memory"
+                  );
+    assert(!fail);
+    wr_ldtr(ldtr_sel);
+
+    launched = 1;
+}
+
+static inline void print_vmcs_info(struct guest_control *g)
+{
+    uint64_t guest_rip, guest_rsp, guest_rflags;
+    uint64_t reason, exit_qual;
+    uint64_t exit_intr_info, intr_err;
+    uint64_t idt_vec_info, idt_vec_err;
+    uint64_t instr_len, instr_info;
+    uint64_t instr_error, gpaddr, gladdr;  
+    uint64_t entry_intr_info, activ_state, intr_state;
+    uint64_t guest_cr0, guest_cr3, guest_cr4;
+    uint64_t guest_efer;
+
+    uint64_t guest_es_sel, guest_es_base, guest_es_lim, guest_es_access;
+    uint64_t guest_cs_sel, guest_cs_base, guest_cs_lim, guest_cs_access; 
+    uint64_t guest_ss_sel, guest_ss_base, guest_ss_lim, guest_ss_access;
+    uint64_t guest_ds_sel, guest_ds_base, guest_ds_lim, guest_ds_access;
+    uint64_t guest_fs_sel, guest_fs_base, guest_fs_lim, guest_fs_access;
+    uint64_t guest_gs_sel, guest_gs_base, guest_gs_lim, guest_gs_access;
+    uint64_t guest_tr_sel, guest_tr_base, guest_tr_lim, guest_tr_access;
+    uint64_t guest_ldtr_sel, guest_ldtr_base, guest_ldtr_lim, guest_ldtr_access;
+    uint64_t guest_idtr_base, guest_idtr_lim;
+    uint64_t guest_gdtr_base, guest_gdtr_lim;
+
+    errval_t err = vmread(VMX_GUEST_ES_SEL, &guest_es_sel);
+    err += vmread(VMX_GUEST_ES_BASE, &guest_es_base);
+    err += vmread(VMX_GUEST_ES_LIM, &guest_es_lim);
+    err += vmread(VMX_GUEST_ES_ACCESS, &guest_es_access);
+    err += vmread(VMX_GUEST_CS_SEL, &guest_cs_sel);
+    err += vmread(VMX_GUEST_CS_BASE, &guest_cs_base);
+    err += vmread(VMX_GUEST_CS_LIM, &guest_cs_lim);
+    err += vmread(VMX_GUEST_CS_ACCESS, &guest_cs_access);
+    err += vmread(VMX_GUEST_SS_SEL, &guest_ss_sel);
+    err += vmread(VMX_GUEST_SS_BASE, &guest_ss_base);
+    err += vmread(VMX_GUEST_SS_LIM, &guest_ss_lim);
+    err += vmread(VMX_GUEST_SS_ACCESS, &guest_ss_access);
+    err += vmread(VMX_GUEST_DS_SEL, &guest_ds_sel);
+    err += vmread(VMX_GUEST_DS_BASE, &guest_ds_base);
+    err += vmread(VMX_GUEST_DS_LIM, &guest_ds_lim);
+    err += vmread(VMX_GUEST_DS_ACCESS, &guest_ds_access);
+    err += vmread(VMX_GUEST_FS_SEL, &guest_fs_sel);
+    err += vmread(VMX_GUEST_FS_BASE, &guest_fs_base);
+    err += vmread(VMX_GUEST_FS_LIM, &guest_fs_lim);
+    err += vmread(VMX_GUEST_FS_ACCESS, &guest_fs_access);
+    err += vmread(VMX_GUEST_GS_SEL, &guest_gs_sel);
+    err += vmread(VMX_GUEST_GS_BASE, &guest_gs_base);
+    err += vmread(VMX_GUEST_GS_LIM, &guest_gs_lim);
+    err += vmread(VMX_GUEST_GS_ACCESS, &guest_gs_access);
+    err += vmread(VMX_GUEST_TR_SEL, &guest_tr_sel);
+    err += vmread(VMX_GUEST_TR_BASE, &guest_tr_base);
+    err += vmread(VMX_GUEST_TR_LIM, &guest_tr_lim);
+    err += vmread(VMX_GUEST_TR_ACCESS, &guest_tr_access);
+    err += vmread(VMX_GUEST_LDTR_SEL, &guest_ldtr_sel);
+    err += vmread(VMX_GUEST_LDTR_BASE, &guest_ldtr_base);
+    err += vmread(VMX_GUEST_LDTR_LIM, &guest_ldtr_lim);
+    err += vmread(VMX_GUEST_LDTR_ACCESS, &guest_ldtr_access);
+    err += vmread(VMX_GUEST_IDTR_BASE, &guest_idtr_base);
+    err += vmread(VMX_GUEST_IDTR_LIM, &guest_idtr_lim);
+    err += vmread(VMX_GUEST_GDTR_BASE, &guest_gdtr_base);
+    err += vmread(VMX_GUEST_GDTR_LIM, &guest_gdtr_lim);
+    
+    err += vmread(VMX_GUEST_RIP, &guest_rip); 
+    err += vmread(VMX_GUEST_RSP, &guest_rsp);   
+    err += vmread(VMX_GUEST_RFLAGS, &guest_rflags);
+    err += vmread(VMX_EXIT_REASON, &reason);
+    err += vmread(VMX_EXIT_QUAL, &exit_qual); 
+    err += vmread(VMX_EXIT_INTR_INFO, &exit_intr_info);
+    err += vmread(VMX_EXIT_INTR_ERR, &intr_err);
+    err += vmread(VMX_IDT_VEC_INFO, &idt_vec_info);
+    err += vmread(VMX_IDT_VEC_ERR, &idt_vec_err);
+    err += vmread(VMX_INSTR_ERROR, &instr_error);
+    err += vmread(VMX_GPADDR_F, &gpaddr);
+    err += vmread(VMX_GL_ADDR, &gladdr);
+    err += vmread(VMX_ENTRY_INTR_INFO, &entry_intr_info);
+    err += vmread(VMX_GUEST_ACTIV_STATE, &activ_state);
+    err += vmread(VMX_GUEST_INTR_STATE, &intr_state);
+    err += vmread(VMX_EXIT_INSTR_LEN, &instr_len);
+    err += vmread(VMX_EXIT_INSTR_INFO, &instr_info);
+    err += vmread(VMX_GUEST_CR0, &guest_cr0);
+    err += vmread(VMX_GUEST_CR3, &guest_cr3);
+    err += vmread(VMX_GUEST_CR4, &guest_cr4);
+    err += vmread(VMX_GUEST_EFER_F, &guest_efer);
+    assert(err_is_ok(err));
+
+    printf("VMCS info:\n");
+    printf("\tvmexit reason = %d\n", (int)reason & 0xFFFF);
+    printf("\texit qualification = 0x%"PRIx64"\n", exit_qual);  
+    printf("\tBit 31 of reason = %x\n", ((int)reason >> 31) & 1);
+    
+    printf("\tVM-exit interruption information = 0x%"PRIx64"\n", exit_intr_info);
+    printf("\tVM-exit interruption error = 0x%"PRIx64"\n", intr_err);
+
+    printf("\tVM-entry interruption info=0x%"PRIx64"\n", entry_intr_info);
+
+    printf("\tIDT vector information = 0x%"PRIx64"\n", idt_vec_info);
+    printf("\tIDT vector error = 0x%"PRIx64"\n", idt_vec_err);
+
+    printf("\tInstruction error = 0x%"PRIx64", gladdr = 0x%"PRIx64", gpaddr = 0x%"PRIx64"\n",
+          instr_error, gpaddr, gladdr);
+    printf("\tActivity state=0x%"PRIx64", Interruptibility state=0x%"PRIx64"\n", 
+          activ_state, intr_state);  
+    printf("\tVM-exit instruction length = 0x%"PRIx64"\n", instr_len);
+    printf("\tVM-exit instruction info = 0x%"PRIx64"\n", instr_info);
+    
+    printf("\tguest_rip = 0x%"PRIx64", guest_rflags = 0x%"PRIx64"\n", 
+          guest_rip, guest_rflags);
+    printf("\tRAX=0x%"PRIx64"    RBX=0x%"PRIx64"    RCX=0x%"PRIx64"    RDX=0x%"PRIx64"\n",
+          g->regs.rax, g->regs.rbx, g->regs.rcx, g->regs.rdx);
+    printf("\tRSP=0x%"PRIx64"    RBP=0x%"PRIx64"    RSI=0x%"PRIx64"    RDI=0x%"PRIx64"\n",
+          guest_rsp, g->regs.rbp, g->regs.rsi, g->regs.rdi);
+    printf("\tR8 =0x%"PRIx64"    R9 =0x%"PRIx64"    R10=0x%"PRIx64"    R11=0x%"PRIx64"\n",
+          g->regs.r8, g->regs.r9, g->regs.r10, g->regs.r11);
+    printf("\tR12=0x%"PRIx64"    R13=0x%"PRIx64"    R14=0x%"PRIx64"    R15=0x%"PRIx64"\n",
+          g->regs.r12, g->regs.r13, g->regs.r14, g->regs.r15);
+    printf("\tCR0=0x%"PRIx64", CR3=0x%"PRIx64", CR4=0x%"PRIx64"\n", 
+          guest_cr0, guest_cr3, guest_cr4);
+    
+    printf("\tES: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_es_sel, guest_es_base, guest_es_lim, guest_es_access);  
+    printf("\tCS: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_cs_sel, guest_cs_base, guest_cs_lim, guest_cs_access);  
+    printf("\tSS: sel= 0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_ss_sel, guest_ss_base, guest_ss_lim, guest_ss_access);  
+    printf("\tDS: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_ds_sel, guest_ds_base, guest_ds_lim, guest_ds_access);  
+    printf("\tFS: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_fs_sel, guest_fs_base, guest_fs_lim, guest_fs_access);  
+    printf("\tGS: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_gs_sel, guest_gs_base, guest_gs_lim, guest_gs_access);  
+    printf("\tTR: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_tr_sel, guest_tr_base, guest_tr_lim, guest_tr_access);  
+    printf("\tLDTR: sel=0x%"PRIx64", base=0x%"PRIx64", lim=0x%"PRIx64", access=0x%"PRIx64"\n", 
+          guest_ldtr_sel, guest_ldtr_base, guest_ldtr_lim, guest_ldtr_access);  
+    printf("\tIDTR: base=0x%"PRIx64", lim=0x%"PRIx64"\n", 
+          guest_idtr_base, guest_idtr_lim);  
+    printf("\tGDTR: base=0x%"PRIx64", lim=0x%"PRIx64"\n", 
+          guest_gdtr_base, guest_gdtr_lim);  
+
+    printf("\tEFER = 0x%"PRIx64"\n", guest_efer);
+}
+
+static inline uint64_t interruption_type(uint64_t intr_info) {
+    return (intr_info >> 8) & 0x7;
+}
+
+static void __attribute__ ((noreturn)) 
+call_monitor(struct dcb *dcb)
+{
+    ctrl->num_vm_exits_with_monitor_invocation++;
+    /* the guest exited not due to an interrupt but some condition the
+     * monitor has to handle, therefore notify the monitor */
+
+    assert(dcb->is_vm_guest);
+
+    // disable the domain
+    scheduler_remove(dcb);
+
+    // call the monitor
+    errval_t err = lmp_deliver_notification(&dcb->guest_desc.monitor_ep.cap);
+    if (err_is_fail(err)) {
+        printk(LOG_ERR, "Unexpected error delivering VMEXIT");
+    }
+    
+    // run the monitor
+    dispatch(dcb->guest_desc.monitor_ep.cap.u.endpoint.listener);
+}
+
+struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
+                          uint64_t *args, uint64_t rflags, uint64_t rip);
+
+extern uint64_t user_stack_save;
+
+void __attribute__ ((noreturn))
+vmx_vmkit_vmenter (struct dcb *dcb)
+{
+    errval_t err;
+    lpaddr_t lpaddr = gen_phys_to_local_phys(dcb->guest_desc.ctrl.cap.u.frame.base);
+    ctrl = (void *)local_phys_to_mem(lpaddr);
+
+    assert(dcb != NULL);
+    assert(dcb->vspace != 0);
+    assert(dcb->is_vm_guest);
+
+    if (ept_enabled()) {
+        err = vmwrite(VMX_EPTP_F, ((dcb->vspace) & pa_width_mask() & ~BASE_PAGE_MASK) | 0x18);
+       assert(err_is_ok(err));
+    } else {
+        err = vmwrite(VMX_GUEST_CR3, dcb->vspace);
+       assert(err_is_ok(err));
+    }
+   
+ vmx_vmenter_loop:
+
+    enter_guest();
+
+    uint16_t exit_reason;
+    err = vmread(VMX_EXIT_REASON, (uint64_t *)&exit_reason);
+
+    switch(exit_reason) {
+    case VMX_EXIT_REASON_INVAL_VMCS:
+      {
+       // A condition that violates ones of the processor checks may be violated 
+       // during the execution of the guest. With the Linux guest we used, the GS
+       // limit is set to 0x10ffef, which causes one of the checks to fail. 
+       uint64_t gs_lim;
+       err += vmread(VMX_GUEST_GS_LIM, &gs_lim);
+       assert(gs_lim == 0x10ffef);
+       err += vmwrite(VMX_GUEST_GS_LIM, 0xfffef);
+       assert(err_is_ok(err));
+      }
+      goto vmx_vmenter_loop;
+
+    case VMX_EXIT_REASON_EXCEPTION:
+      {
+        uint64_t intr_info, type;
+       err += vmread(VMX_EXIT_INTR_INFO, &intr_info);
+       assert(err_is_ok(err));
+
+       type = interruption_type(intr_info);
+
+       if (type != TYPE_NMI) {
+           call_monitor(dcb);
+           break;
+       }
+      }
+    case VMX_EXIT_REASON_EXT_INTR:
+    case VMX_EXIT_REASON_SMI:
+      {
+       ctrl->num_vm_exits_without_monitor_invocation++;
+
+#ifdef CONFIG_ARRAKISMON
+       uint64_t guest_rip, guest_rsp, guest_rflags;
+       err += vmread(VMX_GUEST_RIP, &guest_rip);
+       err += vmread(VMX_GUEST_RSP, &guest_rsp);
+       err += vmread(VMX_GUEST_RFLAGS, &guest_rflags);
+       
+       uint64_t guest_fs_sel, guest_gs_sel;
+       err += vmread(VMX_GUEST_FS_SEL, &guest_fs_sel); 
+       err += vmread(VMX_GUEST_GS_SEL, &guest_gs_sel);
+       assert(err_is_ok(err));
+
+       arch_registers_state_t *area = NULL;
+
+       // Store user state into corresponding save area
+       if(dispatcher_is_disabled_ip(dcb->disp, guest_rip)) {
+           area = dispatcher_get_disabled_save_area(dcb->disp);
+           dcb->disabled = true;
+       } else {
+           area = dispatcher_get_enabled_save_area(dcb->disp);
+           dcb->disabled = false;
+       }
+       memcpy(area, &ctrl->regs, sizeof(arch_registers_state_t));
+       area->rip = guest_rip;
+       area->rax = ctrl->regs.rax;
+       area->rsp = guest_rsp;
+       area->eflags = guest_rflags;
+       area->fs = guest_fs_sel;
+       area->gs = guest_gs_sel;
+#endif 
+       wait_for_interrupt();
+      }
+      break;
+#ifdef CONFIG_ARRAKISMON
+    case VMX_EXIT_REASON_VMCALL:
+      {
+       // Translate this to a SYSCALL
+       struct registers_x86_64 *regs = &ctrl->regs;
+       uint64_t args[10] = {
+           regs->r10, regs->r8, regs->r9, regs->r12, regs->r13, regs->r14,
+           regs->r15, regs->rax, regs->rbp, regs->rbx
+       };
+       
+       /* printf("VMMCALL\n"); */
+
+       uint64_t guest_rip, guest_rsp, guest_rflags;
+       err += vmread(VMX_GUEST_RIP, &guest_rip);
+       err += vmread(VMX_GUEST_RSP, &guest_rsp);
+       err += vmread(VMX_GUEST_RFLAGS, &guest_rflags);
+       // Advance guest RIP to next instruction
+       err += vmwrite(VMX_GUEST_RIP, guest_rip + 3);
+       assert(err_is_ok(err));
+
+       user_stack_save = guest_rsp;
+       
+       struct sysret ret = sys_syscall(regs->rdi, regs->rsi, regs->rdx, 
+                                       args, guest_rflags, guest_rip + 3);
+       regs->rax = ret.error;
+       regs->rdx = ret.value;
+      }
+      goto vmx_vmenter_loop;
+#endif
+    default:      
+        call_monitor(dcb);
+       break;
+    }
+}
index c7950d4..bcdfabc 100644 (file)
@@ -234,37 +234,38 @@ void __attribute__ ((noreturn)) dispatch(struct dcb *dcb)
     arch_registers_state_t *disabled_area =
         dispatcher_get_disabled_save_area(handle);
 
-    assert(disp != NULL);
-    disp->systime = kernel_now + kcb_current->kernel_off;
-       TRACE(KERNEL, SC_YIELD, 1);
+    if(disp != NULL) {
+        disp->systime = kernel_now + kcb_current->kernel_off;
+    }
+    TRACE(KERNEL, SC_YIELD, 1);
        
     if (dcb->disabled) {
-        debug(SUBSYS_DISPATCH, "resume %.*s at 0x%" PRIx64 "\n", DISP_NAME_LEN,
-              disp->name, (uint64_t)registers_get_ip(disabled_area));
-        assert(dispatcher_is_disabled_ip(handle,
-                                         registers_get_ip(disabled_area)));
+        if (disp != NULL) {
+            debug(SUBSYS_DISPATCH, "resume %.*s at 0x%" PRIx64 "\n", DISP_NAME_LEN,
+                  disp->name, (uint64_t)registers_get_ip(disabled_area));
+            assert(dispatcher_is_disabled_ip(handle,
+                                             registers_get_ip(disabled_area)));
+        }
 
-#if defined(__x86_64__) && !defined(__k1om__)
         if(!dcb->is_vm_guest) {
             resume(disabled_area);
+#if defined(__x86_64__) && !defined(__k1om__)
         } else {
             vmkit_vmenter(dcb);
-        }
-#else
-        resume(disabled_area);
 #endif
+        }
     } else {
-        debug(SUBSYS_DISPATCH, "dispatch %.*s\n", DISP_NAME_LEN, disp->name);
-        assert(disp->dispatcher_run != 0);
-        disp->disabled = 1;
-#if defined(__x86_64__) && !defined(__k1om__)
+        if (disp != NULL) {
+            debug(SUBSYS_DISPATCH, "dispatch %.*s\n", DISP_NAME_LEN, disp->name);
+            assert(disp->dispatcher_run != 0);
+            disp->disabled = 1;
+        }
         if(!dcb->is_vm_guest) {
             execute(disp->dispatcher_run);
+#if defined(__x86_64__) && !defined(__k1om__)
         } else {
-            vmkit_vmexec(dcb, disp->dispatcher_run);
+            vmkit_vmexec(dcb, (disp) ? disp->dispatcher_run : 0);
         }
-#else
-        execute(disp->dispatcher_run);
 #endif
     }
 } // end function: dispatch
diff --git a/kernel/include/arch/x86_64/svm_vmkit.h b/kernel/include/arch/x86_64/svm_vmkit.h
new file mode 100644 (file)
index 0000000..6ee463f
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * \file
+ * \brief Contains VMKit kernel interface for version using SVM extensions.
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#ifndef SVM_VMKIT_H
+#define SVM_VMKIT_H
+
+// SVM relevant CPUID info
+#define CPUID_AMD_EXTFEAT       0x80000001
+#define AMD_EXTFEAT_ECX_SVM     (1 << 2)
+
+// some EXITCODE values
+#define VMEXIT_INTR     0x60
+#define VMEXIT_NMI      0x61
+#define VMEXIT_SMI      0x62
+#define VMEXIT_VMMCALL  0x81
+
+errval_t svm_enable_virtualization (void);
+void __attribute__ ((noreturn)) svm_vmkit_vmenter (struct dcb *dcb);
+
+#endif // SVM_VMKIT_H
index aeb9279..2ab1472 100644 (file)
@@ -15,6 +15,9 @@
 #ifndef VMKIT_H
 #define VMKIT_H
 
+#include "vmx_vmkit.h"
+#include "svm_vmkit.h"
+
 #define VMKIT_ERR_OK        0
 #define VMKIT_ERR_UNAVAIL   (-1)
 
diff --git a/kernel/include/arch/x86_64/vmx_checks.h b/kernel/include/arch/x86_64/vmx_checks.h
new file mode 100644 (file)
index 0000000..5620938
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+ * \file
+ * \brief Functions used in the rigorous checks that are performed (optionally) 
+ *  before launching and/or resuming a VM-guest.
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#ifndef VMX_CHECKS_H
+#define VMX_CHECKS_H
+
+#define INTR_TYPE_EXT_INTR 0
+#define INTR_TYPE_NMI 2
+#define INTR_TYPE_HW_EXCEP 3
+#define INTR_TYPE_SW_INTR 4
+#define INTR_TYPE_PRIV_SW_EXCEP 5
+#define INTR_TYPE_SW_EXCEP 6
+#define INTR_TYPE_OTHER 7
+
+#define ACCESS_UNUSABLE (1 << 16)
+#define SEL_TI (1 << 2)
+#define SEL_RPL (0x3)
+#define SEG_TYPE_ACCESSED (1 << 0)
+#define SEG_TYPE_READABLE (1 << 1)
+#define SEG_TYPE_CODE_SEGMENT (1 << 3)
+
+static inline int seg_reg_usable(int access_rights)
+{
+    return !(access_rights & ACCESS_UNUSABLE);
+}
+
+static inline int seg_access_type(uint64_t access_rights)
+{
+    return ((access_rights >> 0) & 0xF);
+}
+
+static inline int seg_access_s(uint64_t access_rights)
+{
+    return ((access_rights >> 4) & 0x1);
+}
+
+static inline int seg_access_dpl(uint64_t access_rights)
+{
+    return ((access_rights >> 5) & 0x3);
+}
+
+static inline int seg_access_p(uint64_t access_rights)
+{
+    return ((access_rights >> 7) & 0x1);
+}
+
+static inline int seg_access_l(uint64_t access_rights)
+{
+    return ((access_rights >> 13) & 0x1);
+}
+
+static inline int seg_access_db(uint64_t access_rights)
+{
+    return ((access_rights >> 14) & 0x1);
+}
+
+static inline int seg_access_g(uint64_t access_rights)
+{
+    return ((access_rights >> 15) & 0x1);
+}
+
+static inline int ept_type(uint64_t eptp) 
+{
+    return ((eptp >> 0) & 0x7);
+}
+
+static inline int ept_page_walk_length(uint64_t eptp)
+{
+    return ((eptp >> 3) & 0x7);
+}
+
+static inline int ept_accessed_dirty_enable(uint64_t eptp)
+{
+    return ((eptp >> 6) & 0x1);
+}
+
+void check_guest_state_area(void);
+void check_host_state_area(void);
+void check_vmx_controls(void);
+
+#endif // VMX_CHECKS_H
diff --git a/kernel/include/arch/x86_64/vmx_vmkit.h b/kernel/include/arch/x86_64/vmx_vmkit.h
new file mode 100644 (file)
index 0000000..af6dbcd
--- /dev/null
@@ -0,0 +1,323 @@
+/**
+ * \file
+ * \brief Contains VMKit kernel interface for version using VMX extensions.
+ */
+
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#ifndef VMX_VMKIT_H
+#define VMX_VMKIT_H
+
+#include <arch/x86/x86.h>
+#include <arch/x86_64/x86.h>
+#include <barrelfish_kpi/vmkit.h>
+#include <barrelfish_kpi/vmx_controls.h>
+#include <barrelfish_kpi/vmx_encodings.h>
+#include <barrelfish_kpi/vmx_exit_reasons.h>
+
+#include <dev/ia32_dev.h>
+
+// Number of MSRs that are loaded on VM-exit
+#define VMX_MSR_COUNT 5
+
+// Size of the host MSR-load area
+#define VMX_MSR_AREA_SIZE (VMX_MSR_COUNT * 16)
+
+#define MSR_KERNEL_GS_BASE 0xc0000102
+#define MSR_STAR           0xc0000081
+#define MSR_LSTAR          0xc0000082
+#define MSR_CSTAR          0xc0000083
+#define MSR_SFMASK         0xc0000084
+
+#define PAGE_SIZE 0x1000
+#define CPUID_PA_WIDTH (0x80000008)
+#define VMX_PA_WIDTH_MASK (0xFF)
+#define CPUID_VMX (0x1) 
+#define VMX_SUPPORT (1 << 5)
+
+#define TYPE_EXT_INTR (0)
+#define TYPE_NMI (2)
+#define TYPE_HW_EXCP (3)
+#define TYPE_SW_EXCP (6)
+
+#define RFLAGS_IF (1 << 9)
+#define RFLAGS_VM (1 << 17)
+
+#define EFER_LME (1UL << 8)
+#define EFER_LMA (1UL << 10)
+#define EFER_NXE (1UL << 11)
+
+#define CR0_PE (1 << 0)
+#define CR0_NW (1 << 29)
+#define CR0_CD (1 << 30)
+#define CR0_PG (1 << 31)
+
+#define CR4_PAE (1UL << 5)
+#define CR4_MCE (1UL << 6)
+#define CR4_PGE (1UL << 7)
+#define CR4_PCE (1UL << 8)
+#define CR4_VMXE (1UL << 13)
+#define CR4_PCIDE (1UL << 17)
+
+#define DWORD_MS(val) ((val >> 32) & 0xFFFFFFFF)
+#define DWORD_LS(val) (val & 0xFFFFFFFF)
+
+union vmcs_prelude {
+    uint32_t raw;
+    struct {
+        uint32_t revision_id :31;
+        uint32_t shadow      :1;
+    } p;
+};
+
+// Represents a VMCS structure which is comprised of up to 4-KB, 
+// the data portion of the structure is implemenation-specific.
+struct vmcs {
+    union vmcs_prelude prelude;
+    uint32_t vmx_abort;
+    char data[PAGE_SIZE - 8];
+} __attribute__ ((aligned(PAGE_SIZE)));
+
+static const int benign_exceptions[] = {1,2,3,4,5,6,7,9,16,17,18,19};
+static inline bool benign_exception(int vector)
+{
+    for (int i = 0; i < sizeof(benign_exceptions); i++) {
+        if (benign_exceptions[i] == vector) return true;
+    }
+    return false;
+}
+
+static const int contributory_exceptions[] = {0,10,11,12,13};
+static inline bool contributory_exception(int vector)
+{
+    for (int i = 0; i < sizeof(contributory_exceptions); i++) {
+        if (contributory_exceptions[i] == vector) return true;
+    }
+    return false;
+}
+
+// Returns true if secondary processor-based VM-execution controls 
+// are used.
+static inline bool sec_ctls_used(uint64_t pp_controls) 
+{
+    return !!(pp_controls & PP_CLTS_SEC_CTLS);
+}
+
+// Returns the canonical form of the address addr.
+static inline uint64_t canonical_form(uint64_t addr)
+{
+    if ((addr >> 47) & 0x1) {
+        return (addr | ~0xffffffffffffUL); 
+    } else {
+        return (addr & 0xffffffffffffUL);
+    }
+}
+
+// Functions for reading segment registers are used in saving the 
+// host state (via vmwrite instructions) prior to VM-entry
+
+static inline uint16_t rd_es(void)
+{
+    uint16_t es;
+    __asm volatile("mov %%es, %[es]" : [es] "=r" (es));
+    return es;
+}
+
+static inline uint16_t rd_cs(void)
+{
+    uint16_t cs;
+    __asm volatile("mov %%cs, %[cs]" : [cs] "=r" (cs));
+    return cs;
+}
+
+static inline uint16_t rd_ss(void)
+{
+    uint16_t ss;
+    __asm volatile("mov %%ss, %[ss]" : [ss] "=r" (ss));
+    return ss;
+}
+
+static inline uint16_t rd_ds(void)
+{
+    uint16_t ds;
+    __asm volatile("mov %%ds, %[ds]" : [ds] "=r" (ds));
+    return ds;
+}
+
+static inline uint16_t rd_fs(void)
+{
+    uint16_t fs;
+    __asm volatile("mov %%fs, %[fs]" : [fs] "=r" (fs));
+    return fs;
+}
+
+static inline uint16_t rd_gs(void)
+{
+    uint16_t gs;
+    __asm volatile("mov %%gs, %[gs]" : [gs] "=r" (gs));
+    return gs;
+}
+
+static inline uint16_t rd_tr(void)
+{
+    uint16_t tr;
+    __asm volatile("str %[tr]" : [tr] "=r" (tr));
+    return tr;
+}
+
+static inline uint64_t rd_idtr(void)
+{
+    uint64_t idtr;
+    __asm volatile("sidt %[idtr]" : [idtr] "=m" (idtr));
+    return idtr;
+}
+
+static inline uint16_t rd_ldtr(void)
+{
+    uint16_t ldtr;
+    __asm volatile("sldt %[ldtr]" : [ldtr] "=r" (ldtr));
+    return ldtr;
+}
+
+static inline void wr_ldtr(uint16_t val)
+{
+  __asm volatile("lldt %[val]" :: [val] "m" (val) : "memory");
+}
+
+static inline uint64_t rd_gdtr(void)
+{
+    uint64_t gdtr;
+    __asm volatile("sgdt %[gdtr]" : [gdtr] "=m" (gdtr));
+    return gdtr;
+}
+
+static inline uint64_t gdtr_addr(uint64_t gdtr)
+{
+    return canonical_form(gdtr >> 16);
+}
+
+static inline uint64_t idtr_addr(uint64_t idtr)
+{
+    return canonical_form(idtr >> 16);
+}
+
+// Return true if the segment selector is in the the LDT (the TI flag 
+// is set), else false, meaning that it's contained in the GDT.
+static inline int seg_in_ldt(uint16_t seg_sel)
+{
+    return ((seg_sel >> 2) & 0x1);
+}
+
+// The index of corresponding segment descriptor in the LDT or GDT.
+static inline int seg_sel_index(uint16_t seg_sel)
+{
+    return ((seg_sel >> 3) & 0x1FFF);
+}
+
+static inline uint64_t tr_addr(uint16_t tr_sel, uint64_t gdtr_base)
+{
+    int tss_index_low  = seg_sel_index(tr_sel);
+    int tss_index_high = tss_index_low + 1;
+
+    uint64_t *gdt_new = (uint64_t *)gdtr_base;
+    uint64_t tss_low = gdt_new[tss_index_low];
+    uint64_t tss_high = gdt_new[tss_index_high];
+    
+    uint64_t tss_base = (((tss_low >> 16) & 0xFFFFFF)   |
+                         ((tss_low >> 32) & 0xFF000000) |
+                         (tss_high << 32));
+    return tss_base;
+}
+
+static inline void vmlaunch(void)
+{
+    __asm volatile("vmlaunch");
+}
+
+static inline void vmresume(void)
+{
+    __asm volatile("vmresume"); 
+}
+
+static inline void enable_vmx(void)
+{
+    wrcr4(rdcr4() | CR4_VMXE);
+}
+
+static inline int vmx_enabled(void)
+{
+    return (rdcr4() & CR4_VMXE);
+}
+
+static inline void disable_vmx(void)
+{
+    wrcr4(rdcr4() & ~CR4_VMXE);
+}
+
+static inline uint64_t vmx_fixed_cr0(void) 
+{ 
+    uint64_t cr0_fixed0 = ia32_vmx_cr0_fixed0_rd(NULL);
+    uint64_t cr0_fixed1 = ia32_vmx_cr0_fixed1_rd(NULL);
+
+    uint64_t cr0_1s_mask = (cr0_fixed0 & cr0_fixed1);
+    uint64_t cr0_0s_mask = (~cr0_fixed0 & ~cr0_fixed1);
+    return ((rdcr0() | cr0_1s_mask) & ~cr0_0s_mask);
+}
+
+static inline uint64_t vmx_fixed_cr4(void) 
+{ 
+    uint64_t cr4_fixed0 = ia32_vmx_cr4_fixed0_rd(NULL);
+    uint64_t cr4_fixed1 = ia32_vmx_cr4_fixed1_rd(NULL);
+
+    uint64_t cr4_1s_mask = (cr4_fixed0 & cr4_fixed1);
+    uint64_t cr4_0s_mask = (~cr4_fixed0 & ~cr4_fixed1);
+    return ((rdcr4() | cr4_1s_mask) & ~cr4_0s_mask);
+}
+
+static inline bool is_canonical(uint64_t addr)
+{
+    uint64_t canonical_addr = canonical_form(addr);
+    return (canonical_addr == addr);
+}
+
+// Returns the physical-address width supported by the logical
+// processor.
+static inline uint64_t physical_address_width(void)
+{
+    uint32_t cpuid_eax;
+    cpuid(CPUID_PA_WIDTH, &cpuid_eax, NULL, NULL, NULL);
+    return (cpuid_eax & VMX_PA_WIDTH_MASK);
+}
+
+// Returns a mask for the bits 0:N-1, where N is the physical-address
+// width supported by the logical processor.
+static inline uint64_t pa_width_mask(void)
+{
+    uint64_t pa_width = physical_address_width();
+    uint64_t physical_addr_width_mask = (1UL << pa_width) - 1;
+    return physical_addr_width_mask;
+}
+
+errval_t vmptrld(lpaddr_t vmcs_base);
+lpaddr_t vmptrst(void);
+errval_t vmclear(lpaddr_t vmcs_base);
+errval_t vmread(uintptr_t encoding, lvaddr_t *dest_addr);
+errval_t vmwrite(uintptr_t encoding, uintptr_t source);
+errval_t vmxon(lpaddr_t base_addr);
+errval_t vmxoff(void);
+
+errval_t initialize_vmcs(lpaddr_t vmcs_base);
+void vmx_set_exec_ctls(void);
+
+errval_t vmx_enable_virtualization (void);
+void __attribute__ ((noreturn)) vmx_vmkit_vmenter (struct dcb *dcb);
+
+#endif // VMX_VMKIT_H
index 0c81acc..dab5981 100644 (file)
@@ -106,7 +106,8 @@ union x86_64_ptable_entry {
         uint64_t        dirty           :1;
         uint64_t        always1         :1;
         uint64_t        global          :1;
-        uint64_t        available       :3;
+        uint64_t        available       :2;
+        uint64_t        vtd_snoop       :1;
         uint64_t        attr_index      :1;
         uint64_t        reserved        :17;
         uint64_t        base_addr       :10;
@@ -124,7 +125,8 @@ union x86_64_ptable_entry {
         uint64_t        dirty           :1;
         uint64_t        always1         :1;
         uint64_t        global          :1;
-        uint64_t        available       :3;
+        uint64_t        available       :2;
+        uint64_t        vtd_snoop       :1;
         uint64_t        attr_index      :1;
         uint64_t        reserved        :8;
         uint64_t        base_addr       :X86_64_PAGING_LARGE_BASE_BITS;
@@ -142,7 +144,8 @@ union x86_64_ptable_entry {
         uint64_t        dirty           :1;
         uint64_t        attr_index      :1;
         uint64_t        global          :1;
-        uint64_t        available       :3;
+        uint64_t        available       :2;
+        uint64_t        vtd_snoop       :1;
         uint64_t        base_addr       :X86_64_PAGING_BASE_BASE_BITS;
         uint64_t        reserved2       :X86_64_PAGING_RESERVED_BITS;
         uint64_t        available2      :11;
@@ -265,6 +268,7 @@ static inline void paging_x86_64_map_large(union x86_64_ptable_entry *entry,
     tmp.large.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
     tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
     tmp.large.always1 = 1;
+    tmp.large.vtd_snoop = bitmap & X86_64_VTD_PAGE_SNOOP ? 1 : 0;
     tmp.large.base_addr = base >> 21;
 
     *entry = tmp;
@@ -299,6 +303,7 @@ static inline void paging_x86_64_map(union x86_64_ptable_entry * NONNULL entry,
     tmp.base.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
 #endif
     tmp.base.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
+    tmp.base.vtd_snoop = bitmap & X86_64_VTD_PAGE_SNOOP ? 1 : 0;
     tmp.base.base_addr = base >> 12;
 
     *entry = tmp;
index a3fc4b8..455292b 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <barrelfish/barrelfish.h>
+#include <barrelfish/caddr.h>
 #include <barrelfish/nameservice_client.h>
 
 #include <if/acpi_defs.h>
@@ -56,6 +57,45 @@ errval_t acpi_get_vbe_bios_cap(struct capref *retcap, size_t *retsize)
     return err_is_fail(err) ? err : msgerr;
 }
 
+errval_t vtd_create_domain(struct capref pml4)
+{
+    assert(rpc_client != NULL);
+    errval_t err, msgerr;
+    err = rpc_client->vtbl.create_domain(rpc_client, pml4, &msgerr);
+    return err_is_fail(err) ? err : msgerr;
+}
+
+errval_t vtd_delete_domain(struct capref pml4)
+{
+    assert(rpc_client != NULL);
+    errval_t err, msgerr;
+    err = rpc_client->vtbl.delete_domain(rpc_client, pml4, &msgerr);
+    return err_is_fail(err) ? err : msgerr;
+}
+
+errval_t vtd_domain_add_device(int seg, int bus, int dev, int func, struct capref pml4) 
+{
+    assert(rpc_client != NULL);
+    errval_t err, msgerr;
+    err = rpc_client->vtbl.vtd_add_device(rpc_client, seg, bus, dev, func, pml4, &msgerr);
+    return err_is_fail(err) ? err : msgerr;
+}
+
+errval_t vtd_domain_remove_device(int seg, int bus, int dev, int func, struct capref pml4) 
+{
+    assert(rpc_client != NULL);
+    errval_t err, msgerr;
+    err = rpc_client->vtbl.vtd_remove_device(rpc_client, seg, bus, dev, func, pml4, &msgerr);
+    return err_is_fail(err) ? err : msgerr;
+}
+
+errval_t vtd_add_devices(void)
+{
+    assert(rpc_client != NULL);
+    errval_t err, msgerr;
+    err = rpc_client->vtbl.vtd_id_dom_add_devices(rpc_client, &msgerr);
+    return err_is_fail(err) ? err : msgerr;
+}
 
 struct acpi_rpc_client* get_acpi_rpc_client(void)
 {
index e25ba40..e0f8681 100644 (file)
 
 [ build library { target = "ahci",
                       cFiles = [ "ahci.c", "ahci_util.c", "sata_fis.c", "ahci_dma_pool.c" ],
-                      flounderBindings = [ "ahci_mgmt" ],
-                      flounderExtraBindings = [ ("ahci_mgmt", ["rpcclient"]) ],
+                      flounderDefs = [ "ata_rw28" ],
+                      flounderBindings = [ "ahci_mgmt", "ata_rw28" ],
+                      flounderExtraBindings = [ ("ahci_mgmt", ["rpcclient"]),
+                                                ("ata_rw28", ["ahci", "rpcclient"]) ],
+                      mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
+                      addLibraries = [ ]
+                },
+  build library { target = "ahci_vsic",
+                      cFiles = [ "ahci.c", "ahci_util.c", "sata_fis.c", "ahci_dma_pool.c", "storage_vsic.c" ],
+                      flounderDefs = [ "ata_rw28" ],
+                      flounderBindings = [ "ahci_mgmt", "ata_rw28" ],
+                      flounderExtraBindings = [ ("ahci_mgmt", ["rpcclient"]),
+                                                ("ata_rw28", ["ahci", "rpcclient"]) ],
                       mackerelDevices = [ "ata_identify", "ahci_port", "ahci_hba" ],
                       addLibraries = [ ]
                 }
diff --git a/lib/ahci/storage_vsic.c b/lib/ahci/storage_vsic.c
new file mode 100644 (file)
index 0000000..1107d9e
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/waitset.h>
+#include <if/ata_rw28_defs.h>
+#include <if/ata_rw28_ahci_defs.h>
+#include <if/ata_rw28_rpcclient_defs.h>
+#include <storage/vsic.h>
+
+struct ahci_vsic {
+    struct ahci_ata_rw28_binding ahci_ata_rw28_binding;
+    struct ata_rw28_rpc_client ata_rw28_rpc;
+    struct ata_rw28_binding *ata_rw28_binding;
+    struct ahci_binding *ahci_binding;
+    errval_t bind_err;
+};
+
+static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa,
+                           off_t offset, size_t size, void *buffer)
+{
+    assert(vsic != NULL);
+    assert(vsa != NULL);
+    assert(buffer != NULL);
+    struct ahci_vsic *mydata = vsic->data;
+    errval_t status;
+
+    errval_t err = mydata->ata_rw28_rpc.vtbl.
+      write_dma(&mydata->ata_rw28_rpc, buffer, STORAGE_VSIC_ROUND(vsic, size),
+               offset, &status);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "write_dma rpc");
+    }
+    if (err_is_fail(status)) {
+        USER_PANIC_ERR(status, "write_dma status");
+    }
+
+    return SYS_ERR_OK;
+}
+
+static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa,
+                          off_t offset, size_t size, void *buffer)
+{
+    assert(vsic != NULL);
+    assert(vsa != NULL);
+    assert(buffer != NULL);
+    struct ahci_vsic *mydata = vsic->data;
+    uint8_t *buf = NULL;
+    size_t bytes_read, toread = STORAGE_VSIC_ROUND(vsic, size);
+
+    errval_t err = mydata->ata_rw28_rpc.vtbl.
+      read_dma(&mydata->ata_rw28_rpc, toread, offset, &buf, &bytes_read);
+    if (err_is_fail(err))
+        USER_PANIC_ERR(err, "read_dma rpc");
+    if (!buf)
+        USER_PANIC("read_dma -> !buf");
+    if (bytes_read != toread)
+        USER_PANIC("read_dma -> read_size != size");
+
+    // XXX: Copy from DMA buffer to user buffer
+    memcpy(buffer, buf, size);
+    free(buf);
+
+    return SYS_ERR_OK;
+}
+
+static errval_t vsic_flush(struct storage_vsic *vsic, struct storage_vsa *vsa)
+{
+  assert(vsic != NULL);
+  assert(vsa != NULL);
+  struct ahci_vsic *mydata = vsic->data;
+  errval_t outerr;
+
+  errval_t err = mydata->ata_rw28_rpc.vtbl.
+    flush_cache(&mydata->ata_rw28_rpc, &outerr);
+  assert(err_is_ok(err));
+
+  return outerr;
+}
+
+static errval_t vsic_wait(struct storage_vsic *vsic)
+{
+  // XXX: Interface currently synchronous
+  return SYS_ERR_OK;
+}
+
+static struct storage_vsic_ops ahci_vsic_ops = {
+    .write = vsic_write,
+    .read = vsic_read,
+    .flush = vsic_flush,
+    .wait = vsic_wait,
+};
+
+static void ahci_bind_cb(void *st, errval_t err, struct ahci_binding *_binding)
+{
+    assert(err_is_ok(err));
+    struct ahci_vsic *mydata = st;
+    mydata->ahci_binding = _binding;
+}
+
+// XXX: This could be made public and controlled by the programmer instead of
+// the commandline
+static errval_t ahci_vsic_alloc(struct storage_vsic *vsic, uint8_t port)
+{
+    assert(vsic != NULL);
+    errval_t err;
+    struct ahci_vsic *mydata = malloc(sizeof(struct ahci_vsic));
+    assert(mydata != NULL);
+    memset(mydata, 0, sizeof(struct ahci_vsic));
+
+    // init ahci management binding
+    err = ahci_init(port, ahci_bind_cb, mydata, get_default_waitset());
+    assert(err_is_ok(err));
+
+    while(!mydata->ahci_binding) {
+        event_dispatch(get_default_waitset());
+    }
+
+    // init ata flounder binding
+    err = ahci_ata_rw28_init(&mydata->ahci_ata_rw28_binding,
+                             get_default_waitset(), mydata->ahci_binding);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "ahci_ata_rw28_init");
+    }
+    mydata->ata_rw28_binding =
+        (struct ata_rw28_binding*)&mydata->ahci_ata_rw28_binding;
+
+    // init RPC client
+    err = ata_rw28_rpc_client_init(&mydata->ata_rw28_rpc,
+                                   mydata->ata_rw28_binding);
+    if (err_is_fail(err)) {
+        USER_PANIC_ERR(err, "ata_rw28_rpc_client_init");
+    }
+
+    // Init VSIC data structure
+    vsic->ops = ahci_vsic_ops;
+    vsic->data = mydata;
+    vsic->blocksize = 512;     // XXX: Determine from drive?
+
+    return SYS_ERR_OK;
+}
+
+errval_t storage_vsic_driver_init(int argc, const char **argv,
+                                 struct storage_vsic *vsic)
+{
+    // init dma pool
+    ahci_dma_pool_init(1024*1024);
+
+    // Allocate port 0
+    return ahci_vsic_alloc(vsic, 0);
+}
index 82c0329..bad1d0f 100644 (file)
@@ -12,6 +12,9 @@
 
 [ build library { target = "arranet",
                   cFiles = [ "arranet.c", "inet_chksum.c", "ip_addr.c" ],
-                  flounderDefs = [ "net_queue_manager" ]
+                  flounderDefs = [ "acpi", "net_queue_manager" ],
+                  flounderBindings = [ "acpi" ],
+                  flounderExtraBindings = [ ("acpi", ["rpcclient"]) ],
+                  addLibraries = [ "acpi_client", "skb" ]
                 }
 ]
index fa06720..b9c9951 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, ETH Zurich.
+ * Copyright (c) 2014, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -17,6 +17,8 @@
 #include <assert.h>
 #include <barrelfish/barrelfish.h>
 #include <barrelfish/inthandler.h>
+#include <barrelfish/sys_debug.h>
+#include <skb/skb.h>
 #include <sys/socket.h>
 #include <netif/e1000.h>
 #include <limits.h>
@@ -26,6 +28,7 @@
 #include <netdb.h>
 #include <arranet.h>
 #include <arranet_impl.h>
+#include <acpi_client/acpi_client.h>
 
 #include "inet_chksum.h"
 
@@ -50,6 +53,9 @@ struct client_closure *g_cl = NULL;
 
 #define MAX_PEERS       256
 
+static int use_vtd = 0;
+static int vtd_coherency = 1;
+
 struct peer {
     uint32_t ip;
     struct eth_addr mac;
@@ -59,8 +65,15 @@ struct peer {
 // IP addresses are in network byte order!
 static struct peer peers[MAX_PEERS] = {
     {
+        // XXX: This needs to be updated each time the tap interface is re-initialized
         .ip = 0x0102000a,       // 10.0.2.1
-        .mac.addr = "\x86\x86\x0b\xda\x22\xd7",
+        /* .mac.addr = "\x86\x86\x0b\xda\x22\xd7", */
+        .mac.addr = "\x12\x67\xb9\x3e\xe2\x2c",
+    },
+    {
+        // XXX: This needs to be updated each time the tap interface is re-initialized
+        .ip = 0x0164a8c0,       // 192.168.100.1
+        .mac.addr = "\x5e\x93\xf2\xf1\xeb\xfa",
     },
     {
         .ip = 0xaf06d080,       // 128.208.6.175 - swingout2
@@ -83,7 +96,7 @@ static struct peer peers[MAX_PEERS] = {
         .mac.addr = "\xa0\x36\x9f\x10\x03\x52",
     },
 };
-static int peers_alloc = 6;             // Set number of static ARP here!
+static int peers_alloc = 7;             // Set number of static ARP here!
 
 #ifdef DEBUG_LATENCIES
 static int rx_packets_available = MAX_PACKETS;
@@ -91,6 +104,7 @@ static int rx_packets_available = MAX_PACKETS;
 
 struct socket {
     struct socket *prev, *next;
+    int type, protocol;
     int fd;
     bool passive, nonblocking, connected, hangup, shutdown;
     struct sockaddr_in bound_addr;
@@ -98,6 +112,11 @@ struct socket {
     uint32_t my_seq, peer_seq, next_ack;
 };
 
+struct pkt_ip_headers {
+    struct eth_hdr eth;
+    struct ip_hdr ip;
+} __attribute__ ((packed));
+
 struct pkt_udp_headers {
     struct eth_hdr eth;
     struct ip_hdr ip;
@@ -147,6 +166,7 @@ size_t hash_unaligned = 0;
 
 static bool arranet_udp_accepted = false;
 static bool arranet_tcp_accepted = false;
+static bool arranet_raw_accepted = false;
 
 //#define TCP_LOCAL_PORT_RANGE_START        0xc000
 #define TCP_LOCAL_PORT_RANGE_START        8081
@@ -244,7 +264,8 @@ struct mac2ip {
 static struct mac2ip ip_config[] = {
     {   // QEMU
         .mac = "\x52\x54\x00\x12\x34\x56",
-        .ip = 0x0a00020f,       // 10.0.2.15
+        /* .ip = 0x0a00020f,       // 10.0.2.15 */
+        .ip = 0xc0a8640f,       // 192.168.100.15
     },
     {
         // QEMU2
@@ -284,27 +305,14 @@ static struct mac2ip ip_config[] = {
 static uint8_t arranet_mymac[ETHARP_HWADDR_LEN];
 static uint32_t arranet_myip = 0;
 
-/******** NYI *********/
-
-struct thread_mutex *lwip_mutex = NULL;
-struct waitset *lwip_waitset = NULL;
-
-void lwip_mutex_lock(void)
-{
-}
-
-void lwip_mutex_unlock(void)
-{
-}
-
 int lwip_read(int s, void *mem, size_t len)
 {
-    assert(!"NYI");
+    return lwip_recv(s, mem, len, 0);
 }
 
 int lwip_write(int s, const void *data, size_t size)
 {
-    assert(!"NYI");
+    return lwip_send(s, data, size, 0);
 }
 
 int lwip_fcntl(int s, int cmd, int val)
@@ -438,11 +446,6 @@ int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
     return 0;
 }
 
-struct hostent *lwip_gethostbyname(const char *name)
-{
-    assert(!"NYI");
-}
-
 int lwip_getaddrinfo(const char *nodename, const char *servname,
                      const struct addrinfo *hints, struct addrinfo **res)
 {
@@ -458,7 +461,11 @@ int lwip_getaddrinfo(const char *nodename, const char *servname,
     // Return dummy UDP socket address
     r->ai_flags = AI_PASSIVE;
     r->ai_family = AF_INET;
-    r->ai_socktype = SOCK_DGRAM;
+    if(hints->ai_socktype != 0) {
+        r->ai_socktype = hints->ai_socktype;
+    } else {
+        r->ai_socktype = SOCK_DGRAM;
+    }
     r->ai_protocol = hints->ai_protocol;
     r->ai_addrlen = sizeof(struct sockaddr_in);
     r->ai_addr = (struct sockaddr *)sa;
@@ -479,13 +486,13 @@ void lwip_freeaddrinfo(struct addrinfo *ai)
     }
 }
 
-int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
+/* The following 2 are #defined in lwIP 1.4.1, but not in 1.3.1, duplicating them here */
+
+char *inet_ntoa(struct in_addr addr)
 {
-    assert(!"NYI");
+    return ipaddr_ntoa((ip_addr_t *)&addr);
 }
 
-/* The following 2 are #defined in lwIP 1.4.1, but not in 1.3.1, duplicating them here */
-
 int inet_aton(const char *cp, struct in_addr *addr)
 {
     return ipaddr_aton(cp, (ip_addr_t *)addr);
@@ -571,6 +578,29 @@ bool lwip_init_auto(void)
     assert(!"NYI");
 }
 
+/******** NYI *********/
+
+struct thread_mutex *lwip_mutex = NULL;
+struct waitset *lwip_waitset = NULL;
+
+void lwip_mutex_lock(void)
+{
+}
+
+void lwip_mutex_unlock(void)
+{
+}
+
+struct hostent *lwip_gethostbyname(const char *name)
+{
+    assert(!"NYI");
+}
+
+int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
+{
+    assert(!"NYI");
+}
+
 /******** NYI END *********/
 
 void ethernetif_backend_init(char *service_name, uint64_t queueid,
@@ -596,14 +626,16 @@ void ethernetif_backend_init(char *service_name, uint64_t queueid,
 
 #define MAX_DRIVER_BUFS         16
 
-static genpaddr_t rx_pbase = 0;
-static genvaddr_t rx_vbase = 0;
+static genpaddr_t rx_pbase = 0, tx_pbase = 0;
+static genvaddr_t rx_vbase = 0, tx_vbase = 0;
 
 static struct packet tx_packets[MAX_PACKETS];
-static uint8_t tx_bufs[MAX_PACKETS][PACKET_SIZE];
+/* static uint8_t tx_bufs[MAX_PACKETS][PACKET_SIZE]; */
 static unsigned int tx_idx = 0;
 /* static ssize_t tx_packets_available = MAX_PACKETS; */
 
+#include <barrelfish/deferred.h>
+
 static void packet_output(struct packet *p)
 {
     struct driver_buffer bufs[MAX_DRIVER_BUFS];
@@ -640,49 +672,71 @@ static void packet_output(struct packet *p)
         assert(q->len > 0);
 
         // Check if it's from the RX region
-        if(((genvaddr_t)q->payload) >= rx_vbase &&
-           ((genvaddr_t)q->payload) < rx_vbase + (MAX_PACKETS * PACKET_SIZE + 4096)) {
-            buf->pa = rx_pbase + ((genvaddr_t)q->payload - rx_vbase);
-        } else {
-            // Check if it's in morecore's region
-            struct morecore_state *mc_state = get_morecore_state();
-            struct vspace_mmu_aware *mmu_state = &mc_state->mmu_state;
-            genvaddr_t base = vregion_get_base_addr(&mmu_state->vregion);
-            struct memobj_frame_list *i;
-
-            // Walk frame list
-            for(i = mmu_state->memobj.frame_list; i != NULL; i = i->next) {
-                // If address is completely within frame, we can resolve
-                // XXX: Everything else would be easier with an IOMMU
-                if(base + i->offset <= (genvaddr_t)q->payload &&
-                   ((genvaddr_t)q->payload) + q->len < base + i->offset + i->size) {
-                    assert(i->pa != 0);
-
-                    /* buf->pa = id.base + ((genvaddr_t)q->payload - base - i->offset); */
-                    buf->pa = i->pa + ((genvaddr_t)q->payload - base - i->offset);
-                    break;
-                }
-            }
-
-            if(i == NULL) {
-                // Check if it's in text/data region
-                int entry;
-                for(entry = 0; entry < mc_state->v2p_entries; entry++) {
-                    struct v2pmap *pmap = &mc_state->v2p_mappings[entry];
-
-                    if(pmap->va <= (genvaddr_t)q->payload &&
-                       ((genvaddr_t)q->payload) + q->len < pmap->va + pmap->size) {
-                        buf->pa = pmap->pa + ((genvaddr_t)q->payload - pmap->va);
+        /* printf("RX region: Comparing %p against [%p:%p]\n", */
+        /*        q->payload, */
+        /*        (void *)rx_vbase, */
+        /*        (void *)(rx_vbase + (MAX_PACKETS * PACKET_SIZE + 4096))); */
+       if (!use_vtd) {
+            if(((genvaddr_t)q->payload) >= rx_vbase &&
+               ((genvaddr_t)q->payload) < rx_vbase + (MAX_PACKETS * PACKET_SIZE + 4096)) {
+                buf->pa = rx_pbase + ((genvaddr_t)q->payload - rx_vbase);
+            } else if(((genvaddr_t)q->payload) >= tx_vbase &&
+                      ((genvaddr_t)q->payload) < tx_vbase + (MAX_PACKETS * PACKET_SIZE)) {
+                // It is from the TX region!
+                buf->pa = tx_pbase + ((genvaddr_t)q->payload - tx_vbase);
+            } else {
+                // Check if it's in morecore's region
+                struct morecore_state *mc_state = get_morecore_state();
+                struct vspace_mmu_aware *mmu_state = &mc_state->mmu_state;
+                genvaddr_t base = vregion_get_base_addr(&mmu_state->vregion);
+                struct memobj_frame_list *i;
+
+                // Walk frame list
+                for(i = mmu_state->memobj.frame_list; i != NULL; i = i->next) {
+                    // If address is completely within frame, we can resolve
+                    // XXX: Everything else would be easier with an IOMMU
+                   /* printf("Heap: Comparing [%p:%p] against [%p:%p]\n", */
+                   /*        q->payload, q->payload + q->len, */
+                   /*        (void *)(base + i->offset), */
+                   /*        (void *)(base + i->offset + i->size)); */
+                    if(base + i->offset <= (genvaddr_t)q->payload &&
+                       ((genvaddr_t)q->payload) + q->len < base + i->offset + i->size) {
+                        assert(i->pa != 0);
+
+                        /* buf->pa = id.base + ((genvaddr_t)q->payload - base - i->offset); */
+                        buf->pa = i->pa + ((genvaddr_t)q->payload - base - i->offset);
                         break;
                     }
                 }
 
-                if(entry == mc_state->v2p_entries) {
-                    printf("Called from %p %p\n",
-                           __builtin_return_address(0),
-                           __builtin_return_address(1));
+                if(i == NULL) {
+                    // Check if it's in text/data region
+                    int entry;
+                    for(entry = 0; entry < mc_state->v2p_entries; entry++) {
+                        struct v2pmap *pmap = &mc_state->v2p_mappings[entry];
+
+                        // If address is completely within frame, we can resolve
+                        // XXX: Everything else would be easier with an IOMMU
+                        /* printf("BSS: Comparing [%p:%p] against [%p:%p]\n", */
+                        /*        q->payload, q->payload + q->len, */
+                        /*        (void *)(pmap->va), */
+                        /*        (void *)(pmap->va + pmap->size)); */
+                        if(pmap->va <= (genvaddr_t)q->payload &&
+                                ((genvaddr_t)q->payload) + q->len < pmap->va + pmap->size) {
+                            buf->pa = pmap->pa + ((genvaddr_t)q->payload - pmap->va);
+                            break;
+                        }
+                    }
+
+                    if(entry == mc_state->v2p_entries) {
+                        printf("Called from %p %p\n",
+                                __builtin_return_address(0),
+                                __builtin_return_address(1),
+                                __builtin_return_address(2));
 
-                    USER_PANIC("Invalid pbuf! payload = %p, pa = %p\n", q->payload, buf->pa);
+                        USER_PANIC("Invalid pbuf! payload = %p, pa = %p, subpacket = %d\n",
+                                   q->payload, buf->pa, n);
+                    }
                 }
             }
         }
@@ -766,6 +820,15 @@ struct recv_tcp_args {
     struct socket *sock;
 };
 
+struct recv_raw_args {
+    void *buf;
+    size_t len;
+    int recv_len;
+    struct sockaddr *src_addr;
+    socklen_t *addrlen;
+    /* struct packet **inpkt; */
+};
+
 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
 
 static void sock_recved_udp_packet(void *arg)
@@ -834,6 +897,42 @@ static void sock_recved_udp_packet(void *arg)
     inpkt = NULL;
 }
 
+static void sock_recved_raw_packet(void *arg)
+{
+    struct recv_raw_args *args = arg;
+    assert(inpkt != NULL);
+    assert(inpkt->next == NULL);
+
+    // Process headers
+    struct ip_hdr *iphdr = (struct ip_hdr *)(inpkt->payload + SIZEOF_ETH_HDR);
+    assert(args->buf != NULL);      // No accept() allowed
+    uint16_t pkt_len = ntohs(IPH_LEN(iphdr));
+    uint8_t *payload = (void *)iphdr;
+
+    // Fill in src_addr if provided
+    if(args->src_addr != NULL) {
+        struct sockaddr_in *addr = (struct sockaddr_in *)args->src_addr;
+
+        assert(*args->addrlen >= sizeof(struct sockaddr_in));
+        memset(addr, 0, sizeof(struct sockaddr_in));
+        addr->sin_len = sizeof(struct sockaddr_in);
+        addr->sin_family = AF_INET;
+        addr->sin_port = 0;
+        addr->sin_addr.s_addr = iphdr->src.addr;
+        *args->addrlen = sizeof(struct sockaddr_in);
+    }
+
+    // It's a recvfrom!
+    assert(args->len != 0);
+    args->recv_len = MIN(args->len, pkt_len);
+    memcpy(args->buf, payload, args->recv_len);
+    errval_t err = rx_register_buffer_fn_ptr(inpkt->pa, inpkt->payload, inpkt);
+    assert(err_is_ok(err));
+
+    // Input packet is consumed in stack
+    inpkt = NULL;
+}
+
 static void sock_recved_tcp_packet(void *arg)
 {
     struct recv_tcp_args *args = arg;
@@ -1022,10 +1121,18 @@ int lwip_socket(int domain, int type, int protocol)
         assert(!arranet_tcp_accepted);
         arranet_udp_accepted = true;
         break;
+
+    case SOCK_RAW:
+      assert(!arranet_tcp_accepted && !arranet_udp_accepted);
+      assert(protocol == IPPROTO_TCP);
+      arranet_raw_accepted = true;
+      break;
     }
 
     struct socket *sock = alloc_socket();
     assert(sock != NULL);
+    sock->type = type;
+    sock->protocol = protocol;
     /* printf("lwip_socket() = %d\n", sock->fd); */
     return sock->fd;
 }
@@ -1042,19 +1149,51 @@ int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
 int lwip_recvfrom(int sockfd, void *buf, size_t len, int flags,
                   struct sockaddr *src_addr, socklen_t *addrlen)
 {
-    assert(arranet_udp_accepted);
+    assert(arranet_udp_accepted || arranet_raw_accepted);
     struct socket *sock = &sockets[sockfd];
-    struct recv_udp_args args = {
-        .buf = buf,
-        .len = len,
-        .src_addr = src_addr,
-        .addrlen = addrlen,
-    };
     struct waitset ws;
     waitset_init(&ws);
+    int *recv_len;
+    errval_t err;
+    struct recv_udp_args udp_args;
+    struct recv_raw_args raw_args;
+
+    switch(sock->type) {
+    case SOCK_DGRAM:
+      {
+         udp_args.buf = buf;
+         udp_args.len = len;
+         udp_args.src_addr = src_addr;
+         udp_args.addrlen = addrlen;
+
+         err = waitset_chan_register_polled(&ws, &recv_chanstate,
+                                            MKCLOSURE(sock_recved_udp_packet, &udp_args));
+         assert(err_is_ok(err));
+
+         recv_len = &udp_args.recv_len;
+      }
+      break;
+
+    case SOCK_RAW:
+      {
+         raw_args.buf = buf;
+         raw_args.len = len;
+         raw_args.src_addr = src_addr;
+         raw_args.addrlen = addrlen;
+
+         err = waitset_chan_register_polled(&ws, &recv_chanstate,
+                                            MKCLOSURE(sock_recved_raw_packet, &raw_args));
+         assert(err_is_ok(err));
+
+         recv_len = &raw_args.recv_len;
+      }
+      break;
+
+    default:
+        assert(!"NYI");
+        break;
+    }
 
-    errval_t err = waitset_chan_register_polled(&ws, &recv_chanstate,
-                                                MKCLOSURE(sock_recved_udp_packet, &args));
     assert(err_is_ok(err));
 
     /* if socket is ready, trigger event right away */
@@ -1069,7 +1208,7 @@ int lwip_recvfrom(int sockfd, void *buf, size_t len, int flags,
             err = waitset_chan_deregister(&recv_chanstate);
             assert(err_is_ok(err));
             errno = EAGAIN;
-            args.recv_len = -1;
+            *recv_len = -1;
         } else {
             assert(err_is_ok(err));
         }
@@ -1087,7 +1226,7 @@ int lwip_recvfrom(int sockfd, void *buf, size_t len, int flags,
 /* #endif */
 
     // Packet is now in buffer
-    return args.recv_len;
+    return *recv_len;
 }
 
 int recvfrom_arranet(int sockfd, void **buf, struct packet **p,
@@ -1147,6 +1286,7 @@ int recvfrom_arranet(int sockfd, void **buf, struct packet **p,
     return args.recv_len;
 }
 
+static struct pkt_ip_headers packet_ip_header;
 static struct pkt_udp_headers packet_udp_header;
 static struct pkt_tcp_headers packet_tcp_header;
 
@@ -1337,6 +1477,11 @@ int lwip_shutdown(int s, int how)
 
 int lwip_close(int s)
 {
+  if(arranet_udp_accepted) {
+    // XXX: Ignore for now
+    return 0;
+  }
+
     assert(arranet_tcp_accepted);
     struct socket *sock = &sockets[s];
 
@@ -1514,7 +1659,7 @@ int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
 
 int lwip_sendmsg(int sockfd, const struct msghdr *msg, int flags)
 {
-    assert(arranet_udp_accepted);
+    assert(arranet_udp_accepted || arranet_raw_accepted);
     struct socket *sock = &sockets[sockfd];
 
 #ifdef DEBUG_LATENCIES
@@ -1557,7 +1702,13 @@ int lwip_sendmsg(int sockfd, const struct msghdr *msg, int flags)
     // Get new TX packet and copy data into it
     struct packet *newp = get_tx_packet();
     uint8_t *buf = newp->payload;
-    size_t pos = sizeof(struct pkt_udp_headers);
+    size_t pos;
+    if(sock->type == SOCK_DGRAM) {
+      pos = sizeof(struct pkt_udp_headers);
+    } else {
+      assert(sock->type == SOCK_RAW);
+      pos = sizeof(struct pkt_ip_headers);
+    }
 
 /* #ifdef DEBUG_LATENCIES */
 /*     if(memcache_transactions[1] < POSIX_TRANSA) { */
@@ -1604,11 +1755,18 @@ int lwip_sendmsg(int sockfd, const struct msghdr *msg, int flags)
     }
 #endif
 
-    newp->len = short_size + sizeof(struct pkt_udp_headers);
-    newp->next = NULL;
+    if(sock->type == SOCK_DGRAM) {
+        newp->len = short_size + sizeof(struct pkt_udp_headers);
 
-    // Slap UDP/IP/Ethernet headers in front
-    memcpy(buf, &packet_udp_header, sizeof(struct pkt_udp_headers));
+        // Slap UDP/IP/Ethernet headers in front
+        memcpy(buf, &packet_udp_header, sizeof(struct pkt_udp_headers));
+    } else {
+        assert(sock->type == SOCK_RAW);
+        newp->len = short_size + sizeof(struct pkt_ip_headers);
+        // Slap IP/Ethernet headers in front
+        memcpy(buf, &packet_ip_header, sizeof(struct pkt_ip_headers));
+    }
+    newp->next = NULL;
 
 /* #ifdef DEBUG_LATENCIES */
 /*     if(memcache_transactions[3] < POSIX_TRANSA) { */
@@ -1624,27 +1782,50 @@ int lwip_sendmsg(int sockfd, const struct msghdr *msg, int flags)
 /*     } */
 /* #endif */
 
-    // Fine-tune headers
-    struct pkt_udp_headers *p = (struct pkt_udp_headers *)buf;
-    assert(msg->msg_name != NULL);
-    struct sockaddr_in *saddr = msg->msg_name;
-    assert(saddr->sin_family == AF_INET);
-    p->ip.dest.addr = saddr->sin_addr.s_addr;
-    p->udp.dest = saddr->sin_port;
-    struct peer *peer = peers_get_from_ip(p->ip.dest.addr);
-    p->eth.dest = peer->mac;
-    assert(sock->bound_addr.sin_port != 0);
-    p->udp.src = sock->bound_addr.sin_port;
-    p->udp.len = htons(short_size + sizeof(struct udp_hdr));
-    p->ip._len = htons(short_size + sizeof(struct udp_hdr) + IP_HLEN);
+    if (sock->type = SOCK_DGRAM) {
+        // Fine-tune headers
+        struct pkt_udp_headers *p = (struct pkt_udp_headers *)buf;
+        assert(msg->msg_name != NULL);
+        struct sockaddr_in *saddr = msg->msg_name;
+        assert(saddr->sin_family == AF_INET);
+        p->ip.dest.addr = saddr->sin_addr.s_addr;
+        p->udp.dest = saddr->sin_port;
+        struct peer *peer = peers_get_from_ip(p->ip.dest.addr);
+        p->eth.dest = peer->mac;
+        assert(sock->bound_addr.sin_port != 0);
+        p->udp.src = sock->bound_addr.sin_port;
+        p->udp.len = htons(short_size + sizeof(struct udp_hdr));
+        p->ip._len = htons(short_size + sizeof(struct udp_hdr) + IP_HLEN);
 #ifdef CONFIG_QEMU_NETWORK
-    p->ip._chksum = inet_chksum(&p->ip, IP_HLEN);
-    newp->flags = 0;
+        p->ip._chksum = inet_chksum(&p->ip, IP_HLEN);
+        newp->flags = 0;
 #else
-    // Hardware IP header checksumming on
-    p->ip._chksum = 0;
-    newp->flags = NETIF_TXFLAG_IPCHECKSUM;
+        // Hardware IP header checksumming on
+        p->ip._chksum = 0;
+        newp->flags = NETIF_TXFLAG_IPCHECKSUM;
+#endif
+    } else {
+      assert(sock->type == SOCK_RAW);
+      // Fine-tune headers
+      struct pkt_ip_headers *p = (struct pkt_ip_headers *)buf;
+      assert(msg->msg_name != NULL);
+      struct sockaddr_in *saddr = msg->msg_name;
+      assert(saddr->sin_family == AF_INET);
+      p->ip.dest.addr = saddr->sin_addr.s_addr;
+      struct peer *peer = peers_get_from_ip(p->ip.dest.addr);
+      assert(peer != NULL);
+      p->eth.dest = peer->mac;
+      p->ip._len = htons(short_size + IP_HLEN);
+      IPH_PROTO_SET(&p->ip, sock->protocol);
+#ifdef CONFIG_QEMU_NETWORK
+      p->ip._chksum = inet_chksum(&p->ip, IP_HLEN);
+      newp->flags = 0;
+#else
+      // Hardware IP header checksumming on
+      p->ip._chksum = 0;
+      newp->flags = NETIF_TXFLAG_IPCHECKSUM;
 #endif
+    }
 
 /* #ifdef DEBUG_LATENCIES */
 /*     if(memcache_transactions[4] < POSIX_TRANSA) { */
@@ -1753,6 +1934,7 @@ int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
     struct socket *newsock = alloc_socket();
     newsock->nonblocking = sock->nonblocking;
     newsock->bound_addr = sock->bound_addr;
+    newsock->type = sock->type;
     socklen_t adlen = sizeof(struct sockaddr_in);
     struct recv_tcp_args args = {
         .buf = NULL,
@@ -1931,7 +2113,8 @@ void process_received_packet(struct driver_rx_buffer *buffer, size_t count,
                dipaddr == arranet_myip) {
                 // Send reply
                 struct packet outp;
-                uint8_t payload[PACKET_SIZE];
+               // XXX: Static payload! Need to lock if multithreaded!
+                static uint8_t payload[PACKET_SIZE];
                 struct eth_hdr *myeth = (struct eth_hdr *)payload;
                 struct etharp_hdr *myarp = (struct etharp_hdr *)(payload + SIZEOF_ETH_HDR);
 
@@ -1954,11 +2137,18 @@ void process_received_packet(struct driver_rx_buffer *buffer, size_t count,
                 memcpy(&myarp->dipaddr, &arphdr->sipaddr, sizeof(myarp->dipaddr));
 
                 outp.payload = payload;
-                outp.len = p->len;
+                outp.len = SIZEOF_ETHARP_PACKET;
+                /* outp.len = p->len; */
                 outp.next = NULL;
                 outp.flags = 0;
                 outp.opaque = NULL;
+
                 packet_output(&outp);
+               static int arp_count = 0;
+               arp_count++;
+               if(arp_count > 100) {
+                 printf("High ARP count!\n");
+               }
                 while(!e1000n_queue_empty()) thread_yield();
             }
         }
@@ -2033,6 +2223,16 @@ void process_received_packet(struct driver_rx_buffer *buffer, size_t count,
                 goto out;
             }
 
+           // Take raw IP packets if that's accepted and ignore the rest
+           if(arranet_raw_accepted) {
+                // XXX: Accept only TCP for now
+                if(IPH_PROTO(iphdr) == IP_PROTO_TCP) {
+                    goto accept;
+                } else {
+                    goto out;
+                }
+           }
+
             if(IPH_PROTO(iphdr) == IP_PROTO_UDP) {
                 struct udp_hdr *udphdr = (struct udp_hdr *)(p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4));
                 /* uint8_t *payload = p->payload + SIZEOF_ETH_HDR + (IPH_HL(iphdr) * 4) + sizeof(struct udp_hdr); */
@@ -2223,6 +2423,7 @@ void process_received_packet(struct driver_rx_buffer *buffer, size_t count,
 #endif
             }
 
+       accept:
             // ARP management
             if(peers_get_from_ip(iphdr->src.addr) == NULL) {
                 struct peer *newpeer = peers_get_next_free();
@@ -2384,7 +2585,7 @@ bool lwip_sock_ready_read(int s)
             return false;
         }
     } else {
-        assert(arranet_udp_accepted);
+        assert(arranet_udp_accepted || arranet_raw_accepted);
         return inpkt != NULL;
     }
 }
@@ -2418,8 +2619,10 @@ bool lwip_sock_ready_write(int s)
         /* printf("lwip_sock_ready_write(%d)\n", s); */
     } else {
         assert(arranet_udp_accepted);
+
+        return tx_packets[tx_idx].len == 0 ? true : false;
         // XXX: Can also return true when one buffer is available in queue
-        return e1000n_queue_empty();
+        // return e1000n_queue_empty();
     }
 }
 
@@ -2596,7 +2799,7 @@ void arranet_polling_loop_proxy(void)
 }
 
 static const char *eat_opts[] = {
-    "function=", "interrupts=", "queue=", "msix=", "vf=", "device=", "bus=",
+    "function=", "interrupts=", "queue=", "msix=", "vf=", "device=", "bus=", "use_vtd=",
     NULL
 };
 
@@ -2607,6 +2810,31 @@ void lwip_arrakis_start(int *argc, char ***argv)
     waitset_chanstate_init(&recv_chanstate, CHANTYPE_LWIP_SOCKET);
     waitset_chanstate_init(&send_chanstate, CHANTYPE_LWIP_SOCKET);
 
+    errval_t err = skb_client_connect();
+    assert(err_is_ok(err));
+
+    err = skb_execute_query("vtd_enabled(0,C), write(vtd_coherency(C)).");
+    if (err_is_ok(err)) {
+        use_vtd = 1;
+        for(int i = 0; i < *argc; i++) { 
+           if(!strncmp((*argv)[i], "use_vtd=", strlen("use_vtd=") - 1)) {
+             use_vtd = !!atol((*argv)[i] + strlen("use_vtd="));
+                break;
+            }
+        }
+       err = skb_read_output("vtd_coherency(%d)", &vtd_coherency);
+       assert(err_is_ok(err));
+    } 
+   
+    if (use_vtd) {
+        err = connect_to_acpi();
+       assert(err_is_ok(err));
+       err = vtd_create_domain(cap_vroot);
+       assert(err_is_ok(err));
+       err = vtd_domain_add_device(0, 13, 16, 1, cap_vroot);
+       assert(err_is_ok(err));
+    }
+
     e1000n_driver_init(*argc, *argv);
 
     ether_get_mac_address_ptr(mac);
@@ -2619,7 +2847,7 @@ void lwip_arrakis_start(int *argc, char ***argv)
     assert(ram_base != NULL);
 
     struct frame_identity id;
-    errval_t err = invoke_frame_identify(frame, &id);
+    err = invoke_frame_identify(frame, &id);
     assert(err_is_ok(err));
 
     rx_pbase = id.base;
@@ -2630,10 +2858,10 @@ void lwip_arrakis_start(int *argc, char ***argv)
         struct packet *p = &rx_packets[i];
 
         // XXX: Use this for recvfrom_arranet to get alignment
-        p->payload = ram_base + (i * PACKET_SIZE) + 6;
-        p->pa = id.base + (i * PACKET_SIZE) + 6;
-        /* p->payload = ram_base + (i * PACKET_SIZE); */
-        /* p->pa = id.base + (i * PACKET_SIZE); */
+        /* p->payload = ram_base + (i * PACKET_SIZE) + 6; */
+        /* p->pa = id.base + (i * PACKET_SIZE) + 6; */
+        p->payload = ram_base + (i * PACKET_SIZE);
+        p->pa = id.base + (i * PACKET_SIZE);
         p->len = PACKET_SIZE;
         p->flags = 0;
 
@@ -2641,9 +2869,24 @@ void lwip_arrakis_start(int *argc, char ***argv)
         assert(err_is_ok(err));
     }
 
+    // Allocate TX buffers (to have them all backed by one frame)
+    uint8_t *tx_bufs = alloc_map_frame(VREGION_FLAGS_READ_WRITE,
+                                       MAX_PACKETS * PACKET_SIZE, &frame);
+    assert(tx_bufs != NULL);
+
+    err = invoke_frame_identify(frame, &id);
+    assert(err_is_ok(err));
+    tx_pbase = id.base;
+    tx_vbase = (genvaddr_t)tx_bufs;
+
     // Initialize TX packet descriptors
     for(int i = 0; i < MAX_PACKETS; i++) {
-        tx_packets[i].payload = tx_bufs[i];
+        /* tx_packets[i].payload = tx_bufs[i]; */
+        tx_packets[i].payload = tx_bufs + (i * PACKET_SIZE);
+    }
+
+    if (!vtd_coherency) {// For the UDP echo server
+        sys_debug_flush_cache();
     }
 
     // Determine my static IP address
@@ -2660,6 +2903,25 @@ void lwip_arrakis_start(int *argc, char ***argv)
         USER_PANIC("Arranet: No static IP config for this MAC address!\n");
     }
 
+    /***** Initialize IP/Ethernet packet header template *****/
+    {
+        struct pkt_ip_headers *p = &packet_ip_header;
+
+        // Initialize Ethernet header
+        memcpy(&p->eth.src, mac, ETHARP_HWADDR_LEN);
+        p->eth.type = htons(ETHTYPE_IP);
+
+        // Initialize IP header
+        p->ip._v_hl = 69;
+        p->ip._tos = 0;
+        p->ip._id = htons(3);
+        p->ip._offset = 0;
+        p->ip._ttl = 0xff;
+        p->ip._proto = 0;
+        p->ip._chksum = 0;
+        p->ip.src.addr = arranet_myip;
+    }
+
     /***** Initialize UDP/IP/Ethernet packet header template *****/
     {
         struct pkt_udp_headers *p = &packet_udp_header;
index 70f7a95..4b5526e 100644 (file)
@@ -38,6 +38,12 @@ struct cnoderef cnode_root = {
     .size_bits = DEFAULT_CNODE_BITS, \
     .guard_size = GUARD_REMAINDER(2 * DEFAULT_CNODE_BITS) }
 
+#define PAGE_CNODE_INIT { \
+    .address = ROOTCN_SLOT_PAGECN << DEFAULT_CN_ADDR_BITS, \
+    .address_bits = DEFAULT_CNODE_BITS, \
+    .size_bits = PAGE_CNODE_BITS, \
+    .guard_size = 0 }
+
 /// Task CNode
 struct cnoderef cnode_task = TASK_CNODE_INIT;
 
@@ -58,12 +64,7 @@ struct cnoderef cnode_super = {
 };
 
 /// Page CNode
-struct cnoderef cnode_page = {
-    .address = ROOTCN_SLOT_PAGECN << DEFAULT_CN_ADDR_BITS,
-    .address_bits = DEFAULT_CNODE_BITS,
-    .size_bits = PAGE_CNODE_BITS,
-    .guard_size = 0
-};
+struct cnoderef cnode_page = PAGE_CNODE_INIT;
 
 /// Module CNode
 struct cnoderef cnode_module = {
@@ -151,6 +152,12 @@ struct capref cap_sessionid = {
     .slot = TASKCN_SLOT_SESSIONID
 };
 
+/// Root PML4 VNode
+struct capref cap_vroot = {
+    .cnode = PAGE_CNODE_INIT,
+    .slot = CPTR_PML4_BASE
+};
+
 static inline bool backoff(int count)
 {
     // very crude exponential backoff based upon core id
index c89fead..b5f4447 100644 (file)
@@ -110,8 +110,8 @@ void debug_printf(const char *fmt, ...)
     char str[256];
     size_t len;
 
-    len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%"PRIuPTR"\033[0m: ", DISP_NAME_LEN, disp_name(),
-                   disp_get_core_id(), thread_id());
+    len = snprintf(str, sizeof(str), "\033[34m%.*s.\033[31m%u.%"PRIuPTR"\033[0m: ",
+                   DISP_NAME_LEN, disp_name(), disp_get_core_id(), thread_id());
     if (len < sizeof(str)) {
         va_start(argptr, fmt);
         vsnprintf(str + len, sizeof(str) - len, fmt, argptr);
@@ -411,3 +411,11 @@ void debug_err(const char *file, const char *func, int line, errval_t err,
         err_print_calltrace(err);
     }
 }
+
+bool debug_notify_syscall = false;
+
+void debug_control_plane_forbidden(void);
+void debug_control_plane_forbidden(void)
+{
+    debug_notify_syscall = true;
+}
index befb510..433329d 100644 (file)
@@ -1050,6 +1050,7 @@ void disp_set_core_id(coreid_t core_id)
     disp->core_id = core_id;
 }
 
+
 /**
  * \brief returns the address and the size of the EH frame
  *
index e5424e5..56958aa 100644 (file)
@@ -46,3 +46,4 @@ uint64_t bench_tsc_per_ms(void)
 {
     return tscperms;
 }
+
index 1fffb1c..9cc5c3d 100644 (file)
@@ -371,7 +371,7 @@ static void gw_req_memory_call_rx(struct xomp_binding *b,
         return;
     }
 
-    uint8_t map_flags;
+    vregion_flags_t map_flags;
 
     switch ((xomp_frame_type_t) type) {
         case XOMP_FRAME_TYPE_MSG:
index 3bee085..763716a 100644 (file)
@@ -248,12 +248,12 @@ static void idc_request_device_info(struct bulk_e10k *bu)
 /** e10k interface: Register memory for descriptor rings */
 static void idc_register_queue_memory(struct bulk_e10k *bu)
 {
-    errval_t r;
+    errval_t r = SYS_ERR_OK;
     DEBUG("idc_register_queue_memory()\n");
 
-    r = e10k_register_queue_memory__tx(bu->binding, NOP_CONT, bu->qi,
-        bu->txframe, bu->txhwbframe, bu->rxframe, bu->buffer_size, E10K_HDRSZ,
-        bu->int_vector, bu->int_core, USE_INTERRUPTS, false);
+    /* r = e10k_register_queue_memory__tx(bu->binding, NOP_CONT, bu->qi, */
+    /*     bu->txframe, bu->txhwbframe, bu->rxframe, bu->buffer_size, E10K_HDRSZ, */
+    /*     bu->int_vector, bu->int_core, USE_INTERRUPTS, false); */
     assert(err_is_ok(r));
 }
 
index 4705f7f..e0e9ef5 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef Queue_Manager_benchmark_H_
 #define Queue_Manager_benchmark_H_
 #include <barrelfish/barrelfish.h>
+#include <if/net_queue_manager_defs.h>
 #include <net_queue_manager/net_queue_manager.h>
 #include <contmng/netbench.h>
 #include <stdio.h>
index 2e26804..620f1c7 100644 (file)
@@ -29,6 +29,7 @@
 #include <net_queue_manager/net_queue_manager.h>
 #include <bfdmuxvm/vm.h>
 #include <if/net_soft_filters_defs.h>
+#include <if/net_queue_manager_defs.h>
 #include "queue_manager_local.h"
 #include "queue_manager_debug.h"
 
index adf6d9b..576eccc 100644 (file)
@@ -9,6 +9,8 @@
 size_t (*_libc_terminal_read_func)(char *, size_t);
 size_t (*_libc_terminal_write_func)(const char *, size_t);
 
+void (*_libc_assert_func)(const char *, const char *, const char *, int);
+
 typedef void *(*morecore_alloc_func_t)(size_t bytes, size_t *retbytes);
 morecore_alloc_func_t sys_morecore_alloc;
 
index 009f8be..dfa0bbd 100644 (file)
@@ -1,5 +1,5 @@
 --------------------------------------------------------------------------
--- Copyright (c) 2007-2009, 2011, 2012, 2013, ETH Zurich.
+-- Copyright (c) 2007-2009, 2011, 2012, 2013, 2014, ETH Zurich.
 -- All rights reserved.
 --
 -- This file is distributed under the terms in the attached LICENSE file.
                              "pthreads.c", 
                              "sleep.c", 
                              "epoll.c", 
+                             "poll.c",
                              "inet_ntop.c", 
-                             "inet_pton.c" ],
-                  flounderDefs = [ 
-                        "unixsock", 
-                        "octopus", 
-                        "monitor", 
-                        "terminal",
-                        "terminal_config",
-                        "terminal_session"
-                  ],
+                             "inet_pton.c", 
+                             "syslog.c", 
+                             "uname.c" ],
+                  flounderDefs = [ "unixsock", "octopus", "monitor", "terminal", "terminal_config", "terminal_session" ],
                   flounderBindings = [ "unixsock", "octopus" ],
                          flounderExtraBindings = [ ("octopus", [ "rpcclient" ]) ],
                   flounderTHCStubs = [ "octopus" ]
index bead0da..022b0fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, 2013, ETH Zurich.
+ * Copyright (c) 2013, 2014, University of Washington.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
index 8aafd81..d02159c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2011, 2014, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
 #include <unistd.h>
 #include <assert.h>
 #include <stdio.h>
+#include <errno.h>
+#include <barrelfish/barrelfish.h>
+#include <vfs/fdtab.h>
+#include <vfs/vfs.h>
 #include "posixcompat.h"
 
 int fsync(int fd)
 {
-    POSIXCOMPAT_DEBUG("Warning: fsync(%d) ignored!\n", fd);
+    struct fdtab_entry *e = fdtab_get(fd);
+
+    switch(e->type) {
+    case FDTAB_TYPE_FILE:
+      {
+       errval_t err = vfs_flush((vfs_handle_t)e->handle);
+       if(err_is_fail(err)) {
+         return -1;
+       }
+      }
+      break;
+
+    default:
+      errno = EINVAL;
+      return -1;
+    }
+
     return 0;
 }
diff --git a/lib/posixcompat/poll.c b/lib/posixcompat/poll.c
new file mode 100644 (file)
index 0000000..adfbd40
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2011, 2012, 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ * Attn: Systems Group.
+ */
+
+#include <poll.h>
+#include <assert.h>
+
+int poll(struct pollfd pfd[], nfds_t nfds, int timeout)
+{
+  assert(!"NYI");
+  return -1;
+}
index eec6311..d80c221 100644 (file)
@@ -1,8 +1,18 @@
+/*
+ * Copyright (c) 2013, 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
 #include <pthread.h>
 #include <assert.h>
 #include <barrelfish/barrelfish.h>
 #include <errno.h>
 #include <string.h>
+#include <signal.h>
 
 #include <posixcompat.h> // for pthread_placement stuff
 
@@ -53,6 +63,10 @@ struct pthread {
     void *retval;
 };
 
+struct pthread_attr {
+    int stacksize;
+};
+
 static pthread_key_t key_index = 0;
 static struct thread_mutex key_mutex = THREAD_MUTEX_INITIALIZER;
 static destructor_fn_t destructors[PTHREAD_KEYS_MAX];
@@ -93,6 +107,12 @@ errval_t posixcompat_pthread_set_placement_fn(pthread_placement_fn fn)
 int pthread_create(pthread_t *pthread, const pthread_attr_t *attr,
                    void *(*start_routine) (void *), void *arg)
 {
+    size_t stacksize = THREADS_DEFAULT_STACK_BYTES;
+
+    if(attr != NULL) {
+        stacksize = (*attr)->stacksize;
+    }
+
     *pthread = malloc(sizeof(struct pthread));
     assert(*pthread != NULL);
     memset(*pthread, 0, sizeof(struct pthread));
@@ -107,11 +127,13 @@ int pthread_create(pthread_t *pthread, const pthread_attr_t *attr,
         (*pthread)->core = pthread_placement(PTHREAD_ACTION_CREATE, 0);
     }
     struct thread *nt;
-    errval_t err = domain_thread_create_on((*pthread)->core, start_pthread, *pthread, &nt);
+    errval_t err = domain_thread_create_on_varstack(
+                     (*pthread)->core, start_pthread, *pthread, stacksize, &nt);
     if (err_is_fail(err)) {
         DEBUG_ERR(err, "pthread_create");
         return 1;
     }
+
     (*pthread)->thread = nt;
     debug_printf("%s: %p -> %"PRIuPTR"\n", __FUNCTION__, *pthread,
             thread_get_id((*pthread)->thread));
@@ -157,6 +179,8 @@ int pthread_setspecific(pthread_key_t key, const void *val)
 
 int pthread_attr_init(pthread_attr_t *attr)
 {
+    *attr = malloc(sizeof(struct pthread_attr));
+    (*attr)->stacksize = THREADS_DEFAULT_STACK_BYTES;
     // No attributes
     return 0;
 }
@@ -691,3 +715,44 @@ int _pthread_once(pthread_once_t *ctrl, void (*init) (void))
     thread_once(ctrl, init);
     return 0;
 }
+
+int pthread_setcancelstate(int state, int *oldstate)
+{
+    // XXX: Not supported
+    if(oldstate != NULL) {
+        *oldstate = PTHREAD_CANCEL_ENABLE;
+    }
+    return 0;
+}
+
+int pthread_setcanceltype(int type, int *oldtype)
+{
+    // XXX: Not supported
+    if(oldtype != NULL) {
+        *oldtype = PTHREAD_CANCEL_DEFERRED;
+    }
+    return 0;
+}
+
+int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
+{
+    return sigprocmask(how, set, oldset);
+}
+
+int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+    *stacksize = (*attr)->stacksize;
+    return 0;
+}
+
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+    (*attr)->stacksize = stacksize;
+    return 0;
+}
+
+int pthread_cancel(pthread_t thread)
+{
+    assert(!"NYI");
+    return -1;
+}
index f89b558..f9a0ae1 100644 (file)
@@ -361,7 +361,7 @@ finish:
 
 finish_no_ws_changed:
     // Remove timeout from waitset if it was set
-    if(timeout != NULL) {
+    if(timeout != NULL && !toe.fired) {
         deferred_event_cancel(&timeout_event);
     }
 
index 74800d4..f0d9b8d 100644 (file)
@@ -14,3 +14,9 @@ unsigned int sleep(unsigned int seconds)
 {
     return usleep((useconds_t)seconds * 1000000);
 }
+
+int nanosleep(const struct timespec *req, struct timespec *rem)
+{
+    assert(!"NYI");
+    return -1;
+}
index 984df85..e88acf9 100644 (file)
@@ -126,6 +126,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                  struct sockaddr *src_addr, socklen_t *addrlen)
 {
     struct fdtab_entry *e = fdtab_get(sockfd);
+    ssize_t ret = 0;
 
     switch(e->type) {
     case FDTAB_TYPE_UNIX_SOCKET:
@@ -135,18 +136,22 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
 
     case FDTAB_TYPE_LWIP_SOCKET:
         lwip_mutex_lock();
-        ssize_t ret = lwip_recvfrom(e->fd, buf, len, flags, src_addr, addrlen);
+        ret = lwip_recvfrom(e->fd, buf, len, flags, src_addr, addrlen);
         lwip_mutex_unlock();
-        return ret;
+        break;
 
     case FDTAB_TYPE_AVAILABLE:
         errno = EBADF;
-        return -1;
+        ret = -1;
+        break;
 
     default:
         errno = ENOTSOCK;
-        return -1;
+        ret = -1;
+        break;
     }
+
+    return ret;
 }
 
 static void unixsock_sent(void *arg)
@@ -265,6 +270,7 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                const struct sockaddr *dest_addr, socklen_t addrlen)
 {
     struct fdtab_entry *e = fdtab_get(sockfd);
+    ssize_t ret = 0;
 
     switch(e->type) {
     case FDTAB_TYPE_UNIX_SOCKET:
@@ -274,23 +280,28 @@ ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
 
     case FDTAB_TYPE_LWIP_SOCKET:
         lwip_mutex_lock();
-        ssize_t ret = lwip_sendto(e->fd, buf, len, flags, dest_addr, addrlen);
+        ret = lwip_sendto(e->fd, buf, len, flags, dest_addr, addrlen);
         lwip_mutex_unlock();
-        return ret;
+        break;
 
     case FDTAB_TYPE_AVAILABLE:
         errno = EBADF;
-        return -1;
+        ret = -1;
+        break;
 
     default:
         errno = ENOTSOCK;
-        return -1;
+        ret = -1;
+        break;
     }
+
+    return ret;
 }
 
 ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
 {
     struct fdtab_entry *e = fdtab_get(sockfd);
+    ssize_t ret = 0;
 
     switch(e->type) {
     case FDTAB_TYPE_UNIX_SOCKET:
@@ -319,26 +330,30 @@ ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)
         }
 
         lwip_mutex_lock();
-        ssize_t ret = lwip_sendto(e->fd, buf, totalsize, flags,
-                                  msg->msg_name, msg->msg_namelen);
+        ret = lwip_sendto(e->fd, buf, totalsize, flags, msg->msg_name,
+                          msg->msg_namelen);
         lwip_mutex_unlock();
         free(buf);
 #else
         lwip_mutex_lock();
-        ssize_t ret = lwip_sendmsg(e->fd, msg, flags);
+        ret = lwip_sendmsg(e->fd, msg, flags);
         lwip_mutex_unlock();
 #endif
 
-        return ret;
+        break;
 
     case FDTAB_TYPE_AVAILABLE:
         errno = EBADF;
-        return -1;
+        ret = -1;
+        break;
 
     default:
         errno = ENOTSOCK;
-        return -1;
+        ret = -1;
+        break;
     }
+
+    return ret;
 }
 
 int socket(int domain, int type, int protocol)
@@ -713,17 +728,19 @@ int setsockopt(int sockfd, int level, int optname, const void *optval,
                socklen_t optlen)
 {
     struct fdtab_entry *e = fdtab_get(sockfd);
+    int ret = 0;
 
     switch(e->type) {
     case FDTAB_TYPE_LWIP_SOCKET:
-        return lwip_setsockopt(e->fd, level, optname, optval, optlen);
+        ret = lwip_setsockopt(e->fd, level, optname, optval, optlen);
+        break;
 
     default:
         assert(!"NYI");
         break;
     }
 
-    return -1;
+    return ret;
 }
 
 static void unixsock_bound(void *st, errval_t err, struct unixsock_binding *b)
diff --git a/lib/posixcompat/syslog.c b/lib/posixcompat/syslog.c
new file mode 100644 (file)
index 0000000..4331b54
--- /dev/null
@@ -0,0 +1,12 @@
+#include <syslog.h>
+#include <assert.h>
+
+void syslog(int priority, const char *format, ...)
+{
+    assert(!"NYI");
+}
+
+void openlog(const char *ident, int option, int facility)
+{
+    assert(!"NYI");
+}
diff --git a/lib/posixcompat/uname.c b/lib/posixcompat/uname.c
new file mode 100644 (file)
index 0000000..9eb8db7
--- /dev/null
@@ -0,0 +1,8 @@
+#include <sys/utsname.h>
+#include <assert.h>
+
+int __xuname(int length, void *name)
+{
+    assert(!"NYI");
+    return 0;
+}
index ec28673..54b8585 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, ETH Zurich.
+ * Copyright (c) 2011, 2013, 2014, ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -26,6 +26,12 @@ pid_t wait(int *status)
     return waitpid(-1, status, 0);
 }
 
+pid_t wait3(int *status, int options, struct rusage *rusage)
+{
+    // XXX: Won't touch rusage at all
+    return waitpid(-1, status, options);
+}
+
 pid_t waitpid(pid_t pid, int *status, int options)
 {
     int i;
diff --git a/lib/storage/Hakefile b/lib/storage/Hakefile
new file mode 100644 (file)
index 0000000..68ded35
--- /dev/null
@@ -0,0 +1,16 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2014, University of Washington.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for lib/storage
+-- 
+--------------------------------------------------------------------------
+
+[ build library { target = "storage",
+                  cFiles = [ "storage.c", "vsa.c" ]
+                }
+]
diff --git a/lib/storage/storage.c b/lib/storage/storage.c
new file mode 100644 (file)
index 0000000..3a2fce1
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <storage/storage.h>
+
+errval_t storage_init(int argc, const char **argv)
+{
+  return SYS_ERR_OK;
+}
diff --git a/lib/storage/vsa.c b/lib/storage/vsa.c
new file mode 100644 (file)
index 0000000..5edfa63
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <storage/vsa.h>
+#include <storage/vsic.h>
+#include <assert.h>
+
+errval_t storage_vsa_alloc(struct storage_vsa *vsa, size_t size)
+{
+    // TODO: No capabilities yet. We need a manager process.
+    // XXX: We just always grant the request.
+    vsa->vsacap = NULL_CAP;
+    vsa->size = size;
+    return SYS_ERR_OK;
+}
+
+errval_t storage_vsa_resize(struct storage_vsa *vsa, size_t newsize)
+{
+    assert(!"NYI");
+}
diff --git a/lib/tenaciousd/Hakefile b/lib/tenaciousd/Hakefile
new file mode 100644 (file)
index 0000000..cc2ea5d
--- /dev/null
@@ -0,0 +1,16 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2014, University of Washington.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for lib/tenaciousd
+-- 
+--------------------------------------------------------------------------
+
+[ build library { target = "tenaciousd",
+                  cFiles = [ "log.c", "ram_vsic.c" ]
+                }
+]
diff --git a/lib/tenaciousd/Makefile b/lib/tenaciousd/Makefile
new file mode 100644 (file)
index 0000000..95c4979
--- /dev/null
@@ -0,0 +1,16 @@
+# Linux Makefile for libtenaciousd.
+
+CFLAGS = -std=gnu99 -g
+CPPFLAGS = -I.
+
+#libtenaciousd.a: log.o aio_vsic.o ram_vsic.o
+libtenaciousd.a: log.o ram_vsic.o
+       rm -f $@
+       $(AR) rcs $@ $^
+
+log.o: log.c
+aio_vsic.o: aio_vsic.c
+ram_vsic.o: ram_vsic.c
+
+clean:
+       rm -f *.o *.a
diff --git a/lib/tenaciousd/README b/lib/tenaciousd/README
new file mode 100644 (file)
index 0000000..2bcf884
--- /dev/null
@@ -0,0 +1,5 @@
+Building on Linux
+=================
+Create a new directory and put symlinks to build.sh and Makefile in there.
+
+Execute build.sh to build the library for Linux.
diff --git a/lib/tenaciousd/aio_vsic.c b/lib/tenaciousd/aio_vsic.c
new file mode 100644 (file)
index 0000000..08445bc
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2014, University of Washington.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <aio.h>
+#include <string.h>
+#include <errors/errno.h>
+#include <storage/vsic.h>
+#include <storage/vsa.h>
+
+#define MAX_CBS         10
+
+struct file_vsic {
+    struct aiocb cb[MAX_CBS];
+    const struct aiocb *cb_list[MAX_CBS];
+};
+
+static struct aiocb *get_aiocb(struct file_vsic *vsic)
+{
+    for(int i = 0; i < MAX_CBS; i++) {
+        if(vsic->cb_list[i] == NULL) {
+            vsic->cb_list[i] = &vsic->cb[i];
+            return &vsic->cb[i];
+        }
+    }
+
+    return NULL;
+}
+
+static errval_t vsic_write(struct storage_vsic *vsic, struct storage_vsa *vsa,
+                           off_t offset, size_t size, void *buffer)
+{
+    assert(vsic != NULL);
+    assert(vsa != NULL);
+    assert(buffer != NULL);
+    struct file_vsic *mydata = vsic->data;
+    struct aiocb *cb = get_aiocb(mydata);
+    assert(cb != NULL);
+
+    cb->aio_fildes = vsa->fd;
+    cb->aio_offset = offset;
+    cb->aio_buf = buffer;
+    cb->aio_nbytes = size;
+
+    int r = aio_write(cb);
+    assert(r == 0);
+
+    return SYS_ERR_OK;
+}
+
+static errval_t vsic_read(struct storage_vsic *vsic, struct storage_vsa *vsa,
+                          off_t offset, size_t size, void *buffer)
+{
+    assert(vsic != NULL);
+    assert(vsa != NULL);
+    assert(buffer != NULL);
+    struct file_vsic *mydata = vsic->data;
+    struct aiocb *cb = get_aiocb(mydata);
+    assert(cb != NULL);
+
+    cb->aio_fildes = vsa->fd;