[
  {
    "path": ".gitignore",
    "content": "build\nDerivedData\n.DS_Store\n*~\n*.rej\n*.orig\ncscope.*\ntags\nTAGS\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015-2018 xhyve developers\nAdditional copyrights are declared on individual source files\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nThe views and conclusions contained in the software and documentation are those\nof the authors and should not be interpreted as representing official policies,\neither expressed or implied, of the xhyve project.\n"
  },
  {
    "path": "Makefile",
    "content": "GIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags)\n\nifeq ($V, 1)\n\tVERBOSE =\nelse\n\tVERBOSE = @\nendif\n\ninclude config.mk\n\nVMM_SRC := \\\n\tsrc/vmm/x86.c \\\n\tsrc/vmm/vmm.c \\\n\tsrc/vmm/vmm_host.c \\\n\tsrc/vmm/vmm_mem.c \\\n\tsrc/vmm/vmm_lapic.c \\\n\tsrc/vmm/vmm_instruction_emul.c \\\n\tsrc/vmm/vmm_ioport.c \\\n\tsrc/vmm/vmm_callout.c \\\n\tsrc/vmm/vmm_stat.c \\\n\tsrc/vmm/vmm_util.c \\\n\tsrc/vmm/vmm_api.c \\\n\tsrc/vmm/intel/vmx.c \\\n\tsrc/vmm/intel/vmx_msr.c \\\n\tsrc/vmm/intel/vmcs.c \\\n\tsrc/vmm/io/vatpic.c \\\n\tsrc/vmm/io/vatpit.c \\\n\tsrc/vmm/io/vhpet.c \\\n\tsrc/vmm/io/vioapic.c \\\n\tsrc/vmm/io/vlapic.c \\\n\tsrc/vmm/io/vpmtmr.c \\\n\tsrc/vmm/io/vrtc.c\n\nXHYVE_SRC := \\\n\tsrc/acpitbl.c \\\n\tsrc/atkbdc.c \\\n\tsrc/bhyvegc.c \\\n\tsrc/block_if.c \\\n\tsrc/bootrom.c \\\n\tsrc/console.c \\\n\tsrc/consport.c \\\n\tsrc/dbgport.c \\\n\tsrc/inout.c \\\n\tsrc/ioapic.c \\\n\tsrc/mem.c \\\n\tsrc/mevent.c \\\n\tsrc/mptbl.c \\\n\tsrc/pci_ahci.c \\\n\tsrc/pci_e82545.c \\\n\tsrc/pci_emul.c \\\n\tsrc/pci_fbuf.c \\\n\tsrc/pci_hostbridge.c \\\n\tsrc/pci_irq.c \\\n\tsrc/pci_lpc.c \\\n\tsrc/pci_uart.c \\\n\tsrc/pci_virtio_block.c \\\n\tsrc/pci_virtio_net_tap.c \\\n\tsrc/pci_virtio_net_vmnet.c \\\n\tsrc/pci_virtio_rnd.c \\\n\tsrc/pm.c \\\n\tsrc/post.c \\\n\tsrc/ps2kbd.c \\\n\tsrc/ps2mouse.c \\\n\tsrc/rtc.c \\\n\tsrc/rfb.c \\\n\tsrc/smbiostbl.c \\\n\tsrc/sockstream.c \\\n\tsrc/task_switch.c \\\n\tsrc/uart_emul.c \\\n\tsrc/xhyve.c \\\n\tsrc/vga.c \\\n\tsrc/virtio.c \\\n\tsrc/xmsr.c\n\nFIRMWARE_SRC := \\\n\tsrc/firmware/kexec.c \\\n\tsrc/firmware/fbsd.c\n\nSRC := \\\n\t$(VMM_SRC) \\\n\t$(XHYVE_SRC) \\\n\t$(FIRMWARE_SRC)\n\nOBJ := $(SRC:src/%.c=build/%.o)\nDEP := $(OBJ:%.o=%.d)\nINC := -Iinclude\n\nCFLAGS += -DVERSION=\\\"$(GIT_VERSION)\\\"\n\nTARGET = build/xhyve\n\nall: $(TARGET) | build\n\n.PHONY: clean all\n.SUFFIXES:\n\n-include $(DEP)\n\nbuild:\n\t@mkdir -p build\n\nbuild/%.o: src/%.c\n\t@echo cc $<\n\t@mkdir -p $(dir $@)\n\t$(VERBOSE) $(ENV) $(CC) $(CFLAGS) $(INC) $(DEF) -MMD -MT $@ -MF build/$*.d -o $@ -c $<\n\n$(TARGET).sym: $(OBJ)\n\t@echo ld $(notdir $@)\n\t$(VERBOSE) $(ENV) $(LD) $(LDFLAGS) -Xlinker $(TARGET).lto.o -o $@ $(OBJ)\n\t@echo dsym $(notdir $(TARGET).dSYM)\n\t$(VERBOSE) $(ENV) $(DSYM) $@ -o $(TARGET).dSYM\n\n$(TARGET): $(TARGET).sym\n\t@echo strip $(notdir $@)\n\t$(VERBOSE) $(ENV) $(STRIP) $(TARGET).sym -o $@\n\nclean:\n\t@rm -rf build\n"
  },
  {
    "path": "README.md",
    "content": "# [xhyve.xyz](http://www.xhyve.xyz)\n\n![](./xhyve_logo.png)\n<!-- https://thenounproject.com/term/squirrel/57718/ -->\n\nAbout\n-----\n\nThe *xhyve hypervisor* is a port of [bhyve](http://www.bhyve.org) to macOS. It is built on top of [Hypervisor.framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/index.html) in OS X 10.10 Yosemite and higher, runs entirely in userspace, and has no other dependencies. It can run FreeBSD, some Linux distributions, and Windows 10 and may gain support for other guest operating systems in the future.\n\nLicense: [BSD-2-Clause](LICENSE)\n\nIntroduction: [http://www.pagetable.com/?p=831](http://www.pagetable.com/?p=831)\n\nRequirements\n------------\n\n* OS X 10.10.3 Yosemite or later\n* a 2010 or later Mac (i.e. a CPU that supports EPT: `sysctl kern.hv_support` = 1)\n\nInstallation\n------------\n\nIf you have homebrew, then simply:\n\n    $ brew update\n    $ brew install --HEAD xhyve\n\nThe `--HEAD` in the brew command ensures that you always get the latest changes, even if the homebrew database is not yet updated. If for any reason you don't want that simply do `brew install xhyve` .\n\nIf you have MacPorts, then simply:\n\n    $ sudo port selfupdate\n    $ sudo port install xhyve\n\nMacPorts is up to date with the GitHub ref listed in the port info\n\n    $ port info xhyve\n    xhyve @20170117 (emulators)\n    ...\n\nOtherwise:\n\nBuilding\n--------\n    $ git clone https://github.com/machyve/xhyve.git\n    $ cd xhyve\n    $ xcodebuild\n\nThe resulting binary will be in build/Release/xhyve\n\nUsage\n-----\n\n    $ xhyve -h\n\nSee below for steps to boot various OSs\n\nWhat is *bhyve*?\n--------------\n\n*bhyve* is the FreeBSD hypervisor, roughly analogous to KVM + QEMU on Linux. It has a focus on simplicity.\n\nIt exposes the following peripherals to virtual machines:\n\n  - Local x(2)APIC\n  - IO-APIC\n  - 8259A PIC\n  - 8253/8254 PIT\n  - HPET\n  - PM Timer\n  - RTC\n  - PS/2 Keyboard and Mouse (via VNC)\n  - PCI\n    - host bridge\n    - passthrough\n    - UART\n    - AHCI (i.e. HDD and CD)\n    - VirtIO block device\n    - VirtIO networking\n    - VirtIO RNG\n    - Intel e1000 (aka e82545)\n    - VGA/Framebuffer (exposed with a minimal VNC server)\n    - XHCI USB support with one device defined - a tablet for Windows guest support\n\n*bhyve* architecture\n------------------\n                                                           Linux\n               I/O        VM control       FreeBSD        NetBSD\n                                                          OpenBSD\n             |     A        |     A           |              |\n             V     |        V     |           V              V\n         +-------------++-------------++-------------++-------------+\n         |             ||             ||             ||             |\n         |    bhyve    ||  bhyvectl   ||  bhyveload  || grub2-bhyve |\n         |             ||             ||             ||             |\n         |             ||             ||             ||             |\n         +-------------++-------------++-------------++-------------+\n         +----------------------------------------------------------+\n         |                        libvmmapi                         |\n         +----------------------------------------------------------+\n                                       A\n                                       |                         user\n         ------------------------------┼------------------------------\n                                       | ioctl         FreeBSD kernel\n                                       V\n                         +----------------------------+\n                         |        VMX/SVM host        |\n                         |       VMX/SVM guest        |\n                         |   VMX/SVM nested paging    |\n                         |           Timers           |\n                         |         Interrupts         |\n                         +----------------------------+\n                          vmm.ko\n\n\n**vmm.ko**\n\nThe *bhyve* FreeBSD kernel module. Manages VM and vCPU objects, the guest physical address space and handles guest interaction with PIC, PIT, HPET, PM Timer, x(2)APIC and I/O-APIC. Contains a minimal x86 emulator to decode guest MMIO. Executes the two innermost vCPU runloops (VMX/SVM and interrupts/timers/paging). Has backends for Intel VMX and AMD SVM. Provides an ioctl and mmap API to userspace.\n\n**libvmmapi**\n\nThin abstraction layer between the vmm.ko ioctl interface and the userspace C API.\n\n**bhyve**\n\nThe userspace *bhyve* component (kind of a very light-weight QEMU) that executes virtual machines. Runs the guest I/O vCPU runloops. Manages ACPI, PCI and all non in-kernel devices. Interacts with vmm.ko through libvmmapi.\n\n**bhyvectl**\n\nSomewhat superfluous utility to introspect and manage the life cycle of virtual machines. Virtual machines and vCPUs can exist as kernel objects independently of a *bhyve* host process. Typically used to delete VM objects after use. Odd architectural choice.\n\n**bhyveload**\n\nUserspace port of the FreeBSD bootloader. This is a cumbersome workaround to bootstrap a FreeBSD guest operating system without using firmware. It creates a VM object, loads the FreeBSD kernel into guest memory, sets up the initial vCPU state and then exits. Only then a VM can be executed by *bhyve*.\n\n**grub2-bhyve**\n\nPerforms the same function as bhyveload but is a userspace port of [GRUB2](http://github.com/grehan-freebsd/grub2-bhyve). It is used to bootstrap guest operating systems other than FreeBSD, i.e. Linux, OpenBSD and NetBSD.\n\n\n*xhyve* architecture\n------------------\n        +----------------------------------------------------------+\n        | xhyve                                                    |\n        |                                                          |\n        |                            I/O                           |\n        |                                                          |\n        |                                                          |\n        |                                                          |\n        |+--------------------------------------------------------+|\n        ||  vmm                   VMX guest                       ||\n        ||                          Timers                        ||\n        ||                        Interrupts                      ||\n        |+--------------------------------------------------------+|\n        +----------------------------------------------------------+\n        +----------------------------------------------------------+\n        |                   Hypervisor.framework                   |\n        +----------------------------------------------------------+\n                                      A\n                                      |                         user\n        ------------------------------┼------------------------------\n                                      |syscall            xnu kernel\n                                      V\n        \n                                   VMX host\n                               VMX nested paging\n\n\n*xhyve* shares most of the code with *bhyve* but is architecturally very different. Hypervisor.framework provides an interface to the VMX VMCS guest state and a safe subset of the VMCS control fields, thus making userspace hypervisors without any additional kernel extensions possible. The VMX host state and all aspects of nested paging are handled by the macOS kernel, you can manage the guest physical address space simply through mapping of regions of your own address space.\n\n*xhyve* is equivalent to the *bhyve* process but gains a subset of a userspace port of the vmm kernel module. SVM, PCI passthrough and the VMX host and EPT aspects are dropped. The vmm component provides a libvmmapi compatible interface to *xhyve*. Hypervisor.framework seems to enforce a strict 1:1 relationship between a host process/VM and host thread/vCPU, that means VMs and vCPUs can only be interacted with by the processes and threads that created them. Therefore, unlike *bhyve*, *xhyve* needs to adhere to a single process model. Multiple virtual machines can be created by launching multiple instances of *xhyve*. *xhyve* retains most of the *bhyve* command line interface.\n\n*bhyvectl*, *bhyveload* and *grub2-bhyve* are incompatible with a single process model and are dropped. *xhyve* supports the Linux [kexec protocol](http://www.kernel.org/doc/Documentation/x86/boot.txt), a very simple and straightforward way to bootstrap a Linux kernel. It takes a bzImage and optionally initrd image and kernel parameter string as input.\n\n*xhyve* can now boot an OS via EFI. The BSD-licensed TianoCore EFI built for *bhyve* can be used to boot Windows and other OSs.\n\nNetworking\n----------\nIf you want the same IP address across VM reboots, assign a UUID to a particular VM:\n\n    $ xhyve [-U uuid]\n\n**Optional:**\n\nIf you need more advanced networking and already have a configured [TAP](http://tuntaposx.sourceforge.net) device you can use it with:\n\n\tvirtio-tap,tapX\n\ninstead of:\n\n    virtio-net\n\nWhere *X* is your tap device, i.e. */dev/tapX*.\n\nBooting TinyCoreLinux\n---------------------\n\nEverything needed to boot TinyCoreLinux is included with *xhyve*.\n\n**Steps:**\n\n- From Terminal, launch the `xhyverun-tinycorelinux.sh` script in your xhyve directory.\n\nBooting FreeBSD (via userboot)\n------------------------------\n**Requirements:**\n\n- A FreeBSD iso image. This can be downloaded from FreeBSD.org\n\n**Steps:**\n\n- Build *xhyve* with `make` (type `make` in Terminal from your *xhyve* directory) - this will build an unsigned copy of *xhyve*\n- `mkfile 5g FreeBSD.dmg` - Create a blank image to install to\n- Use your favorite text editor to edit the xhyverun-freebsd.sh script and properly set the paths to the iso and disk image\n- Run the script from Terminal with sudo: `sudo ./xhyverun-freebsd.sh` and enter your admin password\n\n**Known Issues:**\n- This will only work with an unsigned build of *xhyve* - See *Codesigning/Entitlements* in **Issues**\n\n\nBooting Windows (via EFI)\n-------------------------\n\nNow that *xhyve* has support for a framebuffer, EFI and the e1000 NIC, *xhyve* can now run Windows in a VM. \n\n**Requirements:**\n\n- A Windows 10 iso image. This can be downloaded from Microsoft: [Windows 10 iso](https://www.microsoft.com/en-us/software-download/windows10ISO)\n- A license key for Windows.\n- The *bhyve* EFI - this can be downloaded **in FreeBSD** via `pkg install bhyve-firmware` - the EFI will be named \"BHYVE_UEFI.fd\" and installed into `/usr/local/share/uefi-firmware`. Copy that file to macOS.\n- A VNC client - these vary greatly in speed and willingness to connect to the fairly minimal VNC server built into the framebuffer code.\n\n**Steps:**\n\n- `mkfile 20g Windows.dmg` - Create a blank image to install to\n- Use your favorite text editor to edit the `xhyverun-windows.sh` script and properly set the paths to the iso, disk image and BHYVE_UEFI.fd\n- From Terminal, launch the modified `xhyverun-windows.sh` script in your xhyve directory.\n- Connect the VNC client to 127.0.0.1:29000\n\n**Known Issues:**\n\n- Windows does not recognize more than one CPU and the CPU device is missing from Device Manager\n- The e1000 emulation works, but is incomplete - network statistics don't appear in Task Manager or Resource Monitor\n- Mouse positioning in VNC is wacky - this is due to the nature of how mouse deltas are passed to the VM and what Windows does to them afterwards. Once Windows is installed, one can enable remote connection and connect with Microsoft Remote Desktop instead of the VNC client.\n\nIssues\n------\n\n### Virtual Box\nIf you are, or were, running any version of VirtualBox, prior to 4.3.30 or 5.0, and attempt to run *xhyve*, your system will immediately crash as a kernel panic is triggered. This is due to a VirtualBox bug (that got fixed in newest VirtualBox versions) as VirtualBox wasn't playing nice with OSX's Hypervisor.framework used by *xhyve*.\n\nTo get around this you either have to update to newest VirtualBox 4.3 or 5.0 or, if you for some reason are unable to update, to reboot your Mac after using VirtualBox and before attempting to use *xhyve*. (see issues [#5](https://github.com/mist64/xhyve/issues/5) and [#9](https://github.com/mist64/xhyve/issues/9) for the full context)\n\n### Code signing/Entitlements\nmacOS limits access to the networking API (vmnet) to builds that are code signed and have the appropriate entitlement. The code signing/entitlement requirement can be bypassed by running *xhyve* as root (via `sudo`). A code signed build cannot run FreeBSD via the `userboot.so` bootloader as that requires loading and executing code that is outside the code signature (even as root). Building *xhyve* via `xcodebuild` signs the build. Building *xhyve* via `make` does not.\n\nTODO\n----\n\n- vmm:\n  - enable APIC access page to speed up APIC emulation (**performance**)\n  - enable x2APIC MSRs (even faster) (**performance**)\n  - vmm_callout:\n      - is a quick'n'dirty implementation of the FreeBSD kernel callout mechanism\n      - seems to be racy\n      - fix races or perhaps replace with something better\n      - use per vCPU timer event thread (**performance**)?\n      - use hardware VMX preemption timer instead of `pthread_cond_wait` (**performance**)\n  - some 32-bit guests are broken (support PAE paging in VMCS)\n  - PCID guest support (**performance**)\n- block_if:\n  - macOS does not support `preadv`/`pwritev`, we need to serialize reads and writes for the time being until we find a better solution. (**performance**)\n  - support block devices other than plain files\n- virtio_net:\n  - unify TAP and vmnet backends\n  - vmnet: send/receive more than a single packet at a time (**performance**)\n- virtio_rnd:\n  - is untested\n- e1000\n  - is untested beyond basically working with Windows\n  - fix missing statistics (see Booting Windows)\n  - add support for TAP\n  - tune performance (**performance**)\n- framebuffer\n  - is untested beyond basically working with Windows\n  - VNC: add support for more modern connections (ssh) to improve security and compatibility with more clients\n  - add an option to share the framebuffer with a client UI app (specifics need defining) (**performance**)\n- UEFI\n  - is untested beyond basically working with Windows\n  - Needs testing against various OSs\n  - figure out why Windows doesn't properly see more than one CPU (might also involve ACPI)\n- XHCI\n  - Move XHCI support and the tablet device to *xhyve*\n- remove explicit state transitions:\n  - since only the owning task/thread can modify the VM/vCPUs a lot of the synchronization might be unnecessary (**performance**)\n- performance, performance and performance\n- remove vestigial code, cleanup\n"
  },
  {
    "path": "config.mk",
    "content": "###############################################################################\n# Config                                                                      #\n#                                                                             #\n# [XHYVE_CONFIG_ASSERT] VMM asserts (disable for release builds?)             #\n# [XHYVE_CONFIG_TRACE]  VMM event tracer                                      #\n# [XHYVE_CONFIG_STATS]  VMM event profiler                                    #\n###############################################################################\n\nDEFINES := \\\n  -DXHYVE_CONFIG_ASSERT\n\n###############################################################################\n# Toolchain                                                                   #\n###############################################################################\n\nCC := clang\nAS := clang\nLD := clang\nSTRIP := strip\nDSYM := dsymutil\n\nENV := \\\n  LANG=en_US.US-ASCII\n\n###############################################################################\n# CFLAGS                                                                      #\n###############################################################################\n\nCFLAGS_OPT := \\\n  -Os \\\n  -flto \\\n  -fstrict-aliasing\n\nCFLAGS_WARN := \\\n  -Weverything \\\n  -Werror \\\n  -Wno-unknown-warning-option \\\n  -Wno-reserved-id-macro \\\n  -pedantic\n\nCFLAGS_DIAG := \\\n  -fmessage-length=152 \\\n  -fdiagnostics-show-note-include-stack \\\n  -fmacro-backtrace-limit=0 \\\n  -fcolor-diagnostics\n\nCFLAGS_DBG := \\\n  -g\n\nCFLAGS := \\\n  -arch x86_64 \\\n  -x c \\\n  -std=c11 \\\n  -fno-common \\\n  -fvisibility=hidden \\\n  $(DEFINES) \\\n  $(CFLAGS_OPT) \\\n  $(CFLAGS_WARN) \\\n  $(CFLAGS_DIAG) \\\n  $(CFLAGS_DBG)\n\n###############################################################################\n# LDFLAGS                                                                     #\n###############################################################################\n\nLDFLAGS_DBG := \\\n  -Xlinker -object_path_lto\n\nLDFLAGS := \\\n  -arch x86_64 \\\n  -framework Hypervisor \\\n  -framework vmnet \\\n  -lz \\\n  $(LDFLAGS_DBG)\n"
  },
  {
    "path": "include/xhyve/acpi.h",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n/* if set, create AML instead of ASL and calling out to iasl */\n#define ACPITBL_AML 1\n\n#define SCI_INT 9\n\n#define SMI_CMD 0xb2\n#define BHYVE_ACPI_ENABLE 0xa0\n#define BHYVE_ACPI_DISABLE 0xa1\n\n#define PM1A_EVT_ADDR 0x400\n#define PM1A_EVT_ADDR2 0x402\n#define PM1A_CNT_ADDR 0x404\n\n#define IO_PMTMR 0x408 /* 4-byte i/o port for the timer */\n\nint acpi_build(int ncpu);\nvoid dsdt_line(const char *fmt, ...);\nvoid dsdt_fixed_ioport(uint16_t iobase, uint16_t length);\nvoid dsdt_fixed_irq(uint8_t irq);\nvoid dsdt_fixed_mem32(uint32_t base, uint32_t length);\nvoid dsdt_indent(int levels);\nvoid dsdt_unindent(int levels);\nvoid dsdt_fixup(int bus, uint16_t iobase, uint16_t iolimit, uint32_t membase32,\n\tuint32_t memlimit32, uint64_t membase64, uint64_t memlimit64);\nvoid sci_init(void);\n"
  },
  {
    "path": "include/xhyve/ahci.h",
    "content": "/*-\n * Copyright (c) 1998 - 2008 Søren Schmidt <sos@FreeBSD.org>\n * Copyright (c) 2009-2012 Alexander Motin <mav@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer,\n *    without modification, immediately at the beginning of the file.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n/* ATA register defines */\n#define ATA_DATA                        0       /* (RW) data */\n\n#define ATA_FEATURE                     1       /* (W) feature */\n#define         ATA_F_DMA               0x01    /* enable DMA */\n#define         ATA_F_OVL               0x02    /* enable overlap */\n\n#define ATA_COUNT                       2       /* (W) sector count */\n\n#define ATA_SECTOR                      3       /* (RW) sector # */\n#define ATA_CYL_LSB                     4       /* (RW) cylinder# LSB */\n#define ATA_CYL_MSB                     5       /* (RW) cylinder# MSB */\n#define ATA_DRIVE                       6       /* (W) Sector/Drive/Head */\n#define         ATA_D_LBA               0x40    /* use LBA addressing */\n#define         ATA_D_IBM               0xa0    /* 512 byte sectors, ECC */\n\n#define ATA_COMMAND                     7       /* (W) command */\n\n#define ATA_ERROR                       8       /* (R) error */\n#define         ATA_E_ILI               0x01    /* illegal length */\n#define         ATA_E_NM                0x02    /* no media */\n#define         ATA_E_ABORT             0x04    /* command aborted */\n#define         ATA_E_MCR               0x08    /* media change request */\n#define         ATA_E_IDNF              0x10    /* ID not found */\n#define         ATA_E_MC                0x20    /* media changed */\n#define         ATA_E_UNC               0x40    /* uncorrectable data */\n#define         ATA_E_ICRC              0x80    /* UDMA crc error */\n#define\t\tATA_E_ATAPI_SENSE_MASK\t0xf0\t/* ATAPI sense key mask */\n\n#define ATA_IREASON                     9       /* (R) interrupt reason */\n#define         ATA_I_CMD               0x01    /* cmd (1) | data (0) */\n#define         ATA_I_IN                0x02    /* read (1) | write (0) */\n#define         ATA_I_RELEASE           0x04    /* released bus (1) */\n#define         ATA_I_TAGMASK           0xf8    /* tag mask */\n\n#define ATA_STATUS                      10      /* (R) status */\n#define ATA_ALTSTAT                     11      /* (R) alternate status */\n#define         ATA_S_ERROR             0x01    /* error */\n#define         ATA_S_INDEX             0x02    /* index */\n#define         ATA_S_CORR              0x04    /* data corrected */\n#define         ATA_S_DRQ               0x08    /* data request */\n#define         ATA_S_DSC               0x10    /* drive seek completed */\n#define         ATA_S_SERVICE           0x10    /* drive needs service */\n#define         ATA_S_DWF               0x20    /* drive write fault */\n#define         ATA_S_DMA               0x20    /* DMA ready */\n#define         ATA_S_READY             0x40    /* drive ready */\n#define         ATA_S_BUSY              0x80    /* busy */\n\n#define ATA_CONTROL                     12      /* (W) control */\n#define         ATA_A_IDS               0x02    /* disable interrupts */\n#define         ATA_A_RESET             0x04    /* RESET controller */\n#define         ATA_A_4BIT              0x08    /* 4 head bits */\n#define         ATA_A_HOB               0x80    /* High Order Byte enable */\n\n/* SATA register defines */\n#define ATA_SSTATUS                     13\n#define         ATA_SS_DET_MASK         0x0000000f\n#define         ATA_SS_DET_NO_DEVICE    0x00000000\n#define         ATA_SS_DET_DEV_PRESENT  0x00000001\n#define         ATA_SS_DET_PHY_ONLINE   0x00000003\n#define         ATA_SS_DET_PHY_OFFLINE  0x00000004\n\n#define         ATA_SS_SPD_MASK         0x000000f0\n#define         ATA_SS_SPD_NO_SPEED     0x00000000\n#define         ATA_SS_SPD_GEN1         0x00000010\n#define         ATA_SS_SPD_GEN2         0x00000020\n#define         ATA_SS_SPD_GEN3         0x00000030\n\n#define         ATA_SS_IPM_MASK         0x00000f00\n#define         ATA_SS_IPM_NO_DEVICE    0x00000000\n#define         ATA_SS_IPM_ACTIVE       0x00000100\n#define         ATA_SS_IPM_PARTIAL      0x00000200\n#define         ATA_SS_IPM_SLUMBER      0x00000600\n#define         ATA_SS_IPM_DEVSLEEP     0x00000800\n\n#define ATA_SERROR                      14\n#define         ATA_SE_DATA_CORRECTED   0x00000001\n#define         ATA_SE_COMM_CORRECTED   0x00000002\n#define         ATA_SE_DATA_ERR         0x00000100\n#define         ATA_SE_COMM_ERR         0x00000200\n#define         ATA_SE_PROT_ERR         0x00000400\n#define         ATA_SE_HOST_ERR         0x00000800\n#define         ATA_SE_PHY_CHANGED      0x00010000\n#define         ATA_SE_PHY_IERROR       0x00020000\n#define         ATA_SE_COMM_WAKE        0x00040000\n#define         ATA_SE_DECODE_ERR       0x00080000\n#define         ATA_SE_PARITY_ERR       0x00100000\n#define         ATA_SE_CRC_ERR          0x00200000\n#define         ATA_SE_HANDSHAKE_ERR    0x00400000\n#define         ATA_SE_LINKSEQ_ERR      0x00800000\n#define         ATA_SE_TRANSPORT_ERR    0x01000000\n#define         ATA_SE_UNKNOWN_FIS      0x02000000\n#define         ATA_SE_EXCHANGED        0x04000000\n\n#define ATA_SCONTROL                    15\n#define         ATA_SC_DET_MASK         0x0000000f\n#define         ATA_SC_DET_IDLE         0x00000000\n#define         ATA_SC_DET_RESET        0x00000001\n#define         ATA_SC_DET_DISABLE      0x00000004\n\n#define         ATA_SC_SPD_MASK         0x000000f0\n#define         ATA_SC_SPD_NO_SPEED     0x00000000\n#define         ATA_SC_SPD_SPEED_GEN1   0x00000010\n#define         ATA_SC_SPD_SPEED_GEN2   0x00000020\n#define         ATA_SC_SPD_SPEED_GEN3   0x00000030\n\n#define         ATA_SC_IPM_MASK         0x00000f00\n#define         ATA_SC_IPM_NONE         0x00000000\n#define         ATA_SC_IPM_DIS_PARTIAL  0x00000100\n#define         ATA_SC_IPM_DIS_SLUMBER  0x00000200\n#define         ATA_SC_IPM_DIS_DEVSLEEP 0x00000400\n\n#define ATA_SACTIVE                     16\n\n#define AHCI_MAX_PORTS\t\t\t32\n#define AHCI_MAX_SLOTS\t\t\t32\n#define AHCI_MAX_IRQS\t\t\t16\n\n/* SATA AHCI v1.0 register defines */\n#define AHCI_CAP                    0x00\n#define\t\tAHCI_CAP_NPMASK\t0x0000001f\n#define\t\tAHCI_CAP_SXS\t0x00000020\n#define\t\tAHCI_CAP_EMS\t0x00000040\n#define\t\tAHCI_CAP_CCCS\t0x00000080\n#define\t\tAHCI_CAP_NCS\t0x00001F00\n#define\t\tAHCI_CAP_NCS_SHIFT\t8\n#define\t\tAHCI_CAP_PSC\t0x00002000\n#define\t\tAHCI_CAP_SSC\t0x00004000\n#define\t\tAHCI_CAP_PMD\t0x00008000\n#define\t\tAHCI_CAP_FBSS\t0x00010000\n#define\t\tAHCI_CAP_SPM\t0x00020000\n#define\t\tAHCI_CAP_SAM\t0x00080000\n#define\t\tAHCI_CAP_ISS\t0x00F00000\n#define\t\tAHCI_CAP_ISS_SHIFT\t20\n#define\t\tAHCI_CAP_SCLO\t0x01000000\n#define\t\tAHCI_CAP_SAL\t0x02000000\n#define\t\tAHCI_CAP_SALP\t0x04000000\n#define\t\tAHCI_CAP_SSS\t0x08000000\n#define\t\tAHCI_CAP_SMPS\t0x10000000\n#define\t\tAHCI_CAP_SSNTF\t0x20000000\n#define\t\tAHCI_CAP_SNCQ\t0x40000000\n#define\t\tAHCI_CAP_64BIT\t0x80000000\n\n#define AHCI_GHC                    0x04\n#define         AHCI_GHC_AE         0x80000000\n#define         AHCI_GHC_MRSM       0x00000004\n#define         AHCI_GHC_IE         0x00000002\n#define         AHCI_GHC_HR         0x00000001\n\n#define AHCI_IS                     0x08\n#define AHCI_PI                     0x0c\n#define AHCI_VS                     0x10\n\n#define AHCI_CCCC                   0x14\n#define\t\tAHCI_CCCC_TV_MASK\t0xffff0000\n#define\t\tAHCI_CCCC_TV_SHIFT\t16\n#define\t\tAHCI_CCCC_CC_MASK\t0x0000ff00\n#define\t\tAHCI_CCCC_CC_SHIFT\t8\n#define\t\tAHCI_CCCC_INT_MASK\t0x000000f8\n#define\t\tAHCI_CCCC_INT_SHIFT\t3\n#define\t\tAHCI_CCCC_EN\t\t0x00000001\n#define AHCI_CCCP                   0x18\n\n#define AHCI_EM_LOC                 0x1C\n#define AHCI_EM_CTL                 0x20\n#define \tAHCI_EM_MR              0x00000001\n#define \tAHCI_EM_TM              0x00000100\n#define \tAHCI_EM_RST             0x00000200\n#define \tAHCI_EM_LED             0x00010000\n#define \tAHCI_EM_SAFTE           0x00020000\n#define \tAHCI_EM_SES2            0x00040000\n#define \tAHCI_EM_SGPIO           0x00080000\n#define \tAHCI_EM_SMB             0x01000000\n#define \tAHCI_EM_XMT             0x02000000\n#define \tAHCI_EM_ALHD            0x04000000\n#define \tAHCI_EM_PM              0x08000000\n\n#define AHCI_CAP2                   0x24\n#define\t\tAHCI_CAP2_BOH\t0x00000001\n#define\t\tAHCI_CAP2_NVMP\t0x00000002\n#define\t\tAHCI_CAP2_APST\t0x00000004\n#define\t\tAHCI_CAP2_SDS\t0x00000008\n#define\t\tAHCI_CAP2_SADM\t0x00000010\n#define\t\tAHCI_CAP2_DESO\t0x00000020\n\n#define AHCI_OFFSET                 0x100\n#define AHCI_STEP                   0x80\n\n#define AHCI_P_CLB                  0x00\n#define AHCI_P_CLBU                 0x04\n#define AHCI_P_FB                   0x08\n#define AHCI_P_FBU                  0x0c\n#define AHCI_P_IS                   0x10\n#define AHCI_P_IE                   0x14\n#define         AHCI_P_IX_DHR       0x00000001\n#define         AHCI_P_IX_PS        0x00000002\n#define         AHCI_P_IX_DS        0x00000004\n#define         AHCI_P_IX_SDB       0x00000008\n#define         AHCI_P_IX_UF        0x00000010\n#define         AHCI_P_IX_DP        0x00000020\n#define         AHCI_P_IX_PC        0x00000040\n#define         AHCI_P_IX_MP        0x00000080\n\n#define         AHCI_P_IX_PRC       0x00400000\n#define         AHCI_P_IX_IPM       0x00800000\n#define         AHCI_P_IX_OF        0x01000000\n#define         AHCI_P_IX_INF       0x04000000\n#define         AHCI_P_IX_IF        0x08000000\n#define         AHCI_P_IX_HBD       0x10000000\n#define         AHCI_P_IX_HBF       0x20000000\n#define         AHCI_P_IX_TFE       0x40000000\n#define         AHCI_P_IX_CPD       0x80000000\n\n#define AHCI_P_CMD                  0x18\n#define         AHCI_P_CMD_ST       0x00000001\n#define         AHCI_P_CMD_SUD      0x00000002\n#define         AHCI_P_CMD_POD      0x00000004\n#define         AHCI_P_CMD_CLO      0x00000008\n#define         AHCI_P_CMD_FRE      0x00000010\n#define         AHCI_P_CMD_CCS_MASK 0x00001f00\n#define         AHCI_P_CMD_CCS_SHIFT 8\n#define         AHCI_P_CMD_ISS      0x00002000\n#define         AHCI_P_CMD_FR       0x00004000\n#define         AHCI_P_CMD_CR       0x00008000\n#define         AHCI_P_CMD_CPS      0x00010000\n#define         AHCI_P_CMD_PMA      0x00020000\n#define         AHCI_P_CMD_HPCP     0x00040000\n#define         AHCI_P_CMD_MPSP     0x00080000\n#define         AHCI_P_CMD_CPD      0x00100000\n#define         AHCI_P_CMD_ESP      0x00200000\n#define         AHCI_P_CMD_FBSCP    0x00400000\n#define         AHCI_P_CMD_APSTE    0x00800000\n#define         AHCI_P_CMD_ATAPI    0x01000000\n#define         AHCI_P_CMD_DLAE     0x02000000\n#define         AHCI_P_CMD_ALPE     0x04000000\n#define         AHCI_P_CMD_ASP      0x08000000\n#define         AHCI_P_CMD_ICC_MASK 0xf0000000\n#define         AHCI_P_CMD_NOOP     0x00000000\n#define         AHCI_P_CMD_ACTIVE   0x10000000\n#define         AHCI_P_CMD_PARTIAL  0x20000000\n#define         AHCI_P_CMD_SLUMBER  0x60000000\n#define         AHCI_P_CMD_DEVSLEEP 0x80000000\n\n#define AHCI_P_TFD                  0x20\n#define AHCI_P_SIG                  0x24\n#define AHCI_P_SSTS                 0x28\n#define AHCI_P_SCTL                 0x2c\n#define AHCI_P_SERR                 0x30\n#define AHCI_P_SACT                 0x34\n#define AHCI_P_CI                   0x38\n#define AHCI_P_SNTF                 0x3C\n#define AHCI_P_FBS                  0x40\n#define \tAHCI_P_FBS_EN       0x00000001\n#define \tAHCI_P_FBS_DEC      0x00000002\n#define \tAHCI_P_FBS_SDE      0x00000004\n#define \tAHCI_P_FBS_DEV      0x00000f00\n#define \tAHCI_P_FBS_DEV_SHIFT 8\n#define \tAHCI_P_FBS_ADO      0x0000f000\n#define \tAHCI_P_FBS_ADO_SHIFT 12\n#define \tAHCI_P_FBS_DWE      0x000f0000\n#define \tAHCI_P_FBS_DWE_SHIFT 16\n#define AHCI_P_DEVSLP               0x44\n#define \tAHCI_P_DEVSLP_ADSE  0x00000001\n#define \tAHCI_P_DEVSLP_DSP   0x00000002\n#define \tAHCI_P_DEVSLP_DETO  0x000003fc\n#define \tAHCI_P_DEVSLP_DETO_SHIFT 2\n#define \tAHCI_P_DEVSLP_MDAT  0x00007c00\n#define \tAHCI_P_DEVSLP_MDAT_SHIFT 10\n#define \tAHCI_P_DEVSLP_DITO  0x01ff8000\n#define \tAHCI_P_DEVSLP_DITO_SHIFT 15\n#define \tAHCI_P_DEVSLP_DM    0x0e000000\n#define \tAHCI_P_DEVSLP_DM_SHIFT 25\n\n/* Just to be sure, if building as module. */\n#if MAXPHYS < 512 * 1024\n#undef MAXPHYS\n#define MAXPHYS 512 * 1024\n#endif\n/* Pessimistic prognosis on number of required S/G entries */\n#define AHCI_SG_ENTRIES (roundup(btoc(MAXPHYS) + 1, 8))\n/* Command list. 32 commands. First, 1Kbyte aligned. */\n#define AHCI_CL_OFFSET 0\n#define AHCI_CL_SIZE 32\n/* Command tables. Up to 32 commands, Each, 128byte aligned. */\n#define AHCI_CT_OFFSET (AHCI_CL_OFFSET + AHCI_CL_SIZE * AHCI_MAX_SLOTS)\n#define AHCI_CT_SIZE (128 + AHCI_SG_ENTRIES * 16)\n/* Total main work area. */\n#define AHCI_WORK_SIZE (AHCI_CT_OFFSET + AHCI_CT_SIZE * ch->numslots)\n"
  },
  {
    "path": "include/xhyve/atkbdc.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _ATKBDC_H_\n#define _ATKBDC_H_\n\nstruct atkbdc_softc;\nstruct vmctx;\n\nvoid atkbdc_init(void);\nvoid atkbdc_event(struct atkbdc_softc *sc, int iskbd);\n\n#endif /* _ATKBDC_H_ */\n"
  },
  {
    "path": "include/xhyve/bhyvegc.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _BHYVEGC_H_\n#define\t_BHYVEGC_H_\n\nstruct bhyvegc;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct bhyvegc_image {\n\tint\t\tvgamode;\n\tuint16_t    width;\n\tuint16_t\theight;\n\tuint32_t\t*data;\n};\n\n#pragma clang diagnostic pop\n\nstruct bhyvegc *bhyvegc_init(uint16_t width, uint16_t height, void *fbaddr);\nvoid bhyvegc_set_fbaddr(struct bhyvegc *gc, void *fbaddr);\nvoid bhyvegc_resize(struct bhyvegc *gc, uint16_t width, uint16_t height);\nstruct bhyvegc_image *bhyvegc_get_image(struct bhyvegc *gc);\n\n#endif /* _BHYVEGC_H_ */\n"
  },
  {
    "path": "include/xhyve/block_if.h",
    "content": "/*-\n * Copyright (c) 2013  Peter Grehan <grehan@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * The block API to be used by bhyve block-device emulations. The routines\n * are thread safe, with no assumptions about the context of the completion\n * callback - it may occur in the caller's context, or asynchronously in\n * another thread.\n */\n\n#pragma once\n\n#include <sys/uio.h>\n#include <sys/unistd.h>\n\n#define BLOCKIF_IOV_MAX 33 /* not practical to be IOV_MAX */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct blockif_req {\n\tstruct iovec br_iov[BLOCKIF_IOV_MAX];\n\tint br_iovcnt;\n\toff_t br_offset;\n\tssize_t br_resid;\n\tvoid (*br_callback)(struct blockif_req *req, int err);\n\tvoid *br_param;\n};\n#pragma clang diagnostic pop\n\nstruct blockif_ctxt;\nstruct blockif_ctxt *blockif_open(const char *optstr, const char *ident);\noff_t blockif_size(struct blockif_ctxt *bc);\nvoid blockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h, uint8_t *s);\nint blockif_sectsz(struct blockif_ctxt *bc);\nvoid blockif_psectsz(struct blockif_ctxt *bc, int *size, int *off);\nint blockif_queuesz(struct blockif_ctxt *bc);\nint blockif_is_ro(struct blockif_ctxt *bc);\nint blockif_candelete(struct blockif_ctxt *bc);\nint blockif_read(struct blockif_ctxt *bc, struct blockif_req *breq);\nint blockif_write(struct blockif_ctxt *bc, struct blockif_req *breq);\nint blockif_flush(struct blockif_ctxt *bc, struct blockif_req *breq);\nint blockif_delete(struct blockif_ctxt *bc, struct blockif_req *breq);\nint blockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq);\nint blockif_close(struct blockif_ctxt *bc);\n"
  },
  {
    "path": "include/xhyve/bootrom.h",
    "content": "/*-\n * Copyright (c) 2015 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef\t_BOOTROM_H_\n#define\t_BOOTROM_H_\n\nint\tbootrom_init(const char *romfile);\n\n#endif\n"
  },
  {
    "path": "include/xhyve/console.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _CONSOLE_H_\n#define\t_CONSOLE_H_\n\nstruct bhyvegc;\n\ntypedef void (*fb_render_func_t)(struct bhyvegc *gc, void *arg);\ntypedef void (*kbd_event_func_t)(int down, uint32_t keysym, void *arg);\ntypedef void (*ptr_event_func_t)(uint8_t mask, int x, int y, void *arg);\n\nvoid\tconsole_init(uint16_t w, uint16_t h, void *fbaddr);\n\nvoid\tconsole_set_fbaddr(void *fbaddr);\n\nstruct bhyvegc_image *console_get_image(void);\n\nvoid\tconsole_fb_register(fb_render_func_t render_cb, void *arg);\nvoid\tconsole_refresh(void);\n\nvoid\tconsole_kbd_register(kbd_event_func_t event_cb, void *arg, int pri);\nvoid\tconsole_key_event(int down, uint32_t keysym);\n\nvoid\tconsole_ptr_register(ptr_event_func_t event_cb, void *arg, int pri);\nvoid\tconsole_ptr_event(uint8_t button, int x, int y);\n\n#endif /* _CONSOLE_H_ */\n"
  },
  {
    "path": "include/xhyve/dbgport.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nvoid init_dbgport(int port);\n"
  },
  {
    "path": "include/xhyve/firmware/fbsd.h",
    "content": "#pragma once\n\n#include <stdint.h>\n\n/*\n * USERBOOT interface versions\n */\n#define USERBOOT_VERSION_1 1\n#define USERBOOT_VERSION_2 2\n#define USERBOOT_VERSION_3 3\n\n/*\n * Exit codes from the loader\n */\n#define USERBOOT_EXIT_QUIT 1\n#define USERBOOT_EXIT_REBOOT 2\n\nstruct loader_callbacks {\n\t/* Console i/o */\n\n\t/* Wait until a key is pressed on the console and then return it */\n\tint (*getc)(void *arg);\n\t/* Write the character ch to the console */\n\tvoid (*putc)(void *arg, int ch);\n\t/* Return non-zero if a key can be read from the console */\n\tint (*poll)(void *arg);\n\n\t/* Host filesystem i/o */\n\n\t/* Open a file in the host filesystem */\n\tint (*open)(void *arg, const char *filename, void **h_return);\n\t/* Close a file */\n\tint\t(*close)(void *arg, void *h);\n\t/* Return non-zero if the file is a directory */\n\tint (*isdir)(void *arg, void *h);\n\t/* Read size bytes from a file. The number of bytes remaining in dst after\n\t * reading is returned in *resid_return\n\t */\n\tint (*read)(void *arg, void *h, void *dst, size_t size,\n\t\tsize_t *resid_return);\n\t/* Read an entry from a directory. The entry's inode number is returned in\n\t * fileno_return, its type in *type_return and the name length in\n\t * *namelen_return. The name itself is copied to the buffer name which must\n\t * be at least PATH_MAX in size.\n\t */\n\tint (*readdir)(void *arg, void *h, uint32_t *fileno_return,\n\t\tuint8_t *type_return, size_t *namelen_return, char *name);\n\t/* Seek to a location within an open file */\n\tint (*seek)(void *arg, void *h, uint64_t offset, int whence);\n\t/* Return some stat(2) related information about the file */\n\tint (*stat)(void *arg, void *h, int *mode_return, int *uid_return,\n\t\tint *gid_return, uint64_t *size_return);\n\n\t/* Disk image i/o */\n\n\t/* Read from a disk image at the given offset */\n\tint\t(*diskread)(void *arg, int unit, uint64_t offset, void *dst,\n\t\tsize_t size, size_t *resid_return);\n\n\t/* Guest virtual machine i/o */\n\n\t/* Copy to the guest address space */\n\tint (*copyin)(void *arg, const void *from, uint64_t to, size_t size);\n\t/* Copy from the guest address space */\n\tint (*copyout)(void *arg, uint64_t from, void *to, size_t size);\n\t/* Set a guest register value */\n\tvoid (*setreg)(void *arg, int, uint64_t);\n\t/* Set a guest MSR value */\n\tvoid (*setmsr)(void *arg, u_int, uint64_t);\n\t/* Set a guest CR value */\n\tvoid (*setcr)(void *arg, int, uint64_t);\n\t/* Set the guest GDT address */\n\tvoid (*setgdt)(void *arg, uint64_t, size_t);\n\t/* Transfer control to the guest at the given address */\n\tvoid (*exec)(void *arg, uint64_t pc);\n\n\t/* Misc */\n\n\t/* Sleep for usec microseconds */\n\tvoid (*delay)(void *arg, int usec);\n\t/* Exit with the given exit code */\n\tvoid (*exit)(void);\n\t/* Return guest physical memory map details */\n\tvoid (*getmem)(void *arg, uint64_t *lowmem, uint64_t *highmem);\n\t/* ioctl interface to the disk device */\n\tint (*diskioctl)(void *arg, int unit, u_long cmd, void *data);\n\t/*\n\t * Returns an environment variable in the form \"name=value\".\n\t *\n\t * If there are no more variables that need to be set in the\n\t * loader environment then return NULL.\n\t *\n\t * 'num' is used as a handle for the callback to identify which\n\t * environment variable to return next. It will begin at 0 and\n\t * each invocation will add 1 to the previous value of 'num'.\n\t */\n\tconst char * (*getenv)(void *arg, int num);\n};\n\nvoid fbsd_init(char *userboot_path, char *bootvolume_path, char *kernelenv,\n\tchar *cons);\nuint64_t fbsd_load(void);\n"
  },
  {
    "path": "include/xhyve/firmware/kexec.h",
    "content": "#pragma once\n\n#include <stdint.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\nstruct setup_header {\n\tuint8_t setup_sects; /* The size of the setup in sectors */\n\tuint16_t root_flags; /* If set, the root is mounted readonly */\n\tuint32_t syssize; /* The size of the 32-bit code in 16-byte paras */\n\tuint16_t ram_size; /* DO NOT USE - for bootsect.S use only */\n\tuint16_t vid_mode; /* Video mode control */\n\tuint16_t root_dev; /* Default root device number */\n\tuint16_t boot_flag; /* 0xAA55 magic number */\n\tuint16_t jump; /* Jump instruction */\n\tuint32_t header; /* Magic signature \"HdrS\" */\n\tuint16_t version; /* Boot protocol version supported */\n\tuint32_t realmode_swtch; /* Boot loader hook (see below) */\n\tuint16_t start_sys_seg; /* The load-low segment (0x1000) (obsolete) */\n\tuint16_t kernel_version; /* Pointer to kernel version string */\n\tuint8_t type_of_loader; /* Boot loader identifier */\n\tuint8_t loadflags; /* Boot protocol option flags */\n\tuint16_t setup_move_size; /* Move to high memory size (used with hooks) */\n\tuint32_t code32_start; /* Boot loader hook (see below) */\n\tuint32_t ramdisk_image; /* initrd load address (set by boot loader) */\n\tuint32_t ramdisk_size; /* initrd size (set by boot loader) */\n\tuint32_t bootsect_kludge; /* DO NOT USE - for bootsect.S use only */\n\tuint16_t heap_end_ptr; /* Free memory after setup end */\n\tuint8_t ext_loader_ver; /* Extended boot loader version */\n\tuint8_t ext_loader_type; /* Extended boot loader ID */\n\tuint32_t cmd_line_ptr; /* 32-bit pointer to the kernel command line */\n\tuint32_t initrd_addr_max; /* Highest legal initrd address */\n\tuint32_t kernel_alignment; /* Physical addr alignment required for kernel */\n\tuint8_t relocatable_kernel; /* Whether kernel is relocatable or not */\n\tuint8_t min_alignment; /* Minimum alignment, as a power of two */\n\tuint16_t xloadflags; /* Boot protocol option flags */\n\tuint32_t cmdline_size; /* Maximum size of the kernel command line */\n\tuint32_t hardware_subarch; /* Hardware subarchitecture */\n\tuint64_t hardware_subarch_data; /* Subarchitecture-specific data */\n\tuint32_t payload_offset; /* Offset of kernel payload */\n\tuint32_t payload_length; /* Length of kernel payload */\n\tuint64_t setup_data; /* 64bit pointer to linked list of struct setup_data */\n\tuint64_t pref_address; /* Preferred loading address */\n\tuint32_t init_size; /* Linear memory required during initialization */\n\tuint32_t handover_offset; /* Offset of handover entry point */\n} __attribute__((packed));\n\nstruct zero_page {\n\tuint8_t screen_info[64];\n\tuint8_t apm_bios_info[20];\n\tuint8_t _0[4];\n\tuint64_t tboot_addr;\n\tuint8_t ist_info[16];\n\tuint8_t _1[16];\n\tuint8_t hd0_info[16];\n\tuint8_t hd1_info[16];\n\tuint8_t sys_desc_table[16];\n\tuint8_t olpc_ofw_header[16];\n\tuint32_t ext_ramdisk_image;\n\tuint32_t ext_ramdisk_size;\n\tuint32_t ext_cmd_line_ptr;\n\tuint8_t _2[116];\n\tuint8_t edid_info[128];\n\tuint8_t efi_info[32];\n\tuint32_t alt_mem_k;\n\tuint32_t scratch;\n\tuint8_t e820_entries;\n\tuint8_t eddbuf_entries;\n\tuint8_t edd_mbr_sig_buf_entries;\n\tuint8_t kbd_status;\n\tuint8_t _3[3];\n\tuint8_t sentinel;\n\tuint8_t _4[1];\n\tstruct setup_header setup_header;\n\tuint8_t _5[(0x290 - 0x1f1 - sizeof(struct setup_header))];\n\tuint32_t edd_mbr_sig_buffer[16];\n\tstruct {\n\t\tuint64_t addr;\n\t\tuint64_t size;\n\t\tuint32_t type;\n\t} __attribute__((packed)) e820_map[128];\n\tuint8_t _6[48];\n\tuint8_t eddbuf[492];\n\tuint8_t _7[276];\n} __attribute__((packed));\n#pragma clang diagnostic pop\n\nvoid kexec_init(char *kernel_path, char *initrd_path, char *cmdline);\nuint64_t kexec(void);\n"
  },
  {
    "path": "include/xhyve/inout.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/linker_set.h>\n\nstruct vm_exit;\n\n/*\n * inout emulation handlers return 0 on success and -1 on failure.\n */\ntypedef int (*inout_func_t)(int vcpu, int in, int port,\n\tint bytes, uint32_t *eax, void *arg);\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct inout_port {\n\tconst char *name;\n\tint port;\n\tint size;\n\tint flags;\n\tinout_func_t handler;\n\tvoid *arg;\n};\n#pragma clang diagnostic pop\n\n#define IOPORT_F_IN 0x1\n#define IOPORT_F_OUT 0x2\n#define IOPORT_F_INOUT (IOPORT_F_IN | IOPORT_F_OUT)\n\n/*\n * The following flags are used internally and must not be used by\n * device models.\n */\n#define IOPORT_F_DEFAULT 0x80000000 /* claimed by default handler */\n\n#define\tINOUT_PORT(name, port, flags, handler) \\\n\tstatic struct inout_port __CONCAT(__inout_port, port) = { \\\n\t\t#name, \\\n\t\t(port), \\\n\t\t1, \\\n\t\t(flags), \\\n\t\t(handler), \\\n\t\t0 \\\n\t}; \\\n\tDATA_SET(inout_port_set, __CONCAT(__inout_port, port))\n\nvoid init_inout(void);\nint emulate_inout(int vcpu, struct vm_exit *vmexit, int strict);\nint register_inout(struct inout_port *iop);\nint unregister_inout(struct inout_port *iop);\nvoid init_bvmcons(void);\n"
  },
  {
    "path": "include/xhyve/ioapic.h",
    "content": "/*-\n * Copyright (c) 2014 Hudson River Trading LLC\n * Written by: John H. Baldwin <jhb@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nstruct pci_devinst;\n\n/*\n * Allocate a PCI IRQ from the I/O APIC.\n */\nvoid ioapic_init(void);\nint ioapic_pci_alloc_irq(struct pci_devinst *pi);\n"
  },
  {
    "path": "include/xhyve/lock.h",
    "content": "/*-\n * Copyright (c) 2016 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <Availability.h>\n\n#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 /* __MAC_10_12 */\n\t#include <os/lock.h>\n\t#define xhyve_lock_t os_unfair_lock\n\t#define XHYVE_LOCK_INIT(V, LOCK) (V)->LOCK = OS_UNFAIR_LOCK_INIT;\n\t#define XHYVE_LOCK(V, LOCK) os_unfair_lock_lock(&(V)->LOCK)\n\t#define XHYVE_UNLOCK(V, LOCK) os_unfair_lock_unlock(&(V)->LOCK)\n#else\n\t#include <libkern/OSAtomic.h>\n\t#define xhyve_lock_t OSSpinLock\n\t#define XHYVE_LOCK_INIT(V, LOCK) (V)->LOCK = OS_SPINLOCK_INIT;\n\t#define XHYVE_LOCK(V, LOCK) OSSpinLockLock(&(V)->LOCK)\n\t#define XHYVE_UNLOCK(V, LOCK) OSSpinLockUnlock(&(V)->LOCK)\n#endif\n"
  },
  {
    "path": "include/xhyve/mem.h",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/linker_set.h>\n\ntypedef int (*mem_func_t)(int vcpu, int dir, uint64_t addr, int size,\n\tuint64_t *val, void *arg1, long arg2);\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct mem_range {\n\tconst char *name;\n\tint flags;\n\tmem_func_t handler;\n\tvoid *arg1;\n\tlong arg2;\n\tuint64_t base;\n\tuint64_t size;\n};\n#pragma clang diagnostic pop\n\n#define MEM_F_READ 0x1\n#define MEM_F_WRITE 0x2\n#define MEM_F_RW 0x3\n#define MEM_F_IMMUTABLE 0x4 /* mem_range cannot be unregistered */\n\nvoid init_mem(void);\nint emulate_mem(int vcpu, uint64_t paddr, struct vie *vie,\n\tstruct vm_guest_paging *paging);\n\nint register_mem(struct mem_range *memp);\nint register_mem_fallback(struct mem_range *memp);\nint unregister_mem(struct mem_range *memp);\n"
  },
  {
    "path": "include/xhyve/mevent.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nenum ev_type {\n\tEVF_READ,\n\tEVF_WRITE,\n\tEVF_TIMER,\n\tEVF_SIGNAL\n};\n\nstruct mevent;\n\nstruct mevent *mevent_add(int fd, enum ev_type type,\n\tvoid (*func)(int, enum ev_type, void *), void *param);\nint mevent_enable(struct mevent *evp);\nint mevent_disable(struct mevent *evp);\nint mevent_delete(struct mevent *evp);\nint mevent_delete_close(struct mevent *evp);\n\nvoid mevent_dispatch(void);\n"
  },
  {
    "path": "include/xhyve/mptbl.h",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nint mptable_build(int ncpu);\nvoid mptable_add_oemtbl(void *tbl, int tblsz);\n"
  },
  {
    "path": "include/xhyve/pci_emul.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <pthread.h>\n#include <assert.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/pcireg.h>\n#include <xhyve/support/linker_set.h>\n\n#define PCI_BARMAX PCIR_MAX_BAR_0 /* BAR registers in a Type 0 header */\n\nstruct pci_devinst;\nstruct memory_region;\n\nstruct pci_devemu {\n\t/* name of device emulation */\n\tchar *pe_emu;\n\t/* instance creation */\n\tint (*pe_init)(struct pci_devinst *, char *opts);\n\t/* ACPI DSDT enumeration */\n\tvoid (*pe_write_dsdt)(struct pci_devinst *);\n\t/* config space read/write callbacks */\n\tint\t(*pe_cfgwrite)(int vcpu, struct pci_devinst *pi,\n\t\tint offset, int bytes, uint32_t val);\n\tint\t(*pe_cfgread)(int vcpu, struct pci_devinst *pi, int offset, int bytes,\n\t\tuint32_t *retval);\n\t/* BAR read/write callbacks */\n\tvoid (*pe_barwrite)(int vcpu, struct pci_devinst *pi, int baridx,\n\t\tuint64_t offset, int size, uint64_t value);\n\tuint64_t (*pe_barread)(int vcpu, struct pci_devinst *pi, int baridx,\n\t\tuint64_t offset, int size);\n};\n\n#define PCI_EMUL_SET(x) DATA_SET(pci_devemu_set, x)\n\nenum pcibar_type {\n\tPCIBAR_NONE,\n\tPCIBAR_IO,\n\tPCIBAR_MEM32,\n\tPCIBAR_MEM64,\n\tPCIBAR_MEMHI64\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct pcibar {\n\tenum pcibar_type type; /* io or memory */\n\tuint64_t size;\n\tuint64_t addr;\n};\n#pragma clang diagnostic pop\n\n#define PI_NAMESZ 40\n\nstruct msix_table_entry {\n\tuint64_t addr;\n\tuint32_t msg_data;\n\tuint32_t vector_control;\n};\n\n/* \n * In case the structure is modified to hold extra information, use a define\n * for the size that should be emulated.\n */\n#define MSIX_TABLE_ENTRY_SIZE 16\n#define MAX_MSIX_TABLE_ENTRIES 2048\n#define PBA_SIZE(msgnum) (roundup2((msgnum), 64) / 8)\n\nenum lintr_stat {\n\tIDLE,\n\tASSERTED,\n\tPENDING\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct pci_devinst {\n\tstruct pci_devemu *pi_d;\n\tuint8_t pi_bus, pi_slot, pi_func;\n\tchar pi_name[PI_NAMESZ];\n\tint pi_bar_getsize;\n\tint pi_prevcap;\n\tint pi_capend;\n\n\tstruct {\n\t\tint8_t pin;\n\t\tenum lintr_stat state;\n\t\tint pirq_pin;\n\t\tint ioapic_irq;\n\t\tpthread_mutex_t lock;\n\t} pi_lintr;\n\n\tstruct {\n\t\tint enabled;\n\t\tuint64_t addr;\n\t\tuint64_t msg_data;\n\t\tint maxmsgnum;\n\t} pi_msi;\n\n\tstruct {\n\t\tint enabled;\n\t\tint table_bar;\n\t\tint pba_bar;\n\t\tuint32_t table_offset;\n\t\tint table_count;\n\t\tuint32_t pba_offset;\n\t\tint pba_size;\n\t\tint function_mask;\n\t\tstruct msix_table_entry *table; /* allocated at runtime */\n\t} pi_msix;\n\n\tvoid *pi_arg; /* devemu-private data */\n\n\tu_char pi_cfgdata[PCI_REGMAX + 1];\n\tstruct pcibar pi_bar[PCI_BARMAX + 1];\n};\n#pragma clang diagnostic pop\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\nstruct msicap {\n\tuint8_t capid;\n\tuint8_t nextptr;\n\tuint16_t msgctrl;\n\tuint32_t addrlo;\n\tuint32_t addrhi;\n\tuint16_t msgdata;\n} __packed;\n\nstruct msixcap {\n\tuint8_t capid;\n\tuint8_t nextptr;\n\tuint16_t msgctrl;\n\tuint32_t table_info; /* bar index and offset within it */\n\tuint32_t pba_info; /* bar index and offset within it */\n} __packed;\n\nstruct pciecap {\n\tuint8_t capid;\n\tuint8_t nextptr;\n\tuint16_t pcie_capabilities;\n\n\tuint32_t dev_capabilities; /* all devices */\n\tuint16_t dev_control;\n\tuint16_t dev_status;\n\n\tuint32_t link_capabilities; /* devices with links */\n\tuint16_t link_control;\n\tuint16_t link_status;\n\n\tuint32_t slot_capabilities; /* ports with slots */\n\tuint16_t slot_control;\n\tuint16_t slot_status;\n\n\tuint16_t root_control; /* root ports */\n\tuint16_t root_capabilities;\n\tuint32_t root_status;\n\n\tuint32_t dev_capabilities2; /* all devices */\n\tuint16_t dev_control2;\n\tuint16_t dev_status2;\n\n\tuint32_t link_capabilities2; /* devices with links */\n\tuint16_t link_control2;\n\tuint16_t link_status2;\n\n\tuint32_t slot_capabilities2; /* ports with slots */\n\tuint16_t slot_control2;\n\tuint16_t slot_status2;\n} __packed;\n#pragma clang diagnostic pop\n\ntypedef void (*pci_lintr_cb)(int b, int s, int pin, int pirq_pin,\n\tint ioapic_irq, void *arg);\n\nint init_pci(void);\nvoid msicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,\n\tint bytes, uint32_t val);\nvoid msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,\n\tint bytes, uint32_t val);\nvoid pci_callback(void);\nint pci_emul_alloc_bar(struct pci_devinst *pdi, int idx,\n\tenum pcibar_type type, uint64_t size);\nint pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx,\n\tuint64_t hostbase, enum pcibar_type type, uint64_t size);\nint pci_emul_add_msicap(struct pci_devinst *pi, int msgnum);\nint pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type);\nvoid pci_generate_msi(struct pci_devinst *pi, int msgnum);\nvoid pci_generate_msix(struct pci_devinst *pi, int msgnum);\nvoid pci_lintr_assert(struct pci_devinst *pi);\nvoid pci_lintr_deassert(struct pci_devinst *pi);\nvoid pci_lintr_request(struct pci_devinst *pi);\nint pci_msi_enabled(struct pci_devinst *pi);\nint pci_msix_enabled(struct pci_devinst *pi);\nint pci_msix_table_bar(struct pci_devinst *pi);\nint pci_msix_pba_bar(struct pci_devinst *pi);\nint pci_msi_msgnum(struct pci_devinst *pi);\nint pci_parse_slot(char *opt);\nvoid pci_populate_msicap(struct msicap *cap, int msgs, int nextptr);\nint pci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum);\nint pci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,\n\tuint64_t value);\nuint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size);\nint pci_count_lintr(int bus);\nvoid pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg);\nvoid pci_write_dsdt(void);\nuint64_t pci_ecfg_base(void);\nint pci_bus_configured(int bus);\n\nstatic __inline void \npci_set_cfgdata8(struct pci_devinst *pi, int offset, uint8_t val)\n{\n\tassert(offset <= PCI_REGMAX);\n\t*(uint8_t *)(((uintptr_t) &pi->pi_cfgdata) + ((unsigned) offset)) = val;\n}\n\nstatic __inline void \npci_set_cfgdata16(struct pci_devinst *pi, int offset, uint16_t val)\n{\n\tassert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);\n\t*(uint16_t *)(((uintptr_t) &pi->pi_cfgdata) + ((unsigned) offset)) = val;\n}\n\nstatic __inline void \npci_set_cfgdata32(struct pci_devinst *pi, int offset, uint32_t val)\n{\n\tassert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);\n\t*(uint32_t *)(((uintptr_t) &pi->pi_cfgdata) + ((unsigned) offset)) = val;\n}\n\nstatic __inline uint8_t\npci_get_cfgdata8(struct pci_devinst *pi, int offset)\n{\n\tassert(offset <= PCI_REGMAX);\n\treturn (*(uint8_t *)(((uintptr_t) &pi->pi_cfgdata) + ((unsigned) offset)));\n}\n\nstatic __inline uint16_t\npci_get_cfgdata16(struct pci_devinst *pi, int offset)\n{\n\tassert(offset <= (PCI_REGMAX - 1) && (offset & 1) == 0);\n\treturn (*(uint16_t *)(((uintptr_t) &pi->pi_cfgdata) + ((unsigned) offset)));\n}\n\nstatic __inline uint32_t\npci_get_cfgdata32(struct pci_devinst *pi, int offset)\n{\n\tassert(offset <= (PCI_REGMAX - 3) && (offset & 3) == 0);\n\treturn (*(uint32_t *)(((uintptr_t) &pi->pi_cfgdata) + ((unsigned) offset)));\n}\n"
  },
  {
    "path": "include/xhyve/pci_irq.h",
    "content": "/*-\n * Copyright (c) 2014 Hudson River Trading LLC\n * Written by: John H. Baldwin <jhb@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nstruct pci_devinst;\n\nvoid pci_irq_assert(struct pci_devinst *pi);\nvoid pci_irq_deassert(struct pci_devinst *pi);\nvoid pci_irq_init(void);\nvoid pci_irq_reserve(int irq);\nvoid pci_irq_use(int irq);\nint pirq_alloc_pin(struct pci_devinst *pi);\nint pirq_irq(int pin);\nuint8_t pirq_read(int pin);\nvoid pirq_write(int pin, uint8_t val);\n"
  },
  {
    "path": "include/xhyve/pci_lpc.h",
    "content": "/*-\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/linker_set.h>\n\ntypedef void (*lpc_write_dsdt_t)(void);\n\nstruct lpc_dsdt {\n\tlpc_write_dsdt_t handler;\n};\n\n#define\tLPC_DSDT(handler) \\\n\tstatic struct lpc_dsdt __CONCAT(__lpc_dsdt, handler) = { \\\n\t\t(handler), \\\n\t}; \\\n\tDATA_SET(lpc_dsdt_set, __CONCAT(__lpc_dsdt, handler))\n\nenum lpc_sysres_type {\n\tLPC_SYSRES_IO,\n\tLPC_SYSRES_MEM\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct lpc_sysres {\n\tenum lpc_sysres_type type;\n\tuint32_t base;\n\tuint32_t length;\n};\n#pragma clang diagnostic pop\n\n#define\tLPC_SYSRES(type, base, length) \\\n\tstatic struct lpc_sysres __CONCAT(__lpc_sysres, base) = {\\\n\t\t(type), \\\n\t\t(base), \\\n\t\t(length) \\\n\t}; \\\n\tDATA_SET(lpc_sysres_set, __CONCAT(__lpc_sysres, base))\n\n#define SYSRES_IO(base, length) LPC_SYSRES(LPC_SYSRES_IO, base, length)\n#define SYSRES_MEM(base, length) LPC_SYSRES(LPC_SYSRES_MEM, base, length)\n\nint lpc_device_parse(const char *opt);\nchar *lpc_pirq_name(int pin);\nvoid lpc_pirq_routed(void);\nconst char *lpc_bootrom(void);\n"
  },
  {
    "path": "include/xhyve/ps2kbd.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _PS2KBD_H_\n#define\t_PS2KBD_H_\n\nstruct atkbdc_softc;\n\nstruct ps2kbd_softc *ps2kbd_init(struct atkbdc_softc *sc);\n\nint ps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val);\nvoid ps2kbd_write(struct ps2kbd_softc *sc, uint8_t val);\n\n#endif /* _PS2KBD_H_ */\n"
  },
  {
    "path": "include/xhyve/ps2mouse.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _PS2MOUSE_H_\n#define\t_PS2MOUSE_H_\n\nstruct atkbdc_softc;\n\nstruct ps2mouse_softc *ps2mouse_init(struct atkbdc_softc *sc);\n\nint ps2mouse_read(struct ps2mouse_softc *sc, uint8_t *val);\nvoid ps2mouse_write(struct ps2mouse_softc *sc, uint8_t val, int insert);\nvoid ps2mouse_toggle(struct ps2mouse_softc *sc, int enable);\nint ps2mouse_fifocnt(struct ps2mouse_softc *sc);\n\n#endif /* _PS2MOUSE_H_ */\n"
  },
  {
    "path": "include/xhyve/rfb.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _RFB_H_\n#define\t_RFB_H_\n\n#define\tRFB_PORT\t5900\n\nint\trfb_init(char *hostname, int port, int wait, char *password);\n\n#endif /* _RFB_H_ */\n"
  },
  {
    "path": "include/xhyve/rtc.h",
    "content": "/*\n * Copyright (c) 2013  Peter Grehan <grehan@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nvoid rtc_init(int use_localtime);\n\n"
  },
  {
    "path": "include/xhyve/smbiostbl.h",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nint smbios_build(void);\n"
  },
  {
    "path": "include/xhyve/sockstream.h",
    "content": "/*-\n * Copyright (c) 2015 Nahanni Systems, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <sys/types.h>\n#include <unistd.h>\n\nssize_t stream_read(int fd, void *buf, ssize_t nbytes);\nssize_t stream_write(int fd, const void *buf, ssize_t nbytes);\n"
  },
  {
    "path": "include/xhyve/support/acpi_hpet.h",
    "content": "/*-\n * Copyright (c) 2005 Poul-Henning Kamp\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#define HPET_MEM_WIDTH\t\t0x400\t/* Expected memory region size */\n\n/* General registers */\n#define HPET_CAPABILITIES\t0x0\t/* General capabilities and ID */\n#define\tHPET_CAP_VENDOR_ID\t0xffff0000\n#define\tHPET_CAP_LEG_RT\t\t0x00008000\n#define\tHPET_CAP_COUNT_SIZE\t0x00002000 /* 1 = 64-bit, 0 = 32-bit */\n#define\tHPET_CAP_NUM_TIM\t0x00001f00\n#define\tHPET_CAP_REV_ID\t\t0x000000ff\n#define HPET_PERIOD\t\t0x4\t/* Period (1/hz) of timer */\n#define HPET_CONFIG\t\t0x10\t/* General configuration register */\n#define\tHPET_CNF_LEG_RT\t\t0x00000002\n#define\tHPET_CNF_ENABLE\t\t0x00000001\n#define\tHPET_ISR\t\t0x20\t/* General interrupt status register */\n#define HPET_MAIN_COUNTER\t0xf0\t/* Main counter register */\n\n/* Timer registers */\n#define\tHPET_TIMER_CAP_CNF(x)\t((x) * 0x20 + 0x100)\n#define\tHPET_TCAP_INT_ROUTE\t0xffffffff00000000\n#define\tHPET_TCAP_FSB_INT_DEL\t0x00008000\n#define\tHPET_TCNF_FSB_EN\t0x00004000\n#define\tHPET_TCNF_INT_ROUTE\t0x00003e00\n#define\tHPET_TCNF_32MODE\t0x00000100\n#define\tHPET_TCNF_VAL_SET\t0x00000040\n#define\tHPET_TCAP_SIZE\t\t0x00000020 /* 1 = 64-bit, 0 = 32-bit */\n#define\tHPET_TCAP_PER_INT\t0x00000010 /* Supports periodic interrupts */\n#define\tHPET_TCNF_TYPE\t\t0x00000008 /* 1 = periodic, 0 = one-shot */\n#define\tHPET_TCNF_INT_ENB\t0x00000004\n#define\tHPET_TCNF_INT_TYPE\t0x00000002 /* 1 = level triggered, 0 = edge */\n#define\tHPET_TIMER_COMPARATOR(x) ((x) * 0x20 + 0x108)\n#define\tHPET_TIMER_FSB_VAL(x)\t((x) * 0x20 + 0x110)\n#define\tHPET_TIMER_FSB_ADDR(x)\t((x) * 0x20 + 0x114)\n\n#define\tHPET_MIN_CYCLES\t\t128\t/* Period considered reliable. */\n"
  },
  {
    "path": "include/xhyve/support/apicreg.h",
    "content": "/*-\n * Copyright (c) 1996, by Peter Wemm and Steve Passe\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. The name of the developer may NOT be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n/*\n * Local && I/O APIC definitions.\n */\n\n/*\n * Pentium P54C+ Built-in APIC\n * (Advanced programmable Interrupt Controller)\n * \n * Base Address of Built-in APIC in memory location\n * is 0xfee00000.\n * \n * Map of APIC Registers:\n * \n * Offset (hex)    Description                     Read/Write state\n * 000             Reserved\n * 010             Reserved\n * 020 ID          Local APIC ID                   R/W\n * 030 VER         Local APIC Version              R\n * 040             Reserved\n * 050             Reserved\n * 060             Reserved\n * 070             Reserved\n * 080             Task Priority Register          R/W\n * 090             Arbitration Priority Register   R\n * 0A0             Processor Priority Register     R\n * 0B0             EOI Register                    W\n * 0C0 RRR         Remote read                     R\n * 0D0             Logical Destination             R/W\n * 0E0             Destination Format Register     0..27 R;  28..31 R/W\n * 0F0 SVR         Spurious Interrupt Vector Reg.  0..3  R;  4..9   R/W\n * 100             ISR  000-031                    R\n * 110             ISR  032-063                    R\n * 120             ISR  064-095                    R\n * 130             ISR  095-128                    R\n * 140             ISR  128-159                    R\n * 150             ISR  160-191                    R\n * 160             ISR  192-223                    R\n * 170             ISR  224-255                    R\n * 180             TMR  000-031                    R\n * 190             TMR  032-063                    R\n * 1A0             TMR  064-095                    R\n * 1B0             TMR  095-128                    R\n * 1C0             TMR  128-159                    R\n * 1D0             TMR  160-191                    R\n * 1E0             TMR  192-223                    R\n * 1F0             TMR  224-255                    R\n * 200             IRR  000-031                    R\n * 210             IRR  032-063                    R\n * 220             IRR  064-095                    R\n * 230             IRR  095-128                    R\n * 240             IRR  128-159                    R\n * 250             IRR  160-191                    R\n * 260             IRR  192-223                    R\n * 270             IRR  224-255                    R\n * 280             Error Status Register           R\n * 290             Reserved\n * 2A0             Reserved\n * 2B0             Reserved\n * 2C0             Reserved\n * 2D0             Reserved\n * 2E0             Reserved\n * 2F0             Local Vector Table (CMCI)       R/W\n * 300 ICR_LOW     Interrupt Command Reg. (0-31)   R/W\n * 310 ICR_HI      Interrupt Command Reg. (32-63)  R/W\n * 320             Local Vector Table (Timer)      R/W\n * 330             Local Vector Table (Thermal)    R/W (PIV+)\n * 340             Local Vector Table (Performance) R/W (P6+)\n * 350 LVT1        Local Vector Table (LINT0)      R/W\n * 360 LVT2        Local Vector Table (LINT1)      R/W\n * 370 LVT3        Local Vector Table (ERROR)      R/W\n * 380             Initial Count Reg. for Timer    R/W\n * 390             Current Count of Timer          R\n * 3A0             Reserved\n * 3B0             Reserved\n * 3C0             Reserved\n * 3D0             Reserved\n * 3E0             Timer Divide Configuration Reg. R/W\n * 3F0             Reserved\n */\n\n\n/******************************************************************************\n * global defines, etc.\n */\n\n\n/******************************************************************************\n * LOCAL APIC structure\n */\n\n#define PAD3\tint : 32; int : 32; int : 32\n#define PAD4\tint : 32; int : 32; int : 32; int : 32\n\nstruct LAPIC {\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\tuint32_t id;\t\tPAD3;\n\tuint32_t version;\tPAD3;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\tuint32_t tpr;\t\tPAD3;\n\tuint32_t apr;\t\tPAD3;\n\tuint32_t ppr;\t\tPAD3;\n\tuint32_t eoi;\t\tPAD3;\n\t/* reserved */\t\tPAD4;\n\tuint32_t ldr;\t\tPAD3;\n\tuint32_t dfr;\t\tPAD3;\n\tuint32_t svr;\t\tPAD3;\n\tuint32_t isr0;\t\tPAD3;\n\tuint32_t isr1;\t\tPAD3;\n\tuint32_t isr2;\t\tPAD3;\n\tuint32_t isr3;\t\tPAD3;\n\tuint32_t isr4;\t\tPAD3;\n\tuint32_t isr5;\t\tPAD3;\n\tuint32_t isr6;\t\tPAD3;\n\tuint32_t isr7;\t\tPAD3;\n\tuint32_t tmr0;\t\tPAD3;\n\tuint32_t tmr1;\t\tPAD3;\n\tuint32_t tmr2;\t\tPAD3;\n\tuint32_t tmr3;\t\tPAD3;\n\tuint32_t tmr4;\t\tPAD3;\n\tuint32_t tmr5;\t\tPAD3;\n\tuint32_t tmr6;\t\tPAD3;\n\tuint32_t tmr7;\t\tPAD3;\n\tuint32_t irr0;\t\tPAD3;\n\tuint32_t irr1;\t\tPAD3;\n\tuint32_t irr2;\t\tPAD3;\n\tuint32_t irr3;\t\tPAD3;\n\tuint32_t irr4;\t\tPAD3;\n\tuint32_t irr5;\t\tPAD3;\n\tuint32_t irr6;\t\tPAD3;\n\tuint32_t irr7;\t\tPAD3;\n\tuint32_t esr;\t\tPAD3;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\tuint32_t lvt_cmci;\tPAD3;\n\tuint32_t icr_lo;\tPAD3;\n\tuint32_t icr_hi;\tPAD3;\n\tuint32_t lvt_timer;\tPAD3;\n\tuint32_t lvt_thermal;\tPAD3;\n\tuint32_t lvt_pcint;\tPAD3;\n\tuint32_t lvt_lint0;\tPAD3;\n\tuint32_t lvt_lint1;\tPAD3;\n\tuint32_t lvt_error;\tPAD3;\n\tuint32_t icr_timer;\tPAD3;\n\tuint32_t ccr_timer;\tPAD3;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\t/* reserved */\t\tPAD4;\n\tuint32_t dcr_timer;\tPAD3;\n\t/* reserved */\t\tPAD4;\n};\n\ntypedef struct LAPIC lapic_t;\n\nenum LAPIC_REGISTERS {\n\tLAPIC_ID\t= 0x2,\n\tLAPIC_VERSION\t= 0x3,\n\tLAPIC_TPR\t= 0x8,\n\tLAPIC_APR\t= 0x9,\n\tLAPIC_PPR\t= 0xa,\n\tLAPIC_EOI\t= 0xb,\n\tLAPIC_LDR\t= 0xd,\n\tLAPIC_DFR\t= 0xe, /* Not in x2APIC */\n\tLAPIC_SVR\t= 0xf,\n\tLAPIC_ISR0\t= 0x10,\n\tLAPIC_ISR1\t= 0x11,\n\tLAPIC_ISR2\t= 0x12,\n\tLAPIC_ISR3\t= 0x13,\n\tLAPIC_ISR4\t= 0x14,\n\tLAPIC_ISR5\t= 0x15,\n\tLAPIC_ISR6\t= 0x16,\n\tLAPIC_ISR7\t= 0x17,\n\tLAPIC_TMR0\t= 0x18,\n\tLAPIC_TMR1\t= 0x19,\n\tLAPIC_TMR2\t= 0x1a,\n\tLAPIC_TMR3\t= 0x1b,\n\tLAPIC_TMR4\t= 0x1c,\n\tLAPIC_TMR5\t= 0x1d,\n\tLAPIC_TMR6\t= 0x1e,\n\tLAPIC_TMR7\t= 0x1f,\n\tLAPIC_IRR0\t= 0x20,\n\tLAPIC_IRR1\t= 0x21,\n\tLAPIC_IRR2\t= 0x22,\n\tLAPIC_IRR3\t= 0x23,\n\tLAPIC_IRR4\t= 0x24,\n\tLAPIC_IRR5\t= 0x25,\n\tLAPIC_IRR6\t= 0x26,\n\tLAPIC_IRR7\t= 0x27,\n\tLAPIC_ESR\t= 0x28,\n\tLAPIC_LVT_CMCI\t= 0x2f,\n\tLAPIC_ICR_LO\t= 0x30,\n\tLAPIC_ICR_HI\t= 0x31, /* Not in x2APIC */\n\tLAPIC_LVT_TIMER\t= 0x32,\n\tLAPIC_LVT_THERMAL = 0x33,\n\tLAPIC_LVT_PCINT\t= 0x34,\n\tLAPIC_LVT_LINT0\t= 0x35,\n\tLAPIC_LVT_LINT1\t= 0x36,\n\tLAPIC_LVT_ERROR\t= 0x37,\n\tLAPIC_ICR_TIMER\t= 0x38,\n\tLAPIC_CCR_TIMER\t= 0x39,\n\tLAPIC_DCR_TIMER\t= 0x3e,\n\tLAPIC_SELF_IPI\t= 0x3f, /* Only in x2APIC */\n};\n\n/*\n * The LAPIC_SELF_IPI register only exists in x2APIC mode.  The\n * formula below is applicable only to reserve the memory region,\n * i.e. for xAPIC mode, where LAPIC_SELF_IPI finely serves as the\n * address past end of the region.\n */\n#define\tLAPIC_MEM_REGION (LAPIC_SELF_IPI * 0x10)\n\n#define\tLAPIC_MEM_MUL\t0x10\n\n/******************************************************************************\n * I/O APIC structure\n */\n\nstruct IOAPIC {\n\tuint32_t ioregsel;\tPAD3;\n\tuint32_t iowin;\tPAD3;\n};\n\ntypedef struct IOAPIC ioapic_t;\n\n#undef PAD4\n#undef PAD3\n\n\n/******************************************************************************\n * various code 'logical' values\n */\n\n/******************************************************************************\n * LOCAL APIC defines\n */\n\n/* default physical locations of LOCAL (CPU) APICs */\n#define DEFAULT_APIC_BASE\t0xfee00000\n\n/* constants relating to APIC ID registers */\n#define APIC_ID_MASK\t\t0xff000000\n#define\tAPIC_ID_SHIFT\t\t24\n#define\tAPIC_ID_CLUSTER\t\t0xf0\n#define\tAPIC_ID_CLUSTER_ID\t0x0f\n#define\tAPIC_MAX_CLUSTER\t0xe\n#define\tAPIC_MAX_INTRACLUSTER_ID 3\n#define\tAPIC_ID_CLUSTER_SHIFT\t4\n\n/* fields in VER */\n#define APIC_VER_VERSION\t0x000000ff\n#define APIC_VER_MAXLVT\t\t0x00ff0000\n#define MAXLVTSHIFT\t\t16\n#define APIC_VER_EOI_SUPPRESSION 0x01000000\n\n/* fields in LDR */\n#define\tAPIC_LDR_RESERVED\t0x00ffffff\n\n/* fields in DFR */\n#define\tAPIC_DFR_RESERVED\t0x0fffffff\n#define\tAPIC_DFR_MODEL_MASK\t0xf0000000\n#define\tAPIC_DFR_MODEL_FLAT\t0xf0000000\n#define\tAPIC_DFR_MODEL_CLUSTER\t0x00000000\n\n/* fields in SVR */\n#define APIC_SVR_VECTOR\t\t0x000000ff\n#define APIC_SVR_VEC_PROG\t0x000000f0\n#define APIC_SVR_VEC_FIX\t0x0000000f\n#define APIC_SVR_ENABLE\t\t0x00000100\n# define APIC_SVR_SWDIS\t\t0x00000000\n# define APIC_SVR_SWEN\t\t0x00000100\n#define APIC_SVR_FOCUS\t\t0x00000200\n# define APIC_SVR_FEN\t\t0x00000000\n# define APIC_SVR_FDIS\t\t0x00000200\n#define APIC_SVR_EOI_SUPPRESSION 0x00001000\n\n/* fields in TPR */\n#define APIC_TPR_PRIO\t\t0x000000ff\n# define APIC_TPR_INT\t\t0x000000f0\n# define APIC_TPR_SUB\t\t0x0000000f\n\n/* fields in ESR */\n#define\tAPIC_ESR_SEND_CS_ERROR\t\t0x00000001\n#define\tAPIC_ESR_RECEIVE_CS_ERROR\t0x00000002\n#define\tAPIC_ESR_SEND_ACCEPT\t\t0x00000004\n#define\tAPIC_ESR_RECEIVE_ACCEPT\t\t0x00000008\n#define\tAPIC_ESR_SEND_ILLEGAL_VECTOR\t0x00000020\n#define\tAPIC_ESR_RECEIVE_ILLEGAL_VECTOR\t0x00000040\n#define\tAPIC_ESR_ILLEGAL_REGISTER\t0x00000080\n\n/* fields in ICR_LOW */\n#define APIC_VECTOR_MASK\t0x000000ff\n\n#define APIC_DELMODE_MASK\t0x00000700\n# define APIC_DELMODE_FIXED\t0x00000000\n# define APIC_DELMODE_LOWPRIO\t0x00000100\n# define APIC_DELMODE_SMI\t0x00000200\n# define APIC_DELMODE_RR\t0x00000300\n# define APIC_DELMODE_NMI\t0x00000400\n# define APIC_DELMODE_INIT\t0x00000500\n# define APIC_DELMODE_STARTUP\t0x00000600\n# define APIC_DELMODE_RESV\t0x00000700\n\n#define APIC_DESTMODE_MASK\t0x00000800\n# define APIC_DESTMODE_PHY\t0x00000000\n# define APIC_DESTMODE_LOG\t0x00000800\n\n#define APIC_DELSTAT_MASK\t0x00001000\n# define APIC_DELSTAT_IDLE\t0x00000000\n# define APIC_DELSTAT_PEND\t0x00001000\n\n#define APIC_RESV1_MASK\t\t0x00002000\n\n#define APIC_LEVEL_MASK\t\t0x00004000\n# define APIC_LEVEL_DEASSERT\t0x00000000\n# define APIC_LEVEL_ASSERT\t0x00004000\n\n#define APIC_TRIGMOD_MASK\t0x00008000\n# define APIC_TRIGMOD_EDGE\t0x00000000\n# define APIC_TRIGMOD_LEVEL\t0x00008000\n\n#define APIC_RRSTAT_MASK\t0x00030000\n# define APIC_RRSTAT_INVALID\t0x00000000\n# define APIC_RRSTAT_INPROG\t0x00010000\n# define APIC_RRSTAT_VALID\t0x00020000\n# define APIC_RRSTAT_RESV\t0x00030000\n\n#define APIC_DEST_MASK\t\t0x000c0000\n# define APIC_DEST_DESTFLD\t0x00000000\n# define APIC_DEST_SELF\t\t0x00040000\n# define APIC_DEST_ALLISELF\t0x00080000\n# define APIC_DEST_ALLESELF\t0x000c0000\n\n#define APIC_RESV2_MASK\t\t0xfff00000\n\n#define\tAPIC_ICRLO_RESV_MASK\t(APIC_RESV1_MASK | APIC_RESV2_MASK)\n\n/* fields in LVT1/2 */\n#define APIC_LVT_VECTOR\t\t0x000000ff\n#define APIC_LVT_DM\t\t0x00000700\n# define APIC_LVT_DM_FIXED\t0x00000000\n# define APIC_LVT_DM_SMI\t0x00000200\n# define APIC_LVT_DM_NMI\t0x00000400\n# define APIC_LVT_DM_INIT\t0x00000500\n# define APIC_LVT_DM_EXTINT\t0x00000700\n#define APIC_LVT_DS\t\t0x00001000\n#define APIC_LVT_IIPP\t\t0x00002000\n#define APIC_LVT_IIPP_INTALO\t0x00002000\n#define APIC_LVT_IIPP_INTAHI\t0x00000000\n#define APIC_LVT_RIRR\t\t0x00004000\n#define APIC_LVT_TM\t\t0x00008000\n#define APIC_LVT_M\t\t0x00010000\n\n\n/* fields in LVT Timer */\n#define APIC_LVTT_VECTOR\t0x000000ff\n#define APIC_LVTT_DS\t\t0x00001000\n#define APIC_LVTT_M\t\t0x00010000\n#define APIC_LVTT_TM\t\t0x00020000\n# define APIC_LVTT_TM_ONE_SHOT\t0x00000000\n# define APIC_LVTT_TM_PERIODIC\t0x00020000\n\n\n/* APIC timer current count */\n#define\tAPIC_TIMER_MAX_COUNT\t0xffffffff\n\n/* fields in TDCR */\n#define APIC_TDCR_2\t\t0x00\n#define APIC_TDCR_4\t\t0x01\n#define APIC_TDCR_8\t\t0x02\n#define APIC_TDCR_16\t\t0x03\n#define APIC_TDCR_32\t\t0x08\n#define APIC_TDCR_64\t\t0x09\n#define APIC_TDCR_128\t\t0x0a\n#define APIC_TDCR_1\t\t0x0b\n\n/* LVT table indices */\n#define\tAPIC_LVT_LINT0\t\t0\n#define\tAPIC_LVT_LINT1\t\t1\n#define\tAPIC_LVT_TIMER\t\t2\n#define\tAPIC_LVT_ERROR\t\t3\n#define\tAPIC_LVT_PMC\t\t4\n#define\tAPIC_LVT_THERMAL\t5\n#define\tAPIC_LVT_CMCI\t\t6\n#define\tAPIC_LVT_MAX\t\tAPIC_LVT_CMCI\n\n/******************************************************************************\n * I/O APIC defines\n */\n\n/* default physical locations of an IO APIC */\n#define DEFAULT_IO_APIC_BASE\t0xfec00000\n\n/* window register offset */\n#define IOAPIC_WINDOW\t\t0x10\n#define IOAPIC_EOIR\t\t0x40\n\n/* indexes into IO APIC */\n#define IOAPIC_ID\t\t0x00\n#define IOAPIC_VER\t\t0x01\n#define IOAPIC_ARB\t\t0x02\n#define IOAPIC_REDTBL\t\t0x10\n#define IOAPIC_REDTBL0\t\tIOAPIC_REDTBL\n#define IOAPIC_REDTBL1\t\t(IOAPIC_REDTBL+0x02)\n#define IOAPIC_REDTBL2\t\t(IOAPIC_REDTBL+0x04)\n#define IOAPIC_REDTBL3\t\t(IOAPIC_REDTBL+0x06)\n#define IOAPIC_REDTBL4\t\t(IOAPIC_REDTBL+0x08)\n#define IOAPIC_REDTBL5\t\t(IOAPIC_REDTBL+0x0a)\n#define IOAPIC_REDTBL6\t\t(IOAPIC_REDTBL+0x0c)\n#define IOAPIC_REDTBL7\t\t(IOAPIC_REDTBL+0x0e)\n#define IOAPIC_REDTBL8\t\t(IOAPIC_REDTBL+0x10)\n#define IOAPIC_REDTBL9\t\t(IOAPIC_REDTBL+0x12)\n#define IOAPIC_REDTBL10\t\t(IOAPIC_REDTBL+0x14)\n#define IOAPIC_REDTBL11\t\t(IOAPIC_REDTBL+0x16)\n#define IOAPIC_REDTBL12\t\t(IOAPIC_REDTBL+0x18)\n#define IOAPIC_REDTBL13\t\t(IOAPIC_REDTBL+0x1a)\n#define IOAPIC_REDTBL14\t\t(IOAPIC_REDTBL+0x1c)\n#define IOAPIC_REDTBL15\t\t(IOAPIC_REDTBL+0x1e)\n#define IOAPIC_REDTBL16\t\t(IOAPIC_REDTBL+0x20)\n#define IOAPIC_REDTBL17\t\t(IOAPIC_REDTBL+0x22)\n#define IOAPIC_REDTBL18\t\t(IOAPIC_REDTBL+0x24)\n#define IOAPIC_REDTBL19\t\t(IOAPIC_REDTBL+0x26)\n#define IOAPIC_REDTBL20\t\t(IOAPIC_REDTBL+0x28)\n#define IOAPIC_REDTBL21\t\t(IOAPIC_REDTBL+0x2a)\n#define IOAPIC_REDTBL22\t\t(IOAPIC_REDTBL+0x2c)\n#define IOAPIC_REDTBL23\t\t(IOAPIC_REDTBL+0x2e)\n\n/* fields in VER */\n#define IOART_VER_VERSION\t0x000000ff\n#define IOART_VER_MAXREDIR\t0x00ff0000\n#define MAXREDIRSHIFT\t\t16\n\n/*\n * fields in the IO APIC's redirection table entries\n */\n#define IOART_DEST\tAPIC_ID_MASK\t/* broadcast addr: all APICs */\n\n#define IOART_RESV\t0x00fe0000\t/* reserved */\n\n#define IOART_INTMASK\t0x00010000\t/* R/W: INTerrupt mask */\n# define IOART_INTMCLR\t0x00000000\t/*       clear, allow INTs */\n# define IOART_INTMSET\t0x00010000\t/*       set, inhibit INTs */\n\n#define IOART_TRGRMOD\t0x00008000\t/* R/W: trigger mode */\n# define IOART_TRGREDG\t0x00000000\t/*       edge */\n# define IOART_TRGRLVL\t0x00008000\t/*       level */\n\n#define IOART_REM_IRR\t0x00004000\t/* RO: remote IRR */\n\n#define IOART_INTPOL\t0x00002000\t/* R/W: INT input pin polarity */\n# define IOART_INTAHI\t0x00000000\t/*      active high */\n# define IOART_INTALO\t0x00002000\t/*      active low */\n\n#define IOART_DELIVS\t0x00001000\t/* RO: delivery status */\n\n#define IOART_DESTMOD\t0x00000800\t/* R/W: destination mode */\n# define IOART_DESTPHY\t0x00000000\t/*      physical */\n# define IOART_DESTLOG\t0x00000800\t/*      logical */\n\n#define IOART_DELMOD\t0x00000700\t/* R/W: delivery mode */\n# define IOART_DELFIXED\t0x00000000\t/*       fixed */\n# define IOART_DELLOPRI\t0x00000100\t/*       lowest priority */\n# define IOART_DELSMI\t0x00000200\t/*       System Management INT */\n# define IOART_DELRSV1\t0x00000300\t/*       reserved */\n# define IOART_DELNMI\t0x00000400\t/*       NMI signal */\n# define IOART_DELINIT\t0x00000500\t/*       INIT signal */\n# define IOART_DELRSV2\t0x00000600\t/*       reserved */\n# define IOART_DELEXINT\t0x00000700\t/*       External INTerrupt */\n\n#define IOART_INTVEC\t0x000000ff\t/* R/W: INTerrupt vector field */\n"
  },
  {
    "path": "include/xhyve/support/ata.h",
    "content": "/*-\n * Copyright (c) 2000 - 2008 Søren Schmidt <sos@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer,\n *    without modification, immediately at the beginning of the file.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <xhyve/support/misc.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n#pragma clang diagnostic ignored \"-Wpacked\"\n\n/* ATA/ATAPI device parameters */\nstruct ata_params {\n/*000*/ u_int16_t       config;         /* configuration info */\n#define ATA_PROTO_MASK                  0x8003\n#define ATA_PROTO_ATAPI                 0x8000\n#define ATA_PROTO_ATAPI_12              0x8000\n#define ATA_PROTO_ATAPI_16              0x8001\n#define ATA_PROTO_CFA                   0x848a\n#define ATA_ATAPI_TYPE_MASK             0x1f00\n#define ATA_ATAPI_TYPE_DIRECT           0x0000  /* disk/floppy */\n#define ATA_ATAPI_TYPE_TAPE             0x0100  /* streaming tape */\n#define ATA_ATAPI_TYPE_CDROM            0x0500  /* CD-ROM device */\n#define ATA_ATAPI_TYPE_OPTICAL          0x0700  /* optical disk */\n#define ATA_DRQ_MASK                    0x0060\n#define ATA_DRQ_SLOW                    0x0000  /* cpu 3 ms delay */\n#define ATA_DRQ_INTR                    0x0020  /* interrupt 10 ms delay */\n#define ATA_DRQ_FAST                    0x0040  /* accel 50 us delay */\n#define ATA_RESP_INCOMPLETE             0x0004\n\n/*001*/ u_int16_t       cylinders;              /* # of cylinders */\n/*002*/ u_int16_t       specconf;\t\t/* specific configuration */\n/*003*/ u_int16_t       heads;                  /* # heads */\n\tu_int16_t       obsolete4;\n\tu_int16_t       obsolete5;\n/*006*/ u_int16_t       sectors;                /* # sectors/track */\n/*007*/ u_int16_t       vendor7[3];\n/*010*/ u_int8_t        serial[20];             /* serial number */\n/*020*/ u_int16_t       retired20;\n\tu_int16_t       retired21;\n\tu_int16_t       obsolete22;\n/*023*/ u_int8_t        revision[8];            /* firmware revision */\n/*027*/ u_int8_t        model[40];              /* model name */\n/*047*/ u_int16_t       sectors_intr;           /* sectors per interrupt */\n/*048*/ u_int16_t       usedmovsd;              /* double word read/write? */\n/*049*/ u_int16_t       capabilities1;\n#define ATA_SUPPORT_DMA                 0x0100\n#define ATA_SUPPORT_LBA                 0x0200\n#define ATA_SUPPORT_IORDY               0x0400\n#define ATA_SUPPORT_IORDYDIS            0x0800\n#define ATA_SUPPORT_OVERLAP             0x4000\n\n/*050*/ u_int16_t       capabilities2;\n/*051*/ u_int16_t       retired_piomode;        /* PIO modes 0-2 */\n#define ATA_RETIRED_PIO_MASK            0x0300\n\n/*052*/ u_int16_t       retired_dmamode;        /* DMA modes */\n#define ATA_RETIRED_DMA_MASK            0x0003\n\n/*053*/ u_int16_t       atavalid;               /* fields valid */\n#define ATA_FLAG_54_58                  0x0001  /* words 54-58 valid */\n#define ATA_FLAG_64_70                  0x0002  /* words 64-70 valid */\n#define ATA_FLAG_88                     0x0004  /* word 88 valid */\n\n/*054*/ u_int16_t       current_cylinders;\n/*055*/ u_int16_t       current_heads;\n/*056*/ u_int16_t       current_sectors;\n/*057*/ u_int16_t       current_size_1;\n/*058*/ u_int16_t       current_size_2;\n/*059*/ u_int16_t       multi;\n#define ATA_MULTI_VALID                 0x0100\n\n/*060*/ u_int16_t       lba_size_1;\n\tu_int16_t       lba_size_2;\n\tu_int16_t       obsolete62;\n/*063*/ u_int16_t       mwdmamodes;             /* multiword DMA modes */\n/*064*/ u_int16_t       apiomodes;              /* advanced PIO modes */\n\n/*065*/ u_int16_t       mwdmamin;               /* min. M/W DMA time/word ns */\n/*066*/ u_int16_t       mwdmarec;               /* rec. M/W DMA time ns */\n/*067*/ u_int16_t       pioblind;               /* min. PIO cycle w/o flow */\n/*068*/ u_int16_t       pioiordy;               /* min. PIO cycle IORDY flow */\n/*069*/ u_int16_t       support3;\n#define ATA_SUPPORT_RZAT                0x0020\n#define ATA_SUPPORT_DRAT                0x4000\n\tu_int16_t       reserved70;\n/*071*/ u_int16_t       rlsovlap;               /* rel time (us) for overlap */\n/*072*/ u_int16_t       rlsservice;             /* rel time (us) for service */\n\tu_int16_t       reserved73;\n\tu_int16_t       reserved74;\n/*075*/ u_int16_t       queue;\n#define ATA_QUEUE_LEN(x)                ((x) & 0x001f)\n\n/*76*/  u_int16_t       satacapabilities;\n#define ATA_SATA_GEN1                   0x0002\n#define ATA_SATA_GEN2                   0x0004\n#define ATA_SATA_GEN3                   0x0008\n#define ATA_SUPPORT_NCQ                 0x0100\n#define ATA_SUPPORT_IFPWRMNGTRCV        0x0200\n#define ATA_SUPPORT_PHYEVENTCNT         0x0400\n#define ATA_SUPPORT_NCQ_UNLOAD          0x0800\n#define ATA_SUPPORT_NCQ_PRIO            0x1000\n#define ATA_SUPPORT_HAPST               0x2000\n#define ATA_SUPPORT_DAPST               0x4000\n#define ATA_SUPPORT_READLOGDMAEXT       0x8000\n\n/*77*/  u_int16_t       satacapabilities2;\n#define ATA_SATA_CURR_GEN_MASK          0x0006\n#define ATA_SUPPORT_NCQ_STREAM          0x0010\n#define ATA_SUPPORT_NCQ_QMANAGEMENT     0x0020\n#define ATA_SUPPORT_RCVSND_FPDMA_QUEUED 0x0040\n/*78*/  u_int16_t       satasupport;\n#define ATA_SUPPORT_NONZERO             0x0002\n#define ATA_SUPPORT_AUTOACTIVATE        0x0004\n#define ATA_SUPPORT_IFPWRMNGT           0x0008\n#define ATA_SUPPORT_INORDERDATA         0x0010\n#define ATA_SUPPORT_ASYNCNOTIF          0x0020\n#define ATA_SUPPORT_SOFTSETPRESERVE     0x0040\n/*79*/  u_int16_t       sataenabled;\n#define ATA_ENABLED_DAPST               0x0080\n\n/*080*/ u_int16_t       version_major;\n/*081*/ u_int16_t       version_minor;\n\n\tstruct {\n/*082/085*/ u_int16_t   command1;\n#define ATA_SUPPORT_SMART               0x0001\n#define ATA_SUPPORT_SECURITY            0x0002\n#define ATA_SUPPORT_REMOVABLE           0x0004\n#define ATA_SUPPORT_POWERMGT            0x0008\n#define ATA_SUPPORT_PACKET              0x0010\n#define ATA_SUPPORT_WRITECACHE          0x0020\n#define ATA_SUPPORT_LOOKAHEAD           0x0040\n#define ATA_SUPPORT_RELEASEIRQ          0x0080\n#define ATA_SUPPORT_SERVICEIRQ          0x0100\n#define ATA_SUPPORT_RESET               0x0200\n#define ATA_SUPPORT_PROTECTED           0x0400\n#define ATA_SUPPORT_WRITEBUFFER         0x1000\n#define ATA_SUPPORT_READBUFFER          0x2000\n#define ATA_SUPPORT_NOP                 0x4000\n\n/*083/086*/ u_int16_t   command2;\n#define ATA_SUPPORT_MICROCODE           0x0001\n#define ATA_SUPPORT_QUEUED              0x0002\n#define ATA_SUPPORT_CFA                 0x0004\n#define ATA_SUPPORT_APM                 0x0008\n#define ATA_SUPPORT_NOTIFY              0x0010\n#define ATA_SUPPORT_STANDBY             0x0020\n#define ATA_SUPPORT_SPINUP              0x0040\n#define ATA_SUPPORT_MAXSECURITY         0x0100\n#define ATA_SUPPORT_AUTOACOUSTIC        0x0200\n#define ATA_SUPPORT_ADDRESS48           0x0400\n#define ATA_SUPPORT_OVERLAY             0x0800\n#define ATA_SUPPORT_FLUSHCACHE          0x1000\n#define ATA_SUPPORT_FLUSHCACHE48        0x2000\n\n/*084/087*/ u_int16_t   extension;\n#define ATA_SUPPORT_SMARTLOG\t\t0x0001\n#define ATA_SUPPORT_SMARTTEST\t\t0x0002\n#define ATA_SUPPORT_MEDIASN\t\t0x0004\n#define ATA_SUPPORT_MEDIAPASS\t\t0x0008\n#define ATA_SUPPORT_STREAMING\t\t0x0010\n#define ATA_SUPPORT_GENLOG\t\t0x0020\n#define ATA_SUPPORT_WRITEDMAFUAEXT\t0x0040\n#define ATA_SUPPORT_WRITEDMAQFUAEXT\t0x0080\n#define ATA_SUPPORT_64BITWWN\t\t0x0100\n#define ATA_SUPPORT_UNLOAD\t\t0x2000\n\t} __packed support, enabled;\n\n/*088*/ u_int16_t       udmamodes;              /* UltraDMA modes */\n/*089*/ u_int16_t       erase_time;             /* time req'd in 2min units */\n/*090*/ u_int16_t       enhanced_erase_time;    /* time req'd in 2min units */\n/*091*/ u_int16_t       apm_value;\n/*092*/ u_int16_t       master_passwd_revision; /* password revision code */\n/*093*/ u_int16_t       hwres;\n#define ATA_CABLE_ID                    0x2000\n\n/*094*/ u_int16_t       acoustic;\n#define ATA_ACOUSTIC_CURRENT(x)         ((x) & 0x00ff)\n#define ATA_ACOUSTIC_VENDOR(x)          (((x) & 0xff00) >> 8)\n\n/*095*/ u_int16_t       stream_min_req_size;\n/*096*/ u_int16_t       stream_transfer_time;\n/*097*/ u_int16_t       stream_access_latency;\n/*098*/ u_int32_t       stream_granularity;\n/*100*/ u_int16_t       lba_size48_1;\n\tu_int16_t       lba_size48_2;\n\tu_int16_t       lba_size48_3;\n\tu_int16_t       lba_size48_4;\n\tu_int16_t       reserved104;\n/*105*/\tu_int16_t       max_dsm_blocks;\n/*106*/\tu_int16_t       pss;\n#define ATA_PSS_LSPPS\t\t\t0x000F\n#define ATA_PSS_LSSABOVE512\t\t0x1000\n#define ATA_PSS_MULTLS\t\t\t0x2000\n#define ATA_PSS_VALID_MASK\t\t0xC000\n#define ATA_PSS_VALID_VALUE\t\t0x4000\n/*107*/ u_int16_t       isd;\n/*108*/ u_int16_t       wwn[4];\n\tu_int16_t       reserved112[5];\n/*117*/ u_int16_t       lss_1;\n/*118*/ u_int16_t       lss_2;\n/*119*/ u_int16_t       support2;\n#define ATA_SUPPORT_WRITEREADVERIFY\t0x0002\n#define ATA_SUPPORT_WRITEUNCORREXT\t0x0004\n#define ATA_SUPPORT_RWLOGDMAEXT\t\t0x0008\n#define ATA_SUPPORT_MICROCODE3\t\t0x0010\n#define ATA_SUPPORT_FREEFALL\t\t0x0020\n/*120*/ u_int16_t       enabled2;\n\tu_int16_t       reserved121[6];\n/*127*/ u_int16_t       removable_status;\n/*128*/ u_int16_t       security_status;\n#define ATA_SECURITY_LEVEL\t\t0x0100\t/* 0: high, 1: maximum */\n#define ATA_SECURITY_ENH_SUPP\t\t0x0020\t/* enhanced erase supported */\n#define ATA_SECURITY_COUNT_EXP\t\t0x0010\t/* count expired */\n#define ATA_SECURITY_FROZEN\t\t0x0008\t/* security config is frozen */\n#define ATA_SECURITY_LOCKED\t\t0x0004\t/* drive is locked */\n#define ATA_SECURITY_ENABLED\t\t0x0002\t/* ATA Security is enabled */\n#define ATA_SECURITY_SUPPORTED\t\t0x0001\t/* ATA Security is supported */\n\n\tu_int16_t       reserved129[31];\n/*160*/ u_int16_t       cfa_powermode1;\n\tu_int16_t       reserved161;\n/*162*/ u_int16_t       cfa_kms_support;\n/*163*/ u_int16_t       cfa_trueide_modes;\n/*164*/ u_int16_t       cfa_memory_modes;\n\tu_int16_t       reserved165[4];\n/*169*/\tu_int16_t       support_dsm;\n#define ATA_SUPPORT_DSM_TRIM\t\t0x0001\n\tu_int16_t       reserved170[6];\n/*176*/ u_int8_t        media_serial[60];\n/*206*/ u_int16_t       sct;\n\tu_int16_t       reserved206[2];\n/*209*/ u_int16_t       lsalign;\n/*210*/ u_int16_t       wrv_sectors_m3_1;\n\tu_int16_t       wrv_sectors_m3_2;\n/*212*/ u_int16_t       wrv_sectors_m2_1;\n\tu_int16_t       wrv_sectors_m2_2;\n/*214*/ u_int16_t       nv_cache_caps;\n/*215*/ u_int16_t       nv_cache_size_1;\n\tu_int16_t       nv_cache_size_2;\n/*217*/ u_int16_t       media_rotation_rate;\n#define ATA_RATE_NOT_REPORTED\t\t0x0000\n#define ATA_RATE_NON_ROTATING\t\t0x0001\n\tu_int16_t       reserved218;\n/*219*/ u_int16_t       nv_cache_opt;\n/*220*/ u_int16_t       wrv_mode;\n\tu_int16_t       reserved221;\n/*222*/ u_int16_t       transport_major;\n/*223*/ u_int16_t       transport_minor;\n\tu_int16_t       reserved224[31];\n/*255*/ u_int16_t       integrity;\n} __packed;\n\n/* ATA Dataset Management */\n#define ATA_DSM_BLK_SIZE\t512\n#define ATA_DSM_BLK_RANGES\t64\n#define ATA_DSM_RANGE_SIZE\t8\n#define ATA_DSM_RANGE_MAX\t65535\n\n/*\n * ATA Device Register\n *\n * bit 7 Obsolete (was 1 in early ATA specs)\n * bit 6 Sets LBA/CHS mode. 1=LBA, 0=CHS \n * bit 5 Obsolete (was 1 in early ATA specs)\n * bit 4 1 = Slave Drive, 0 = Master Drive\n * bit 3-0 In LBA mode, 27-24 of address. In CHS mode, head number\n*/\n\n#define ATA_DEV_MASTER\t\t0x00\n#define ATA_DEV_SLAVE\t\t0x10\n#define ATA_DEV_LBA\t\t0x40\n\n/* ATA limits */\n#define ATA_MAX_28BIT_LBA\t268435455UL\n\n/* ATA Status Register */\n#define ATA_STATUS_ERROR\t0x01\n#define ATA_STATUS_DEVICE_FAULT\t0x20\n\n/* ATA Error Register */\n#define ATA_ERROR_ABORT\t\t0x04\n#define ATA_ERROR_ID_NOT_FOUND\t0x10\n\n/* ATA HPA Features */\n#define ATA_HPA_FEAT_MAX_ADDR\t0x00\n#define ATA_HPA_FEAT_SET_PWD\t0x01\n#define ATA_HPA_FEAT_LOCK\t0x02\n#define ATA_HPA_FEAT_UNLOCK\t0x03\n#define ATA_HPA_FEAT_FREEZE\t0x04\n\n/* ATA transfer modes */\n#define ATA_MODE_MASK           0x0f\n#define ATA_DMA_MASK            0xf0\n#define ATA_PIO                 0x00\n#define ATA_PIO0                0x08\n#define ATA_PIO1                0x09\n#define ATA_PIO2                0x0a\n#define ATA_PIO3                0x0b\n#define ATA_PIO4                0x0c\n#define ATA_PIO_MAX             0x0f\n#define ATA_DMA                 0x10\n#define ATA_WDMA0               0x20\n#define ATA_WDMA1               0x21\n#define ATA_WDMA2               0x22\n#define ATA_UDMA0               0x40\n#define ATA_UDMA1               0x41\n#define ATA_UDMA2               0x42\n#define ATA_UDMA3               0x43\n#define ATA_UDMA4               0x44\n#define ATA_UDMA5               0x45\n#define ATA_UDMA6               0x46\n#define ATA_SA150               0x47\n#define ATA_SA300               0x48\n#define ATA_DMA_MAX             0x4f\n\n\n/* ATA commands */\n#define ATA_NOP                         0x00    /* NOP */\n#define         ATA_NF_FLUSHQUEUE       0x00    /* flush queued cmd's */\n#define         ATA_NF_AUTOPOLL         0x01    /* start autopoll function */\n#define ATA_DATA_SET_MANAGEMENT\t\t0x06\n#define \tATA_DSM_TRIM\t\t0x01\n#define ATA_DEVICE_RESET                0x08    /* reset device */\n#define ATA_READ                        0x20    /* read */\n#define ATA_READ48                      0x24    /* read 48bit LBA */\n#define ATA_READ_DMA48                  0x25    /* read DMA 48bit LBA */\n#define ATA_READ_DMA_QUEUED48           0x26    /* read DMA QUEUED 48bit LBA */\n#define ATA_READ_NATIVE_MAX_ADDRESS48   0x27    /* read native max addr 48bit */\n#define ATA_READ_MUL48                  0x29    /* read multi 48bit LBA */\n#define ATA_READ_STREAM_DMA48           0x2a    /* read DMA stream 48bit LBA */\n#define ATA_READ_LOG_EXT                0x2f    /* read log ext - PIO Data-In */\n#define ATA_READ_STREAM48               0x2b    /* read stream 48bit LBA */\n#define ATA_WRITE                       0x30    /* write */\n#define ATA_WRITE48                     0x34    /* write 48bit LBA */\n#define ATA_WRITE_DMA48                 0x35    /* write DMA 48bit LBA */\n#define ATA_WRITE_DMA_QUEUED48          0x36    /* write DMA QUEUED 48bit LBA*/\n#define ATA_SET_MAX_ADDRESS48           0x37    /* set max address 48bit */\n#define ATA_WRITE_MUL48                 0x39    /* write multi 48bit LBA */\n#define ATA_WRITE_STREAM_DMA48          0x3a\n#define ATA_WRITE_STREAM48              0x3b\n#define ATA_WRITE_DMA_FUA48             0x3d\n#define ATA_WRITE_DMA_QUEUED_FUA48      0x3e\n#define ATA_WRITE_LOG_EXT               0x3f\n#define ATA_READ_VERIFY                 0x40\n#define ATA_READ_VERIFY48               0x42\n#define ATA_READ_LOG_DMA_EXT            0x47    /* read log DMA ext - PIO Data-In */\n#define ATA_READ_FPDMA_QUEUED           0x60    /* read DMA NCQ */\n#define ATA_WRITE_FPDMA_QUEUED          0x61    /* write DMA NCQ */\n#define ATA_NCQ_NON_DATA\t\t0x63\t/* NCQ non-data command */\n#define ATA_SEND_FPDMA_QUEUED           0x64    /* send DMA NCQ */\n#define\t\tATA_SFPDMA_DSM\t\t0x00\t/* Data set management */\n#define\t\t\tATA_SFPDMA_DSM_TRIM\t0x01\t/* Set trim bit in auxilary */\n#define\t\tATA_SFPDMA_HYBRID_EVICT\t0x01\t/* Hybrid Evict */\n#define\t\tATA_SFPDMA_WLDMA\t0x02\t/* Write Log DMA EXT */\n#define ATA_RECV_FPDMA_QUEUED           0x65    /* recieve DMA NCQ */\n#define ATA_SEP_ATTN                    0x67    /* SEP request */\n#define ATA_SEEK                        0x70    /* seek */\n#define ATA_PACKET_CMD                  0xa0    /* packet command */\n#define ATA_ATAPI_IDENTIFY              0xa1    /* get ATAPI params*/\n#define ATA_SERVICE                     0xa2    /* service command */\n#define ATA_SMART_CMD                   0xb0    /* SMART command */\n#define ATA_CFA_ERASE                   0xc0    /* CFA erase */\n#define ATA_READ_MUL                    0xc4    /* read multi */\n#define ATA_WRITE_MUL                   0xc5    /* write multi */\n#define ATA_SET_MULTI                   0xc6    /* set multi size */\n#define ATA_READ_DMA_QUEUED             0xc7    /* read DMA QUEUED */\n#define ATA_READ_DMA                    0xc8    /* read DMA */\n#define ATA_WRITE_DMA                   0xca    /* write DMA */\n#define ATA_WRITE_DMA_QUEUED            0xcc    /* write DMA QUEUED */\n#define ATA_WRITE_MUL_FUA48             0xce\n#define ATA_STANDBY_IMMEDIATE           0xe0    /* standby immediate */\n#define ATA_IDLE_IMMEDIATE              0xe1    /* idle immediate */\n#define ATA_STANDBY_CMD                 0xe2    /* standby */\n#define ATA_IDLE_CMD                    0xe3    /* idle */\n#define ATA_READ_BUFFER                 0xe4    /* read buffer */\n#define ATA_READ_PM                     0xe4    /* read portmultiplier */\n#define ATA_SLEEP                       0xe6    /* sleep */\n#define ATA_FLUSHCACHE                  0xe7    /* flush cache to disk */\n#define ATA_WRITE_PM                    0xe8    /* write portmultiplier */\n#define ATA_FLUSHCACHE48                0xea    /* flush cache to disk */\n#define ATA_ATA_IDENTIFY                0xec    /* get ATA params */\n#define ATA_SETFEATURES                 0xef    /* features command */\n#define         ATA_SF_SETXFER          0x03    /* set transfer mode */\n#define         ATA_SF_ENAB_WCACHE      0x02    /* enable write cache */\n#define         ATA_SF_DIS_WCACHE       0x82    /* disable write cache */\n#define         ATA_SF_ENAB_PUIS        0x06    /* enable PUIS */\n#define         ATA_SF_DIS_PUIS         0x86    /* disable PUIS */\n#define         ATA_SF_PUIS_SPINUP      0x07    /* PUIS spin-up */\n#define         ATA_SF_ENAB_RCACHE      0xaa    /* enable readahead cache */\n#define         ATA_SF_DIS_RCACHE       0x55    /* disable readahead cache */\n#define         ATA_SF_ENAB_RELIRQ      0x5d    /* enable release interrupt */\n#define         ATA_SF_DIS_RELIRQ       0xdd    /* disable release interrupt */\n#define         ATA_SF_ENAB_SRVIRQ      0x5e    /* enable service interrupt */\n#define         ATA_SF_DIS_SRVIRQ       0xde    /* disable service interrupt */\n#define ATA_SECURITY_SET_PASSWORD       0xf1    /* set drive password */\n#define ATA_SECURITY_UNLOCK             0xf2    /* unlock drive using passwd */\n#define ATA_SECURITY_ERASE_PREPARE      0xf3    /* prepare to erase drive */\n#define ATA_SECURITY_ERASE_UNIT         0xf4    /* erase all blocks on drive */\n#define ATA_SECURITY_FREEZE_LOCK        0xf5    /* freeze security config */\n#define ATA_SECURITY_DISABLE_PASSWORD   0xf6    /* disable drive password */\n#define ATA_READ_NATIVE_MAX_ADDRESS     0xf8    /* read native max address */\n#define ATA_SET_MAX_ADDRESS             0xf9    /* set max address */\n\n\n/* ATAPI commands */\n#define ATAPI_TEST_UNIT_READY           0x00    /* check if device is ready */\n#define ATAPI_REZERO                    0x01    /* rewind */\n#define ATAPI_REQUEST_SENSE             0x03    /* get sense data */\n#define ATAPI_FORMAT                    0x04    /* format unit */\n#define ATAPI_READ                      0x08    /* read data */\n#define ATAPI_WRITE                     0x0a    /* write data */\n#define ATAPI_WEOF                      0x10    /* write filemark */\n#define         ATAPI_WF_WRITE          0x01\n#define ATAPI_SPACE                     0x11    /* space command */\n#define         ATAPI_SP_FM             0x01\n#define         ATAPI_SP_EOD            0x03\n#define ATAPI_INQUIRY\t\t\t0x12\t/* get inquiry data */\n#define ATAPI_MODE_SELECT               0x15    /* mode select */\n#define ATAPI_ERASE                     0x19    /* erase */\n#define ATAPI_MODE_SENSE                0x1a    /* mode sense */\n#define ATAPI_START_STOP                0x1b    /* start/stop unit */\n#define         ATAPI_SS_LOAD           0x01\n#define         ATAPI_SS_RETENSION      0x02\n#define         ATAPI_SS_EJECT          0x04\n#define ATAPI_PREVENT_ALLOW             0x1e    /* media removal */\n#define ATAPI_READ_FORMAT_CAPACITIES    0x23    /* get format capacities */\n#define ATAPI_READ_CAPACITY             0x25    /* get volume capacity */\n#define ATAPI_READ_BIG                  0x28    /* read data */\n#define ATAPI_WRITE_BIG                 0x2a    /* write data */\n#define ATAPI_LOCATE                    0x2b    /* locate to position */\n#define ATAPI_READ_POSITION             0x34    /* read position */\n#define ATAPI_SYNCHRONIZE_CACHE         0x35    /* flush buf, close channel */\n#define ATAPI_WRITE_BUFFER              0x3b    /* write device buffer */\n#define ATAPI_READ_BUFFER               0x3c    /* read device buffer */\n#define ATAPI_READ_SUBCHANNEL           0x42    /* get subchannel info */\n#define ATAPI_READ_TOC                  0x43    /* get table of contents */\n#define ATAPI_PLAY_10                   0x45    /* play by lba */\n#define ATAPI_PLAY_MSF                  0x47    /* play by MSF address */\n#define ATAPI_PLAY_TRACK                0x48    /* play by track number */\n#define ATAPI_PAUSE                     0x4b    /* pause audio operation */\n#define ATAPI_READ_DISK_INFO            0x51    /* get disk info structure */\n#define ATAPI_READ_TRACK_INFO           0x52    /* get track info structure */\n#define ATAPI_RESERVE_TRACK             0x53    /* reserve track */\n#define ATAPI_SEND_OPC_INFO             0x54    /* send OPC structurek */\n#define ATAPI_MODE_SELECT_BIG           0x55    /* set device parameters */\n#define ATAPI_REPAIR_TRACK              0x58    /* repair track */\n#define ATAPI_READ_MASTER_CUE           0x59    /* read master CUE info */\n#define ATAPI_MODE_SENSE_BIG            0x5a    /* get device parameters */\n#define ATAPI_CLOSE_TRACK               0x5b    /* close track/session */\n#define ATAPI_READ_BUFFER_CAPACITY      0x5c    /* get buffer capicity */\n#define ATAPI_SEND_CUE_SHEET            0x5d    /* send CUE sheet */\n#define ATAPI_SERVICE_ACTION_IN         0x96\t/* get service data */\n#define ATAPI_BLANK                     0xa1    /* blank the media */\n#define ATAPI_SEND_KEY                  0xa3    /* send DVD key structure */\n#define ATAPI_REPORT_KEY                0xa4    /* get DVD key structure */\n#define ATAPI_PLAY_12                   0xa5    /* play by lba */\n#define ATAPI_LOAD_UNLOAD               0xa6    /* changer control command */\n#define ATAPI_READ_STRUCTURE            0xad    /* get DVD structure */\n#define ATAPI_PLAY_CD                   0xb4    /* universal play command */\n#define ATAPI_SET_SPEED                 0xbb    /* set drive speed */\n#define ATAPI_MECH_STATUS               0xbd    /* get changer status */\n#define ATAPI_READ_CD                   0xbe    /* read data */\n#define ATAPI_POLL_DSC                  0xff    /* poll DSC status bit */\n\n\nstruct ata_ioc_devices {\n    int                 channel;\n    char                name[2][32];\n    struct ata_params   params[2];\n};\n\n/* pr channel ATA ioctl calls */\n#define IOCATAGMAXCHANNEL       _IOR('a',  1, int)\n#define IOCATAREINIT            _IOW('a',  2, int)\n#define IOCATAATTACH            _IOW('a',  3, int)\n#define IOCATADETACH            _IOW('a',  4, int)\n#define IOCATADEVICES           _IOWR('a',  5, struct ata_ioc_devices)\n\n/* ATAPI request sense structure */\nstruct atapi_sense {\n    u_int8_t\terror;\t\t\t\t/* current or deferred errors */\n#define\tATA_SENSE_VALID\t\t\t0x80\n\n    u_int8_t\tsegment;\t\t\t/* segment number */\n    u_int8_t\tkey;\t\t\t\t/* sense key */\n#define ATA_SENSE_KEY_MASK\t\t0x0f    /* sense key mask */\n#define ATA_SENSE_NO_SENSE\t\t0x00    /* no specific sense key info */\n#define ATA_SENSE_RECOVERED_ERROR \t0x01    /* command OK, data recovered */\n#define ATA_SENSE_NOT_READY\t\t0x02    /* no access to drive */\n#define ATA_SENSE_MEDIUM_ERROR\t\t0x03    /* non-recovered data error */\n#define ATA_SENSE_HARDWARE_ERROR\t0x04    /* non-recoverable HW failure */\n#define ATA_SENSE_ILLEGAL_REQUEST\t0x05    /* invalid command param(s) */\n#define ATA_SENSE_UNIT_ATTENTION\t0x06    /* media changed */\n#define ATA_SENSE_DATA_PROTECT\t\t0x07    /* write protect */\n#define ATA_SENSE_BLANK_CHECK\t\t0x08    /* blank check */\n#define ATA_SENSE_VENDOR_SPECIFIC\t0x09    /* vendor specific skey */\n#define ATA_SENSE_COPY_ABORTED\t\t0x0a    /* copy aborted */\n#define ATA_SENSE_ABORTED_COMMAND\t0x0b    /* command aborted, try again */\n#define ATA_SENSE_EQUAL\t\t\t0x0c    /* equal */\n#define ATA_SENSE_VOLUME_OVERFLOW\t0x0d    /* volume overflow */\n#define ATA_SENSE_MISCOMPARE\t\t0x0e    /* data dont match the medium */\n#define ATA_SENSE_RESERVED\t\t0x0f\n#define\tATA_SENSE_ILI\t\t\t0x20;\n#define\tATA_SENSE_EOM\t\t\t0x40;\n#define\tATA_SENSE_FILEMARK\t\t0x80;\n\n    u_int32_t   cmd_info;\t\t/* cmd information */\n    u_int8_t\tsense_length;\t\t/* additional sense len (n-7) */\n    u_int32_t   cmd_specific_info;\t/* additional cmd spec info */\n    u_int8_t    asc;\t\t\t/* additional sense code */\n    u_int8_t    ascq;\t\t\t/* additional sense code qual */\n    u_int8_t    replaceable_unit_code;\t/* replaceable unit code */\n    u_int8_t\tspecific;\t\t/* sense key specific */\n#define\tATA_SENSE_SPEC_VALID\t0x80\n#define\tATA_SENSE_SPEC_MASK\t0x7f\n\t\n    u_int8_t\tspecific1;\t\t/* sense key specific */\n    u_int8_t\tspecific2;\t\t/* sense key specific */\n} __packed;\n\nstruct ata_ioc_request {\n    union {\n\tstruct {\n\t    u_int8_t            command;\n\t    u_int8_t            feature;\n\t    u_int64_t           lba;\n\t    u_int16_t           count;\n\t} ata;\n\tstruct {\n\t    char                ccb[16];\n\t    struct atapi_sense\tsense;\n\t} atapi;\n    } u;\n    caddr_t             data;\n    int                 count;\n    int                 flags;\n#define ATA_CMD_CONTROL                 0x01\n#define ATA_CMD_READ                    0x02\n#define ATA_CMD_WRITE                   0x04\n#define ATA_CMD_ATAPI                   0x08\n\n    int                 timeout;\n    int                 error;\n};\n\nstruct ata_security_password {\n\tu_int16_t\t\tctrl;\n#define ATA_SECURITY_PASSWORD_USER\t0x0000\n#define ATA_SECURITY_PASSWORD_MASTER\t0x0001\n#define ATA_SECURITY_ERASE_NORMAL\t0x0000\n#define ATA_SECURITY_ERASE_ENHANCED\t0x0002\n#define ATA_SECURITY_LEVEL_HIGH\t\t0x0000\n#define ATA_SECURITY_LEVEL_MAXIMUM\t0x0100\n\n\tu_int8_t\t\tpassword[32];\n\tu_int16_t\t\trevision;\n\tu_int16_t\t\treserved[238];\n};\n\n/* pr device ATA ioctl calls */\n#define IOCATAREQUEST           _IOWR('a', 100, struct ata_ioc_request)\n#define IOCATAGPARM             _IOR('a', 101, struct ata_params)\n#define IOCATAGMODE             _IOR('a', 102, int)\n#define IOCATASMODE             _IOW('a', 103, int)\n\n#define IOCATAGSPINDOWN\t\t_IOR('a', 104, int)\n#define IOCATASSPINDOWN\t\t_IOW('a', 105, int)\n\n\nstruct ata_ioc_raid_config {\n\t    int                 lun;\n\t    int                 type;\n#define AR_JBOD                         0x0001\n#define AR_SPAN                         0x0002\n#define AR_RAID0                        0x0004\n#define AR_RAID1                        0x0008\n#define AR_RAID01                       0x0010\n#define AR_RAID3                        0x0020\n#define AR_RAID4                        0x0040\n#define AR_RAID5                        0x0080\n\n\t    int                 interleave;\n\t    int                 status;\n#define AR_READY                        1\n#define AR_DEGRADED                     2\n#define AR_REBUILDING                   4\n\n\t    int                 progress;\n\t    int                 total_disks;\n\t    int                 disks[16];\n};\n\nstruct ata_ioc_raid_status {\n\t    int                 lun;\n\t    int                 type;\n\t    int                 interleave;\n\t    int                 status;\n\t    int                 progress;\n\t    int                 total_disks;\n\t    struct {\n\t\t    int\t\tstate;\n#define AR_DISK_ONLINE\t\t\t0x01\n#define AR_DISK_PRESENT\t\t\t0x02\n#define AR_DISK_SPARE\t\t\t0x04\n\t\t    int\t\tlun;\n\t    } disks[16];\n};\n\n/* ATA RAID ioctl calls */\n#define IOCATARAIDCREATE        _IOWR('a', 200, struct ata_ioc_raid_config)\n#define IOCATARAIDDELETE        _IOW('a', 201, int)\n#define IOCATARAIDSTATUS        _IOWR('a', 202, struct ata_ioc_raid_status)\n#define IOCATARAIDADDSPARE      _IOW('a', 203, struct ata_ioc_raid_config)\n#define IOCATARAIDREBUILD       _IOW('a', 204, int)\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "include/xhyve/support/atomic.h",
    "content": "/*-\n * Copyright (c) 1998 Doug Rabson\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/misc.h>\n\n#define\t__compiler_membar()\t__asm __volatile(\" \" : : : \"memory\")\n\n#define\tmb()\t__asm __volatile(\"mfence;\" : : : \"memory\")\n#define\twmb()\t__asm __volatile(\"sfence;\" : : : \"memory\")\n#define\trmb()\t__asm __volatile(\"lfence;\" : : : \"memory\")\n\n/*\n * Various simple operations on memory, each of which is atomic in the\n * presence of interrupts and multiple processors.\n *\n * atomic_set_char(P, V)\t(*(u_char *)(P) |= (V))\n * atomic_clear_char(P, V)\t(*(u_char *)(P) &= ~(V))\n * atomic_add_char(P, V)\t(*(u_char *)(P) += (V))\n * atomic_subtract_char(P, V)\t(*(u_char *)(P) -= (V))\n *\n * atomic_set_short(P, V)\t(*(u_short *)(P) |= (V))\n * atomic_clear_short(P, V)\t(*(u_short *)(P) &= ~(V))\n * atomic_add_short(P, V)\t(*(u_short *)(P) += (V))\n * atomic_subtract_short(P, V)\t(*(u_short *)(P) -= (V))\n *\n * atomic_set_int(P, V)\t\t(*(u_int *)(P) |= (V))\n * atomic_clear_int(P, V)\t(*(u_int *)(P) &= ~(V))\n * atomic_add_int(P, V)\t\t(*(u_int *)(P) += (V))\n * atomic_subtract_int(P, V)\t(*(u_int *)(P) -= (V))\n * atomic_swap_int(P, V)\t(return (*(u_int *)(P)); *(u_int *)(P) = (V);)\n * atomic_readandclear_int(P)\t(return (*(u_int *)(P)); *(u_int *)(P) = 0;)\n *\n * atomic_set_long(P, V)\t(*(u_long *)(P) |= (V))\n * atomic_clear_long(P, V)\t(*(u_long *)(P) &= ~(V))\n * atomic_add_long(P, V)\t(*(u_long *)(P) += (V))\n * atomic_subtract_long(P, V)\t(*(u_long *)(P) -= (V))\n * atomic_swap_long(P, V)\t(return (*(u_long *)(P)); *(u_long *)(P) = (V);)\n * atomic_readandclear_long(P)\t(return (*(u_long *)(P)); *(u_long *)(P) = 0;)\n */\n\n#define\tMPLOCKED\t\"lock ; \"\n\n/*\n * The assembly is volatilized to avoid code chunk removal by the compiler.\n * GCC aggressively reorders operations and memory clobbering is necessary\n * in order to avoid that for memory barriers.\n */\n#define\tATOMIC_ASM(NAME, TYPE, OP, CONS, V)\t\t\\\nstatic __inline void\t\t\t\t\t\\\natomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\\\n{\t\t\t\t\t\t\t\\\n\t__asm __volatile(MPLOCKED OP\t\t\t\\\n\t: \"+m\" (*p)\t\t\t\t\t\\\n\t: CONS (V)\t\t\t\t\t\\\n\t: \"cc\");\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\\\nstatic __inline void\t\t\t\t\t\\\natomic_##NAME##_barr_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\\\n{\t\t\t\t\t\t\t\\\n\t__asm __volatile(MPLOCKED OP\t\t\t\\\n\t: \"+m\" (*p)\t\t\t\t\t\\\n\t: CONS (V)\t\t\t\t\t\\\n\t: \"memory\", \"cc\");\t\t\t\t\\\n}\t\t\t\t\t\t\t\\\nstruct __hack\n\n/*\n * Atomic compare and set, used by the mutex functions\n *\n * if (*dst == expect) *dst = src (all 32 bit words)\n *\n * Returns 0 on failure, non-zero on success\n */\n\nstatic __inline int\natomic_cmpset_int(volatile u_int *dst, u_int expect, u_int src)\n{\n\tu_char res;\n\n\t__asm __volatile(\n\t\"\t\" MPLOCKED \"\t\t\"\n\t\"\tcmpxchgl %3,%1 ;\t\"\n\t\"       sete\t%0 ;\t\t\"\n\t\"# atomic_cmpset_int\"\n\t: \"=q\" (res),\t\t\t/* 0 */\n\t  \"+m\" (*dst),\t\t\t/* 1 */\n\t  \"+a\" (expect)\t\t\t/* 2 */\n\t: \"r\" (src)\t\t\t/* 3 */\n\t: \"memory\", \"cc\");\n\treturn (res);\n}\n\nstatic __inline int\natomic_cmpset_long(volatile u_long *dst, u_long expect, u_long src)\n{\n\tu_char res;\n\n\t__asm __volatile(\n\t\"\t\" MPLOCKED \"\t\t\"\n\t\"\tcmpxchgq %3,%1 ;\t\"\n\t\"       sete\t%0 ;\t\t\"\n\t\"# atomic_cmpset_long\"\n\t: \"=q\" (res),\t\t\t/* 0 */\n\t  \"+m\" (*dst),\t\t\t/* 1 */\n\t  \"+a\" (expect)\t\t\t/* 2 */\n\t: \"r\" (src)\t\t\t/* 3 */\n\t: \"memory\", \"cc\");\n\treturn (res);\n}\n\n/*\n * Atomically add the value of v to the integer pointed to by p and return\n * the previous value of *p.\n */\nstatic __inline u_int\natomic_fetchadd_int(volatile u_int *p, u_int v)\n{\n\n\t__asm __volatile(\n\t\"\t\" MPLOCKED \"\t\t\"\n\t\"\txaddl\t%0,%1 ;\t\t\"\n\t\"# atomic_fetchadd_int\"\n\t: \"+r\" (v),\t\t\t/* 0 */\n\t  \"+m\" (*p)\t\t\t/* 1 */\n\t: : \"cc\");\n\treturn (v);\n}\n\n/*\n * Atomically add the value of v to the long integer pointed to by p and return\n * the previous value of *p.\n */\nstatic __inline u_long\natomic_fetchadd_long(volatile u_long *p, u_long v)\n{\n\n\t__asm __volatile(\n\t\"\t\" MPLOCKED \"\t\t\"\n\t\"\txaddq\t%0,%1 ;\t\t\"\n\t\"# atomic_fetchadd_long\"\n\t: \"+r\" (v),\t\t\t/* 0 */\n\t  \"+m\" (*p)\t\t\t/* 1 */\n\t: : \"cc\");\n\treturn (v);\n}\n\nstatic __inline int\natomic_testandset_int(volatile u_int *p, u_int v)\n{\n\tu_char res;\n\n\t__asm __volatile(\n\t\"\t\" MPLOCKED \"\t\t\"\n\t\"\tbtsl\t%2,%1 ;\t\t\"\n\t\"\tsetc\t%0 ;\t\t\"\n\t\"# atomic_testandset_int\"\n\t: \"=q\" (res),\t\t\t/* 0 */\n\t  \"+m\" (*p)\t\t\t/* 1 */\n\t: \"Ir\" (v & 0x1f)\t\t/* 2 */\n\t: \"cc\");\n\treturn (res);\n}\n\nstatic __inline int\natomic_testandset_long(volatile u_long *p, u_int v)\n{\n\tu_char res;\n\n\t__asm __volatile(\n\t\"\t\" MPLOCKED \"\t\t\"\n\t\"\tbtsq\t%2,%1 ;\t\t\"\n\t\"\tsetc\t%0 ;\t\t\"\n\t\"# atomic_testandset_long\"\n\t: \"=q\" (res),\t\t\t/* 0 */\n\t  \"+m\" (*p)\t\t\t/* 1 */\n\t: \"Jr\" ((u_long)(v & 0x3f))\t/* 2 */\n\t: \"cc\");\n\treturn (res);\n}\n\n/*\n * We assume that a = b will do atomic loads and stores.  Due to the\n * IA32 memory model, a simple store guarantees release semantics.\n *\n * However, loads may pass stores, so for atomic_load_acq we have to\n * ensure a Store/Load barrier to do the load in SMP kernels.  We use\n * \"lock cmpxchg\" as recommended by the AMD Software Optimization\n * Guide, and not mfence.  For UP kernels, however, the cache of the\n * single processor is always consistent, so we only need to take care\n * of the compiler.\n */\n#define\tATOMIC_STORE(TYPE)\t\t\t\t\\\nstatic __inline void\t\t\t\t\t\\\natomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\\\n{\t\t\t\t\t\t\t\\\n\t__compiler_membar();\t\t\t\t\\\n\t*p = v;\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\\\nstruct __hack\n\n#define\tATOMIC_LOAD(TYPE, LOP)\t\t\t\t\\\nstatic __inline u_##TYPE\t\t\t\t\\\natomic_load_acq_##TYPE(volatile u_##TYPE *p)\t\t\\\n{\t\t\t\t\t\t\t\\\n\tu_##TYPE res;\t\t\t\t\t\\\n\t\t\t\t\t\t\t\\\n\t__asm __volatile(MPLOCKED LOP\t\t\t\\\n\t: \"=a\" (res),\t\t\t/* 0 */\t\t\\\n\t  \"+m\" (*p)\t\t\t/* 1 */\t\t\\\n\t: : \"memory\", \"cc\");\t\t\t\t\\\n\treturn (res);\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\\\nstruct __hack\n\nATOMIC_ASM(set,\t     char,  \"orb %b1,%0\",  \"iq\",  v);\nATOMIC_ASM(clear,    char,  \"andb %b1,%0\", \"iq\", ~v);\nATOMIC_ASM(add,\t     char,  \"addb %b1,%0\", \"iq\",  v);\nATOMIC_ASM(subtract, char,  \"subb %b1,%0\", \"iq\",  v);\n\nATOMIC_ASM(set,\t     short, \"orw %w1,%0\",  \"ir\",  v);\nATOMIC_ASM(clear,    short, \"andw %w1,%0\", \"ir\", ~v);\nATOMIC_ASM(add,\t     short, \"addw %w1,%0\", \"ir\",  v);\nATOMIC_ASM(subtract, short, \"subw %w1,%0\", \"ir\",  v);\n\nATOMIC_ASM(set,\t     int,   \"orl %1,%0\",   \"ir\",  v);\nATOMIC_ASM(clear,    int,   \"andl %1,%0\",  \"ir\", ~v);\nATOMIC_ASM(add,\t     int,   \"addl %1,%0\",  \"ir\",  v);\nATOMIC_ASM(subtract, int,   \"subl %1,%0\",  \"ir\",  v);\n\nATOMIC_ASM(set,\t     long,  \"orq %1,%0\",   \"ir\",  v);\nATOMIC_ASM(clear,    long,  \"andq %1,%0\",  \"ir\", ~v);\nATOMIC_ASM(add,\t     long,  \"addq %1,%0\",  \"ir\",  v);\nATOMIC_ASM(subtract, long,  \"subq %1,%0\",  \"ir\",  v);\n\nATOMIC_LOAD(char,  \"cmpxchgb %b0,%1\");\nATOMIC_LOAD(short, \"cmpxchgw %w0,%1\");\nATOMIC_LOAD(int,   \"cmpxchgl %0,%1\");\nATOMIC_LOAD(long,  \"cmpxchgq %0,%1\");\n\nATOMIC_STORE(char);\nATOMIC_STORE(short);\nATOMIC_STORE(int);\nATOMIC_STORE(long);\n\n#undef ATOMIC_ASM\n#undef ATOMIC_LOAD\n#undef ATOMIC_STORE\n\n/* Read the current value and store a new value in the destination. */\n\nstatic __inline u_int\natomic_swap_int(volatile u_int *p, u_int v)\n{\n\n\t__asm __volatile(\n\t\"\txchgl\t%1,%0 ;\t\t\"\n\t\"# atomic_swap_int\"\n\t: \"+r\" (v),\t\t\t/* 0 */\n\t  \"+m\" (*p));\t\t\t/* 1 */\n\treturn (v);\n}\n\nstatic __inline u_long\natomic_swap_long(volatile u_long *p, u_long v)\n{\n\n\t__asm __volatile(\n\t\"\txchgq\t%1,%0 ;\t\t\"\n\t\"# atomic_swap_long\"\n\t: \"+r\" (v),\t\t\t/* 0 */\n\t  \"+m\" (*p));\t\t\t/* 1 */\n\treturn (v);\n}\n\n#define\tatomic_set_acq_char\t\tatomic_set_barr_char\n#define\tatomic_set_rel_char\t\tatomic_set_barr_char\n#define\tatomic_clear_acq_char\t\tatomic_clear_barr_char\n#define\tatomic_clear_rel_char\t\tatomic_clear_barr_char\n#define\tatomic_add_acq_char\t\tatomic_add_barr_char\n#define\tatomic_add_rel_char\t\tatomic_add_barr_char\n#define\tatomic_subtract_acq_char\tatomic_subtract_barr_char\n#define\tatomic_subtract_rel_char\tatomic_subtract_barr_char\n\n#define\tatomic_set_acq_short\t\tatomic_set_barr_short\n#define\tatomic_set_rel_short\t\tatomic_set_barr_short\n#define\tatomic_clear_acq_short\t\tatomic_clear_barr_short\n#define\tatomic_clear_rel_short\t\tatomic_clear_barr_short\n#define\tatomic_add_acq_short\t\tatomic_add_barr_short\n#define\tatomic_add_rel_short\t\tatomic_add_barr_short\n#define\tatomic_subtract_acq_short\tatomic_subtract_barr_short\n#define\tatomic_subtract_rel_short\tatomic_subtract_barr_short\n\n#define\tatomic_set_acq_int\t\tatomic_set_barr_int\n#define\tatomic_set_rel_int\t\tatomic_set_barr_int\n#define\tatomic_clear_acq_int\t\tatomic_clear_barr_int\n#define\tatomic_clear_rel_int\t\tatomic_clear_barr_int\n#define\tatomic_add_acq_int\t\tatomic_add_barr_int\n#define\tatomic_add_rel_int\t\tatomic_add_barr_int\n#define\tatomic_subtract_acq_int\t\tatomic_subtract_barr_int\n#define\tatomic_subtract_rel_int\t\tatomic_subtract_barr_int\n#define\tatomic_cmpset_acq_int\t\tatomic_cmpset_int\n#define\tatomic_cmpset_rel_int\t\tatomic_cmpset_int\n\n#define\tatomic_set_acq_long\t\tatomic_set_barr_long\n#define\tatomic_set_rel_long\t\tatomic_set_barr_long\n#define\tatomic_clear_acq_long\t\tatomic_clear_barr_long\n#define\tatomic_clear_rel_long\t\tatomic_clear_barr_long\n#define\tatomic_add_acq_long\t\tatomic_add_barr_long\n#define\tatomic_add_rel_long\t\tatomic_add_barr_long\n#define\tatomic_subtract_acq_long\tatomic_subtract_barr_long\n#define\tatomic_subtract_rel_long\tatomic_subtract_barr_long\n#define\tatomic_cmpset_acq_long\t\tatomic_cmpset_long\n#define\tatomic_cmpset_rel_long\t\tatomic_cmpset_long\n\n#define\tatomic_readandclear_int(p)\tatomic_swap_int(p, 0)\n#define\tatomic_readandclear_long(p)\tatomic_swap_long(p, 0)\n\n/* Operations on 8-bit bytes. */\n#define\tatomic_set_8\t\tatomic_set_char\n#define\tatomic_set_acq_8\tatomic_set_acq_char\n#define\tatomic_set_rel_8\tatomic_set_rel_char\n#define\tatomic_clear_8\t\tatomic_clear_char\n#define\tatomic_clear_acq_8\tatomic_clear_acq_char\n#define\tatomic_clear_rel_8\tatomic_clear_rel_char\n#define\tatomic_add_8\t\tatomic_add_char\n#define\tatomic_add_acq_8\tatomic_add_acq_char\n#define\tatomic_add_rel_8\tatomic_add_rel_char\n#define\tatomic_subtract_8\tatomic_subtract_char\n#define\tatomic_subtract_acq_8\tatomic_subtract_acq_char\n#define\tatomic_subtract_rel_8\tatomic_subtract_rel_char\n#define\tatomic_load_acq_8\tatomic_load_acq_char\n#define\tatomic_store_rel_8\tatomic_store_rel_char\n\n/* Operations on 16-bit words. */\n#define\tatomic_set_16\t\tatomic_set_short\n#define\tatomic_set_acq_16\tatomic_set_acq_short\n#define\tatomic_set_rel_16\tatomic_set_rel_short\n#define\tatomic_clear_16\t\tatomic_clear_short\n#define\tatomic_clear_acq_16\tatomic_clear_acq_short\n#define\tatomic_clear_rel_16\tatomic_clear_rel_short\n#define\tatomic_add_16\t\tatomic_add_short\n#define\tatomic_add_acq_16\tatomic_add_acq_short\n#define\tatomic_add_rel_16\tatomic_add_rel_short\n#define\tatomic_subtract_16\tatomic_subtract_short\n#define\tatomic_subtract_acq_16\tatomic_subtract_acq_short\n#define\tatomic_subtract_rel_16\tatomic_subtract_rel_short\n#define\tatomic_load_acq_16\tatomic_load_acq_short\n#define\tatomic_store_rel_16\tatomic_store_rel_short\n\n/* Operations on 32-bit double words. */\n#define\tatomic_set_32\t\tatomic_set_int\n#define\tatomic_set_acq_32\tatomic_set_acq_int\n#define\tatomic_set_rel_32\tatomic_set_rel_int\n#define\tatomic_clear_32\t\tatomic_clear_int\n#define\tatomic_clear_acq_32\tatomic_clear_acq_int\n#define\tatomic_clear_rel_32\tatomic_clear_rel_int\n#define\tatomic_add_32\t\tatomic_add_int\n#define\tatomic_add_acq_32\tatomic_add_acq_int\n#define\tatomic_add_rel_32\tatomic_add_rel_int\n#define\tatomic_subtract_32\tatomic_subtract_int\n#define\tatomic_subtract_acq_32\tatomic_subtract_acq_int\n#define\tatomic_subtract_rel_32\tatomic_subtract_rel_int\n#define\tatomic_load_acq_32\tatomic_load_acq_int\n#define\tatomic_store_rel_32\tatomic_store_rel_int\n#define\tatomic_cmpset_32\tatomic_cmpset_int\n#define\tatomic_cmpset_acq_32\tatomic_cmpset_acq_int\n#define\tatomic_cmpset_rel_32\tatomic_cmpset_rel_int\n#define\tatomic_swap_32\t\tatomic_swap_int\n#define\tatomic_readandclear_32\tatomic_readandclear_int\n#define\tatomic_fetchadd_32\tatomic_fetchadd_int\n#define\tatomic_testandset_32\tatomic_testandset_int\n\n/* Operations on 64-bit quad words. */\n#define\tatomic_set_64\t\tatomic_set_long\n#define\tatomic_set_acq_64\tatomic_set_acq_long\n#define\tatomic_set_rel_64\tatomic_set_rel_long\n#define\tatomic_clear_64\t\tatomic_clear_long\n#define\tatomic_clear_acq_64\tatomic_clear_acq_long\n#define\tatomic_clear_rel_64\tatomic_clear_rel_long\n#define\tatomic_add_64\t\tatomic_add_long\n#define\tatomic_add_acq_64\tatomic_add_acq_long\n#define\tatomic_add_rel_64\tatomic_add_rel_long\n#define\tatomic_subtract_64\tatomic_subtract_long\n#define\tatomic_subtract_acq_64\tatomic_subtract_acq_long\n#define\tatomic_subtract_rel_64\tatomic_subtract_rel_long\n#define\tatomic_load_acq_64\tatomic_load_acq_long\n#define\tatomic_store_rel_64\tatomic_store_rel_long\n#define\tatomic_cmpset_64\tatomic_cmpset_long\n#define\tatomic_cmpset_acq_64\tatomic_cmpset_acq_long\n#define\tatomic_cmpset_rel_64\tatomic_cmpset_rel_long\n#define\tatomic_swap_64\t\tatomic_swap_long\n#define\tatomic_readandclear_64\tatomic_readandclear_long\n#define\tatomic_testandset_64\tatomic_testandset_long\n\n/* Operations on pointers. */\n#define\tatomic_set_ptr\t\tatomic_set_long\n#define\tatomic_set_acq_ptr\tatomic_set_acq_long\n#define\tatomic_set_rel_ptr\tatomic_set_rel_long\n#define\tatomic_clear_ptr\tatomic_clear_long\n#define\tatomic_clear_acq_ptr\tatomic_clear_acq_long\n#define\tatomic_clear_rel_ptr\tatomic_clear_rel_long\n#define\tatomic_add_ptr\t\tatomic_add_long\n#define\tatomic_add_acq_ptr\tatomic_add_acq_long\n#define\tatomic_add_rel_ptr\tatomic_add_rel_long\n#define\tatomic_subtract_ptr\tatomic_subtract_long\n#define\tatomic_subtract_acq_ptr\tatomic_subtract_acq_long\n#define\tatomic_subtract_rel_ptr\tatomic_subtract_rel_long\n#define\tatomic_load_acq_ptr\tatomic_load_acq_long\n#define\tatomic_store_rel_ptr\tatomic_store_rel_long\n#define\tatomic_cmpset_ptr\tatomic_cmpset_long\n#define\tatomic_cmpset_acq_ptr\tatomic_cmpset_acq_long\n#define\tatomic_cmpset_rel_ptr\tatomic_cmpset_rel_long\n#define\tatomic_swap_ptr\t\tatomic_swap_long\n#define\tatomic_readandclear_ptr\tatomic_readandclear_long\n"
  },
  {
    "path": "include/xhyve/support/bitset.h",
    "content": "/*-\n * Copyright (c) 2008, Jeffrey Roberson <jeff@freebsd.org>\n * All rights reserved.\n *\n * Copyright (c) 2008 Nokia Corporation\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <strings.h>\n#include <sys/types.h>\n\n/*\n * Macros addressing word and bit within it, tuned to make compiler\n * optimize cases when SETSIZE fits into single machine word.\n */\n#define\t_BITSET_BITS\t\t(sizeof(long) * NBBY)\n\n#define\t__bitset_words(_s)\t(howmany(_s, _BITSET_BITS))\n\n#define\t__bitset_mask(_s, n)\t\t\t\t\t\t\\\n\t(1L << ((__bitset_words((_s)) == 1) ?\t\t\t\t\\\n\t    (size_t)(n) : ((n) % _BITSET_BITS)))\n\n#define\t__bitset_word(_s, n)\t\t\t\t\t\t\\\n\t((__bitset_words((_s)) == 1) ? 0 : ((n) / _BITSET_BITS))\n\n#define\tBITSET_DEFINE(t, _s)\t\t\t\t\t\t\\\nstruct t {\t\t\t\t\t\t\t\t\\\n        long    __bits[__bitset_words((_s))];\t\t\t\t\\\n}\n\n#define\tBITSET_T_INITIALIZER(x)\t\t\t\t\t\t\\\n\t{ .__bits = { x } }\n\n#define\tBITSET_FSET(n)\t\t\t\t\t\t\t\\\n\t[ 0 ... ((n) - 1) ] = (-1L)\n\n#define\tBIT_CLR(_s, n, p)\t\t\t\t\t\t\\\n\t((p)->__bits[__bitset_word(_s, n)] &= ~__bitset_mask((_s), (n)))\n\n#define\tBIT_COPY(_s, f, t)\t(void)(*(t) = *(f))\n\n#define\tBIT_ISSET(_s, n, p)\t\t\t\t\t\t\\\n\t((((p)->__bits[__bitset_word(_s, n)] & __bitset_mask((_s), (n))) != 0))\n\n#define\tBIT_SET(_s, n, p)\t\t\t\t\t\t\\\n\t((p)->__bits[__bitset_word(_s, n)] |= __bitset_mask((_s), (n)))\n\n#define\tBIT_ZERO(_s, p) do {\t\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\t(p)->__bits[__i] = 0L;\t\t\t\t\t\\\n} while (0)\n\n#define\tBIT_FILL(_s, p) do {\t\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\t(p)->__bits[__i] = -1L;\t\t\t\t\t\\\n} while (0)\n\n#define\tBIT_SETOF(_s, n, p) do {\t\t\t\t\t\\\n\tBIT_ZERO(_s, p);\t\t\t\t\t\t\\\n\t(p)->__bits[__bitset_word(_s, n)] = __bitset_mask((_s), (n));\t\\\n} while (0)\n\n/* Is p empty. */\n#define\tBIT_EMPTY(_s, p) __extension__ ({\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tif ((p)->__bits[__i])\t\t\t\t\t\\\n\t\t\tbreak;\t\t\t\t\t\t\\\n\t__i == __bitset_words((_s));\t\t\t\t\t\\\n})\n\n/* Is p full set. */\n#define\tBIT_ISFULLSET(_s, p) __extension__ ({\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tif ((p)->__bits[__i] != (long)-1)\t\t\t\\\n\t\t\tbreak;\t\t\t\t\t\t\\\n\t__i == __bitset_words((_s));\t\t\t\t\t\\\n})\n\n/* Is c a subset of p. */\n#define\tBIT_SUBSET(_s, p, c) __extension__ ({\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tif (((c)->__bits[__i] &\t\t\t\t\t\\\n\t\t    (p)->__bits[__i]) !=\t\t\t\t\\\n\t\t    (c)->__bits[__i])\t\t\t\t\t\\\n\t\t\tbreak;\t\t\t\t\t\t\\\n\t__i == __bitset_words((_s));\t\t\t\t\t\\\n})\n\n/* Are there any common bits between b & c? */\n#define\tBIT_OVERLAP(_s, p, c) __extension__ ({\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tif (((c)->__bits[__i] &\t\t\t\t\t\\\n\t\t    (p)->__bits[__i]) != 0)\t\t\t\t\\\n\t\t\tbreak;\t\t\t\t\t\t\\\n\t__i != __bitset_words((_s));\t\t\t\t\t\\\n})\n\n/* Compare two sets, returns 0 if equal 1 otherwise. */\n#define\tBIT_CMP(_s, p, c) __extension__ ({\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tif (((c)->__bits[__i] !=\t\t\t\t\\\n\t\t    (p)->__bits[__i]))\t\t\t\t\t\\\n\t\t\tbreak;\t\t\t\t\t\t\\\n\t__i != __bitset_words((_s));\t\t\t\t\t\\\n})\n\n#define\tBIT_OR(_s, d, s) do {\t\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\t(d)->__bits[__i] |= (s)->__bits[__i];\t\t\t\\\n} while (0)\n\n#define\tBIT_AND(_s, d, s) do {\t\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\t(d)->__bits[__i] &= (s)->__bits[__i];\t\t\t\\\n} while (0)\n\n#define\tBIT_NAND(_s, d, s) do {\t\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\t(d)->__bits[__i] &= ~(s)->__bits[__i];\t\t\t\\\n} while (0)\n\n#define\tBIT_CLR_ATOMIC(_s, n, p) \\\n\tatomic_clear_long(((volatile u_long *) \\\n\t\t&(p)->__bits[__bitset_word(_s, n)]), __bitset_mask((_s), n))\n\n#define\tBIT_SET_ATOMIC(_s, n, p) \\\n\tatomic_set_long(((volatile u_long *) &(p)->__bits[__bitset_word(_s, n)]), \\\n\t    __bitset_mask((_s), n))\n\n#define\tBIT_SET_ATOMIC_ACQ(_s, n, p)\t\t\t\t\t\\\n\tatomic_set_acq_long(&(p)->__bits[__bitset_word(_s, n)],\t\t\\\n\t    __bitset_mask((_s), n))\n\n/* Convenience functions catering special cases. */\n#define\tBIT_AND_ATOMIC(_s, d, s) do {\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tatomic_clear_long(&(d)->__bits[__i],\t\t\t\\\n\t\t    ~(s)->__bits[__i]);\t\t\t\t\t\\\n} while (0)\n\n#define\tBIT_OR_ATOMIC(_s, d, s) do {\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tatomic_set_long(&(d)->__bits[__i],\t\t\t\\\n\t\t    (s)->__bits[__i]);\t\t\t\t\t\\\n} while (0)\n\n#define\tBIT_COPY_STORE_REL(_s, f, t) do {\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\tatomic_store_rel_long(&(t)->__bits[__i],\t\t\\\n\t\t    (f)->__bits[__i]);\t\t\t\t\t\\\n} while (0)\n\n#define\tBIT_FFS(_s, p) __extension__ ({\t\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tint __bit;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t__bit = 0;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++) {\t\t\\\n\t\tif ((p)->__bits[__i] != 0) {\t\t\t\t\\\n\t\t\t__bit = ffsl((p)->__bits[__i]);\t\t\t\\\n\t\t\t__bit += __i * _BITSET_BITS;\t\t\t\\\n\t\t\tbreak;\t\t\t\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\t__bit;\t\t\t\t\t\t\t\t\\\n})\n\n#define\tBIT_COUNT(_s, p) __extension__ ({\t\t\t\t\\\n\tsize_t __i;\t\t\t\t\t\t\t\\\n\tint __count;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t__count = 0;\t\t\t\t\t\t\t\\\n\tfor (__i = 0; __i < __bitset_words((_s)); __i++)\t\t\\\n\t\t__count += __bitcountl((p)->__bits[__i]);\t\t\\\n\t__count;\t\t\t\t\t\t\t\\\n})\n"
  },
  {
    "path": "include/xhyve/support/cpuset.h",
    "content": "/*-\n * Copyright (c) 2008,\tJeffrey Roberson <jeff@freebsd.org>\n * All rights reserved.\n *\n * Copyright (c) 2008 Nokia Corporation\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <xhyve/support/bitset.h>\n\n#define\tCPU_MAXSIZE\t32\n\n#ifndef\tCPU_SETSIZE\n#define\tCPU_SETSIZE\tCPU_MAXSIZE\n#endif\n\n// #define\t_NCPUBITS\t_BITSET_BITS\n// #define\t_NCPUWORDS\t__bitset_words(CPU_SETSIZE)\n\nBITSET_DEFINE(_cpuset, CPU_SETSIZE);\ntypedef struct _cpuset cpuset_t;\n\n// #define\tCPUSET_FSET\t\tBITSET_FSET(_NCPUWORDS)\n// #define\tCPUSET_T_INITIALIZER\tBITSET_T_INITIALIZER\n\n// #define\tCPUSETBUFSIZ\t((2 + sizeof(long) * 2) * _NCPUWORDS)\n\n#define\tCPU_CLR(n, p)\t\t\tBIT_CLR(CPU_SETSIZE, n, p)\n// #define\tCPU_COPY(f, t)\t\t\tBIT_COPY(CPU_SETSIZE, f, t)\n#define\tCPU_ISSET(n, p)\t\t\tBIT_ISSET(CPU_SETSIZE, n, p)\n#define\tCPU_SET(n, p)\t\t\tBIT_SET(CPU_SETSIZE, n, p)\n#define\tCPU_ZERO(p) \t\t\tBIT_ZERO(CPU_SETSIZE, p)\n// #define\tCPU_FILL(p) \t\t\tBIT_FILL(CPU_SETSIZE, p)\n#define\tCPU_SETOF(n, p)\t\t\tBIT_SETOF(CPU_SETSIZE, n, p)\n#define\tCPU_EMPTY(p)\t\t\tBIT_EMPTY(CPU_SETSIZE, p)\n// #define\tCPU_ISFULLSET(p)\t\tBIT_ISFULLSET(CPU_SETSIZE, p)\n// #define\tCPU_SUBSET(p, c)\t\tBIT_SUBSET(CPU_SETSIZE, p, c)\n// #define\tCPU_OVERLAP(p, c)\t\tBIT_OVERLAP(CPU_SETSIZE, p, c)\n#define\tCPU_CMP(p, c)\t\t\tBIT_CMP(CPU_SETSIZE, p, c)\n// #define\tCPU_OR(d, s)\t\t\tBIT_OR(CPU_SETSIZE, d, s)\n#define\tCPU_AND(d, s)\t\t\tBIT_AND(CPU_SETSIZE, d, s)\n// #define\tCPU_NAND(d, s)\t\t\tBIT_NAND(CPU_SETSIZE, d, s)\n#define\tCPU_CLR_ATOMIC(n, p)\t\tBIT_CLR_ATOMIC(CPU_SETSIZE, n, p)\n#define\tCPU_SET_ATOMIC(n, p)\t\tBIT_SET_ATOMIC(CPU_SETSIZE, n, p)\n// #define\tCPU_SET_ATOMIC_ACQ(n, p)\tBIT_SET_ATOMIC_ACQ(CPU_SETSIZE, n, p)\n// #define\tCPU_AND_ATOMIC(n, p)\t\tBIT_AND_ATOMIC(CPU_SETSIZE, n, p)\n// #define\tCPU_OR_ATOMIC(d, s)\t\tBIT_OR_ATOMIC(CPU_SETSIZE, d, s)\n// #define\tCPU_COPY_STORE_REL(f, t)\tBIT_COPY_STORE_REL(CPU_SETSIZE, f, t)\n#define\tCPU_FFS(p)\t\t\tBIT_FFS(CPU_SETSIZE, p)\n// #define\tCPU_COUNT(p)\t\t\tBIT_COUNT(CPU_SETSIZE, p)\n\n// /*\n//  * Valid cpulevel_t values.\n//  */\n// #define\tCPU_LEVEL_ROOT\t\t1\t/* All system cpus. */\n// #define\tCPU_LEVEL_CPUSET\t2\t/* Available cpus for which. */\n// #define\tCPU_LEVEL_WHICH\t\t3\t/* Actual mask/id for which. */\n\n// /*\n//  * Valid cpuwhich_t values.\n//  */\n// #define\tCPU_WHICH_TID\t\t1\t/* Specifies a thread id. */\n// #define\tCPU_WHICH_PID\t\t2\t/* Specifies a process id. */\n// #define\tCPU_WHICH_CPUSET\t3\t/* Specifies a set id. */\n// #define\tCPU_WHICH_IRQ\t\t4\t/* Specifies an irq #. */\n// #define\tCPU_WHICH_JAIL\t\t5\t/* Specifies a jail id. */\n// #define\tCPU_WHICH_DOMAIN\t6\t/* Specifies a NUMA domain id. */\n\n// /*\n//  * Reserved cpuset identifiers.\n//  */\n// #define\tCPUSET_INVALID\t-1\n// #define\tCPUSET_DEFAULT\t0\n\n// #ifdef _KERNEL\n// LIST_HEAD(setlist, cpuset);\n\n// /*\n//  * cpusets encapsulate cpu binding information for one or more threads.\n//  *\n//  * \ta - Accessed with atomics.\n//  *\ts - Set at creation, never modified.  Only a ref required to read.\n//  *\tc - Locked internally by a cpuset lock.\n//  *\n//  * The bitmask is only modified while holding the cpuset lock.  It may be\n//  * read while only a reference is held but the consumer must be prepared\n//  * to deal with inconsistent results.\n//  */\n// struct cpuset {\n// \tcpuset_t\t\tcs_mask;\t/* bitmask of valid cpus. */\n// \tvolatile u_int\t\tcs_ref;\t\t/* (a) Reference count. */\n// \tint\t\t\tcs_flags;\t/* (s) Flags from below. */\n// \tcpusetid_t\t\tcs_id;\t\t/* (s) Id or INVALID. */\n// \tstruct cpuset\t\t*cs_parent;\t/* (s) Pointer to our parent. */\n// \tLIST_ENTRY(cpuset)\tcs_link;\t/* (c) All identified sets. */\n// \tLIST_ENTRY(cpuset)\tcs_siblings;\t/* (c) Sibling set link. */\n// \tstruct setlist\t\tcs_children;\t/* (c) List of children. */\n// };\n\n// #define CPU_SET_ROOT    0x0001  /* Set is a root set. */\n// #define CPU_SET_RDONLY  0x0002  /* No modification allowed. */\n\n// extern cpuset_t *cpuset_root;\n// struct prison;\n// struct proc;\n\n// struct cpuset *cpuset_thread0(void);\n// struct cpuset *cpuset_ref(struct cpuset *);\n// void\tcpuset_rel(struct cpuset *);\n// int\tcpuset_setthread(lwpid_t id, cpuset_t *);\n// int\tcpuset_setithread(lwpid_t id, int cpu);\n// int\tcpuset_create_root(struct prison *, struct cpuset **);\n// int\tcpuset_setproc_update_set(struct proc *, struct cpuset *);\n// char\t*cpusetobj_strprint(char *, const cpuset_t *);\n// int\tcpusetobj_strscan(cpuset_t *, const char *);\n\n// #else\n// __BEGIN_DECLS\n// int\tcpuset(cpusetid_t *);\n// int\tcpuset_setid(cpuwhich_t, id_t, cpusetid_t);\n// int\tcpuset_getid(cpulevel_t, cpuwhich_t, id_t, cpusetid_t *);\n// int\tcpuset_getaffinity(cpulevel_t, cpuwhich_t, id_t, size_t, cpuset_t *);\n// int\tcpuset_setaffinity(cpulevel_t, cpuwhich_t, id_t, size_t, const cpuset_t *);\n// __END_DECLS\n// #endif\n"
  },
  {
    "path": "include/xhyve/support/e1000_defines.h",
    "content": "/******************************************************************************\n  SPDX-License-Identifier: BSD-3-Clause\n\n  Copyright (c) 2001-2015, Intel Corporation\n  All rights reserved.\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions are met:\n\n   1. Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n\n   3. Neither the name of the Intel Corporation nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n  POSSIBILITY OF SUCH DAMAGE.\n\n******************************************************************************/\n/*$FreeBSD$*/\n\n#ifndef _E1000_DEFINES_H_\n#define _E1000_DEFINES_H_\n\n/* Number of Transmit and Receive Descriptors must be a multiple of 8 */\n#define REQ_TX_DESCRIPTOR_MULTIPLE  8\n#define REQ_RX_DESCRIPTOR_MULTIPLE  8\n\n/* Definitions for power management and wakeup registers */\n/* Wake Up Control */\n#define E1000_WUC_APME\t\t0x00000001 /* APM Enable */\n#define E1000_WUC_PME_EN\t0x00000002 /* PME Enable */\n#define E1000_WUC_PME_STATUS\t0x00000004 /* PME Status */\n#define E1000_WUC_APMPME\t0x00000008 /* Assert PME on APM Wakeup */\n#define E1000_WUC_PHY_WAKE\t0x00000100 /* if PHY supports wakeup */\n\n/* Wake Up Filter Control */\n#define E1000_WUFC_LNKC\t0x00000001 /* Link Status Change Wakeup Enable */\n#define E1000_WUFC_MAG\t0x00000002 /* Magic Packet Wakeup Enable */\n#define E1000_WUFC_EX\t0x00000004 /* Directed Exact Wakeup Enable */\n#define E1000_WUFC_MC\t0x00000008 /* Directed Multicast Wakeup Enable */\n#define E1000_WUFC_BC\t0x00000010 /* Broadcast Wakeup Enable */\n#define E1000_WUFC_ARP\t0x00000020 /* ARP Request Packet Wakeup Enable */\n#define E1000_WUFC_IPV4\t0x00000040 /* Directed IPv4 Packet Wakeup Enable */\n#define E1000_WUFC_FLX0\t\t0x00010000 /* Flexible Filter 0 Enable */\n\n/* Wake Up Status */\n#define E1000_WUS_LNKC\t\tE1000_WUFC_LNKC\n#define E1000_WUS_MAG\t\tE1000_WUFC_MAG\n#define E1000_WUS_EX\t\tE1000_WUFC_EX\n#define E1000_WUS_MC\t\tE1000_WUFC_MC\n#define E1000_WUS_BC\t\tE1000_WUFC_BC\n\n/* Extended Device Control */\n#define E1000_CTRL_EXT_LPCD\t\t0x00000004 /* LCD Power Cycle Done */\n#define E1000_CTRL_EXT_SDP4_DATA\t0x00000010 /* SW Definable Pin 4 data */\n#define E1000_CTRL_EXT_SDP6_DATA\t0x00000040 /* SW Definable Pin 6 data */\n#define E1000_CTRL_EXT_SDP3_DATA\t0x00000080 /* SW Definable Pin 3 data */\n/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */\n#define E1000_CTRL_EXT_SDP4_DIR\t0x00000100 /* Direction of SDP4 0=in 1=out */\n#define E1000_CTRL_EXT_SDP6_DIR\t0x00000400 /* Direction of SDP6 0=in 1=out */\n#define E1000_CTRL_EXT_SDP3_DIR\t0x00000800 /* Direction of SDP3 0=in 1=out */\n#define E1000_CTRL_EXT_FORCE_SMBUS\t0x00000800 /* Force SMBus mode */\n#define E1000_CTRL_EXT_EE_RST\t0x00002000 /* Reinitialize from EEPROM */\n/* Physical Func Reset Done Indication */\n#define E1000_CTRL_EXT_PFRSTD\t0x00004000\n#define E1000_CTRL_EXT_SDLPE\t0X00040000  /* SerDes Low Power Enable */\n#define E1000_CTRL_EXT_SPD_BYPS\t0x00008000 /* Speed Select Bypass */\n#define E1000_CTRL_EXT_RO_DIS\t0x00020000 /* Relaxed Ordering disable */\n#define E1000_CTRL_EXT_DMA_DYN_CLK_EN\t0x00080000 /* DMA Dynamic Clk Gating */\n#define E1000_CTRL_EXT_LINK_MODE_MASK\t0x00C00000\n/* Offset of the link mode field in Ctrl Ext register */\n#define E1000_CTRL_EXT_LINK_MODE_OFFSET\t22\n#define E1000_CTRL_EXT_LINK_MODE_1000BASE_KX\t0x00400000\n#define E1000_CTRL_EXT_LINK_MODE_GMII\t0x00000000\n#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES\t0x00C00000\n#define E1000_CTRL_EXT_LINK_MODE_SGMII\t0x00800000\n#define E1000_CTRL_EXT_EIAME\t\t0x01000000\n#define E1000_CTRL_EXT_IRCA\t\t0x00000001\n#define E1000_CTRL_EXT_DRV_LOAD\t\t0x10000000 /* Drv loaded bit for FW */\n#define E1000_CTRL_EXT_IAME\t\t0x08000000 /* Int ACK Auto-mask */\n#define E1000_CTRL_EXT_PBA_CLR\t\t0x80000000 /* PBA Clear */\n#define E1000_CTRL_EXT_LSECCK\t\t0x00001000\n#define E1000_CTRL_EXT_PHYPDEN\t\t0x00100000\n#define E1000_I2CCMD_REG_ADDR_SHIFT\t16\n#define E1000_I2CCMD_PHY_ADDR_SHIFT\t24\n#define E1000_I2CCMD_OPCODE_READ\t0x08000000\n#define E1000_I2CCMD_OPCODE_WRITE\t0x00000000\n#define E1000_I2CCMD_READY\t\t0x20000000\n#define E1000_I2CCMD_ERROR\t\t0x80000000\n#define E1000_I2CCMD_SFP_DATA_ADDR(a)\t(0x0000 + (a))\n#define E1000_I2CCMD_SFP_DIAG_ADDR(a)\t(0x0100 + (a))\n#define E1000_MAX_SGMII_PHY_REG_ADDR\t255\n#define E1000_I2CCMD_PHY_TIMEOUT\t200\n#define E1000_IVAR_VALID\t0x80\n#define E1000_GPIE_NSICR\t0x00000001\n#define E1000_GPIE_MSIX_MODE\t0x00000010\n#define E1000_GPIE_EIAME\t0x40000000\n#define E1000_GPIE_PBA\t\t0x80000000\n\n/* Receive Descriptor bit definitions */\n#define E1000_RXD_STAT_DD\t0x01    /* Descriptor Done */\n#define E1000_RXD_STAT_EOP\t0x02    /* End of Packet */\n#define E1000_RXD_STAT_IXSM\t0x04    /* Ignore checksum */\n#define E1000_RXD_STAT_VP\t0x08    /* IEEE VLAN Packet */\n#define E1000_RXD_STAT_UDPCS\t0x10    /* UDP xsum calculated */\n#define E1000_RXD_STAT_TCPCS\t0x20    /* TCP xsum calculated */\n#define E1000_RXD_STAT_IPCS\t0x40    /* IP xsum calculated */\n#define E1000_RXD_STAT_PIF\t0x80    /* passed in-exact filter */\n#define E1000_RXD_STAT_IPIDV\t0x200   /* IP identification valid */\n#define E1000_RXD_STAT_UDPV\t0x400   /* Valid UDP checksum */\n#define E1000_RXD_STAT_DYNINT\t0x800   /* Pkt caused INT via DYNINT */\n#define E1000_RXD_ERR_CE\t0x01    /* CRC Error */\n#define E1000_RXD_ERR_SE\t0x02    /* Symbol Error */\n#define E1000_RXD_ERR_SEQ\t0x04    /* Sequence Error */\n#define E1000_RXD_ERR_CXE\t0x10    /* Carrier Extension Error */\n#define E1000_RXD_ERR_TCPE\t0x20    /* TCP/UDP Checksum Error */\n#define E1000_RXD_ERR_IPE\t0x40    /* IP Checksum Error */\n#define E1000_RXD_ERR_RXE\t0x80    /* Rx Data Error */\n#define E1000_RXD_SPC_VLAN_MASK\t0x0FFF  /* VLAN ID is in lower 12 bits */\n\n#define E1000_RXDEXT_STATERR_TST\t0x00000100 /* Time Stamp taken */\n#define E1000_RXDEXT_STATERR_LB\t\t0x00040000\n#define E1000_RXDEXT_STATERR_CE\t\t0x01000000\n#define E1000_RXDEXT_STATERR_SE\t\t0x02000000\n#define E1000_RXDEXT_STATERR_SEQ\t0x04000000\n#define E1000_RXDEXT_STATERR_CXE\t0x10000000\n#define E1000_RXDEXT_STATERR_TCPE\t0x20000000\n#define E1000_RXDEXT_STATERR_IPE\t0x40000000\n#define E1000_RXDEXT_STATERR_RXE\t0x80000000\n\n/* mask to determine if packets should be dropped due to frame errors */\n#define E1000_RXD_ERR_FRAME_ERR_MASK ( \\\n\tE1000_RXD_ERR_CE  |\t\t\\\n\tE1000_RXD_ERR_SE  |\t\t\\\n\tE1000_RXD_ERR_SEQ |\t\t\\\n\tE1000_RXD_ERR_CXE |\t\t\\\n\tE1000_RXD_ERR_RXE)\n\n/* Same mask, but for extended and packet split descriptors */\n#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \\\n\tE1000_RXDEXT_STATERR_CE  |\t\\\n\tE1000_RXDEXT_STATERR_SE  |\t\\\n\tE1000_RXDEXT_STATERR_SEQ |\t\\\n\tE1000_RXDEXT_STATERR_CXE |\t\\\n\tE1000_RXDEXT_STATERR_RXE)\n\n#define E1000_MRQC_RSS_ENABLE_2Q\t\t0x00000001\n#define E1000_MRQC_RSS_FIELD_MASK\t\t0xFFFF0000\n#define E1000_MRQC_RSS_FIELD_IPV4_TCP\t\t0x00010000\n#define E1000_MRQC_RSS_FIELD_IPV4\t\t0x00020000\n#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX\t0x00040000\n#define E1000_MRQC_RSS_FIELD_IPV6_EX\t\t0x00080000\n#define E1000_MRQC_RSS_FIELD_IPV6\t\t0x00100000\n#define E1000_MRQC_RSS_FIELD_IPV6_TCP\t\t0x00200000\n\n#define E1000_RXDPS_HDRSTAT_HDRSP\t\t0x00008000\n\n/* Management Control */\n#define E1000_MANC_SMBUS_EN\t0x00000001 /* SMBus Enabled - RO */\n#define E1000_MANC_ASF_EN\t0x00000002 /* ASF Enabled - RO */\n#define E1000_MANC_ARP_EN\t0x00002000 /* Enable ARP Request Filtering */\n#define E1000_MANC_RCV_TCO_EN\t0x00020000 /* Receive TCO Packets Enabled */\n#define E1000_MANC_BLK_PHY_RST_ON_IDE\t0x00040000 /* Block phy resets */\n/* Enable MAC address filtering */\n#define E1000_MANC_EN_MAC_ADDR_FILTER\t0x00100000\n/* Enable MNG packets to host memory */\n#define E1000_MANC_EN_MNG2HOST\t\t0x00200000\n\n#define E1000_MANC2H_PORT_623\t\t0x00000020 /* Port 0x26f */\n#define E1000_MANC2H_PORT_664\t\t0x00000040 /* Port 0x298 */\n#define E1000_MDEF_PORT_623\t\t0x00000800 /* Port 0x26f */\n#define E1000_MDEF_PORT_664\t\t0x00000400 /* Port 0x298 */\n\n/* Receive Control */\n#define E1000_RCTL_RST\t\t0x00000001 /* Software reset */\n#define E1000_RCTL_EN\t\t0x00000002 /* enable */\n#define E1000_RCTL_SBP\t\t0x00000004 /* store bad packet */\n#define E1000_RCTL_UPE\t\t0x00000008 /* unicast promisc enable */\n#define E1000_RCTL_MPE\t\t0x00000010 /* multicast promisc enable */\n#define E1000_RCTL_LPE\t\t0x00000020 /* long packet enable */\n#define E1000_RCTL_LBM_NO\t0x00000000 /* no loopback mode */\n#define E1000_RCTL_LBM_MAC\t0x00000040 /* MAC loopback mode */\n#define E1000_RCTL_LBM_TCVR\t0x000000C0 /* tcvr loopback mode */\n#define E1000_RCTL_DTYP_PS\t0x00000400 /* Packet Split descriptor */\n#define E1000_RCTL_RDMTS_HALF\t0x00000000 /* Rx desc min thresh size */\n#define E1000_RCTL_RDMTS_HEX\t0x00010000\n#define E1000_RCTL_RDMTS1_HEX\tE1000_RCTL_RDMTS_HEX\n#define E1000_RCTL_MO_SHIFT\t12 /* multicast offset shift */\n#define E1000_RCTL_MO_3\t\t0x00003000 /* multicast offset 15:4 */\n#define E1000_RCTL_BAM\t\t0x00008000 /* broadcast enable */\n/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */\n#define E1000_RCTL_SZ_2048\t0x00000000 /* Rx buffer size 2048 */\n#define E1000_RCTL_SZ_1024\t0x00010000 /* Rx buffer size 1024 */\n#define E1000_RCTL_SZ_512\t0x00020000 /* Rx buffer size 512 */\n#define E1000_RCTL_SZ_256\t0x00030000 /* Rx buffer size 256 */\n/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */\n#define E1000_RCTL_SZ_16384\t0x00010000 /* Rx buffer size 16384 */\n#define E1000_RCTL_SZ_8192\t0x00020000 /* Rx buffer size 8192 */\n#define E1000_RCTL_SZ_4096\t0x00030000 /* Rx buffer size 4096 */\n#define E1000_RCTL_VFE\t\t0x00040000 /* vlan filter enable */\n#define E1000_RCTL_CFIEN\t0x00080000 /* canonical form enable */\n#define E1000_RCTL_CFI\t\t0x00100000 /* canonical form indicator */\n#define E1000_RCTL_DPF\t\t0x00400000 /* discard pause frames */\n#define E1000_RCTL_PMCF\t\t0x00800000 /* pass MAC control frames */\n#define E1000_RCTL_BSEX\t\t0x02000000 /* Buffer size extension */\n#define E1000_RCTL_SECRC\t0x04000000 /* Strip Ethernet CRC */\n\n/* Use byte values for the following shift parameters\n * Usage:\n *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &\n *\t\t  E1000_PSRCTL_BSIZE0_MASK) |\n *\t\t((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &\n *\t\t  E1000_PSRCTL_BSIZE1_MASK) |\n *\t\t((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &\n *\t\t  E1000_PSRCTL_BSIZE2_MASK) |\n *\t\t((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;\n *\t\t  E1000_PSRCTL_BSIZE3_MASK))\n * where value0 = [128..16256],  default=256\n *       value1 = [1024..64512], default=4096\n *       value2 = [0..64512],    default=4096\n *       value3 = [0..64512],    default=0\n */\n\n#define E1000_PSRCTL_BSIZE0_MASK\t0x0000007F\n#define E1000_PSRCTL_BSIZE1_MASK\t0x00003F00\n#define E1000_PSRCTL_BSIZE2_MASK\t0x003F0000\n#define E1000_PSRCTL_BSIZE3_MASK\t0x3F000000\n\n#define E1000_PSRCTL_BSIZE0_SHIFT\t7    /* Shift _right_ 7 */\n#define E1000_PSRCTL_BSIZE1_SHIFT\t2    /* Shift _right_ 2 */\n#define E1000_PSRCTL_BSIZE2_SHIFT\t6    /* Shift _left_ 6 */\n#define E1000_PSRCTL_BSIZE3_SHIFT\t14   /* Shift _left_ 14 */\n\n/* SWFW_SYNC Definitions */\n#define E1000_SWFW_EEP_SM\t0x01\n#define E1000_SWFW_PHY0_SM\t0x02\n#define E1000_SWFW_PHY1_SM\t0x04\n#define E1000_SWFW_CSR_SM\t0x08\n#define E1000_SWFW_PHY2_SM\t0x20\n#define E1000_SWFW_PHY3_SM\t0x40\n#define E1000_SWFW_SW_MNG_SM\t0x400\n\n/* Device Control */\n#define E1000_CTRL_FD\t\t0x00000001  /* Full duplex.0=half; 1=full */\n#define E1000_CTRL_PRIOR\t0x00000004  /* Priority on PCI. 0=rx,1=fair */\n#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */\n#define E1000_CTRL_LRST\t\t0x00000008  /* Link reset. 0=normal,1=reset */\n#define E1000_CTRL_ASDE\t\t0x00000020  /* Auto-speed detect enable */\n#define E1000_CTRL_SLU\t\t0x00000040  /* Set link up (Force Link) */\n#define E1000_CTRL_ILOS\t\t0x00000080  /* Invert Loss-Of Signal */\n#define E1000_CTRL_SPD_SEL\t0x00000300  /* Speed Select Mask */\n#define E1000_CTRL_SPD_10\t0x00000000  /* Force 10Mb */\n#define E1000_CTRL_SPD_100\t0x00000100  /* Force 100Mb */\n#define E1000_CTRL_SPD_1000\t0x00000200  /* Force 1Gb */\n#define E1000_CTRL_FRCSPD\t0x00000800  /* Force Speed */\n#define E1000_CTRL_FRCDPX\t0x00001000  /* Force Duplex */\n#define E1000_CTRL_LANPHYPC_OVERRIDE\t0x00010000 /* SW control of LANPHYPC */\n#define E1000_CTRL_LANPHYPC_VALUE\t0x00020000 /* SW value of LANPHYPC */\n#define E1000_CTRL_MEHE\t\t0x00080000 /* Memory Error Handling Enable */\n#define E1000_CTRL_SWDPIN0\t0x00040000 /* SWDPIN 0 value */\n#define E1000_CTRL_SWDPIN1\t0x00080000 /* SWDPIN 1 value */\n#define E1000_CTRL_SWDPIN2\t0x00100000 /* SWDPIN 2 value */\n#define E1000_CTRL_ADVD3WUC\t0x00100000 /* D3 WUC */\n#define E1000_CTRL_EN_PHY_PWR_MGMT\t0x00200000 /* PHY PM enable */\n#define E1000_CTRL_SWDPIN3\t0x00200000 /* SWDPIN 3 value */\n#define E1000_CTRL_SWDPIO0\t0x00400000 /* SWDPIN 0 Input or output */\n#define E1000_CTRL_SWDPIO2\t0x01000000 /* SWDPIN 2 input or output */\n#define E1000_CTRL_SWDPIO3\t0x02000000 /* SWDPIN 3 input or output */\n#define E1000_CTRL_RST\t\t0x04000000 /* Global reset */\n#define E1000_CTRL_RFCE\t\t0x08000000 /* Receive Flow Control enable */\n#define E1000_CTRL_TFCE\t\t0x10000000 /* Transmit flow control enable */\n#define E1000_CTRL_VME\t\t0x40000000 /* IEEE VLAN mode enable */\n#define E1000_CTRL_PHY_RST\t0x80000000 /* PHY Reset */\n#define E1000_CTRL_I2C_ENA\t0x02000000 /* I2C enable */\n\n#define E1000_CTRL_MDIO_DIR\t\tE1000_CTRL_SWDPIO2\n#define E1000_CTRL_MDIO\t\t\tE1000_CTRL_SWDPIN2\n#define E1000_CTRL_MDC_DIR\t\tE1000_CTRL_SWDPIO3\n#define E1000_CTRL_MDC\t\t\tE1000_CTRL_SWDPIN3\n\n#define E1000_CONNSW_ENRGSRC\t\t0x4\n#define E1000_CONNSW_PHYSD\t\t0x400\n#define E1000_CONNSW_PHY_PDN\t\t0x800\n#define E1000_CONNSW_SERDESD\t\t0x200\n#define E1000_CONNSW_AUTOSENSE_CONF\t0x2\n#define E1000_CONNSW_AUTOSENSE_EN\t0x1\n#define E1000_PCS_CFG_PCS_EN\t\t8\n#define E1000_PCS_LCTL_FLV_LINK_UP\t1\n#define E1000_PCS_LCTL_FSV_10\t\t0\n#define E1000_PCS_LCTL_FSV_100\t\t2\n#define E1000_PCS_LCTL_FSV_1000\t\t4\n#define E1000_PCS_LCTL_FDV_FULL\t\t8\n#define E1000_PCS_LCTL_FSD\t\t0x10\n#define E1000_PCS_LCTL_FORCE_LINK\t0x20\n#define E1000_PCS_LCTL_FORCE_FCTRL\t0x80\n#define E1000_PCS_LCTL_AN_ENABLE\t0x10000\n#define E1000_PCS_LCTL_AN_RESTART\t0x20000\n#define E1000_PCS_LCTL_AN_TIMEOUT\t0x40000\n#define E1000_ENABLE_SERDES_LOOPBACK\t0x0410\n\n#define E1000_PCS_LSTS_LINK_OK\t\t1\n#define E1000_PCS_LSTS_SPEED_100\t2\n#define E1000_PCS_LSTS_SPEED_1000\t4\n#define E1000_PCS_LSTS_DUPLEX_FULL\t8\n#define E1000_PCS_LSTS_SYNK_OK\t\t0x10\n#define E1000_PCS_LSTS_AN_COMPLETE\t0x10000\n\n/* Device Status */\n#define E1000_STATUS_FD\t\t\t0x00000001 /* Duplex 0=half 1=full */\n#define E1000_STATUS_LU\t\t\t0x00000002 /* Link up.0=no,1=link */\n#define E1000_STATUS_FUNC_MASK\t\t0x0000000C /* PCI Function Mask */\n#define E1000_STATUS_FUNC_SHIFT\t\t2\n#define E1000_STATUS_FUNC_1\t\t0x00000004 /* Function 1 */\n#define E1000_STATUS_TXOFF\t\t0x00000010 /* transmission paused */\n#define E1000_STATUS_SPEED_MASK\t0x000000C0\n#define E1000_STATUS_SPEED_10\t\t0x00000000 /* Speed 10Mb/s */\n#define E1000_STATUS_SPEED_100\t\t0x00000040 /* Speed 100Mb/s */\n#define E1000_STATUS_SPEED_1000\t\t0x00000080 /* Speed 1000Mb/s */\n#define E1000_STATUS_LAN_INIT_DONE\t0x00000200 /* Lan Init Compltn by NVM */\n#define E1000_STATUS_PHYRA\t\t0x00000400 /* PHY Reset Asserted */\n#define E1000_STATUS_GIO_MASTER_ENABLE\t0x00080000 /* Master request status */\n#define E1000_STATUS_PCI66\t\t0x00000800 /* In 66Mhz slot */\n#define E1000_STATUS_BUS64\t\t0x00001000 /* In 64 bit slot */\n#define E1000_STATUS_2P5_SKU\t\t0x00001000 /* Val of 2.5GBE SKU strap */\n#define E1000_STATUS_2P5_SKU_OVER\t0x00002000 /* Val of 2.5GBE SKU Over */\n#define E1000_STATUS_PCIX_MODE\t\t0x00002000 /* PCI-X mode */\n#define E1000_STATUS_PCIX_SPEED\t\t0x0000C000 /* PCI-X bus speed */\n\n/* Constants used to interpret the masked PCI-X bus speed. */\n#define E1000_STATUS_PCIX_SPEED_66\t0x00000000 /* PCI-X bus spd 50-66MHz */\n#define E1000_STATUS_PCIX_SPEED_100\t0x00004000 /* PCI-X bus spd 66-100MHz */\n#define E1000_STATUS_PCIX_SPEED_133\t0x00008000 /* PCI-X bus spd 100-133MHz*/\n\n#define SPEED_10\t10\n#define SPEED_100\t100\n#define SPEED_1000\t1000\n#define SPEED_2500\t2500\n#define HALF_DUPLEX\t1\n#define FULL_DUPLEX\t2\n\n#define PHY_FORCE_TIME\t20\n\n#define ADVERTISE_10_HALF\t\t0x0001\n#define ADVERTISE_10_FULL\t\t0x0002\n#define ADVERTISE_100_HALF\t\t0x0004\n#define ADVERTISE_100_FULL\t\t0x0008\n#define ADVERTISE_1000_HALF\t\t0x0010 /* Not used, just FYI */\n#define ADVERTISE_1000_FULL\t\t0x0020\n\n/* 1000/H is not supported, nor spec-compliant. */\n#define E1000_ALL_SPEED_DUPLEX\t( \\\n\tADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \\\n\tADVERTISE_100_FULL | ADVERTISE_1000_FULL)\n#define E1000_ALL_NOT_GIG\t( \\\n\tADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | \\\n\tADVERTISE_100_FULL)\n#define E1000_ALL_100_SPEED\t(ADVERTISE_100_HALF | ADVERTISE_100_FULL)\n#define E1000_ALL_10_SPEED\t(ADVERTISE_10_HALF | ADVERTISE_10_FULL)\n#define E1000_ALL_HALF_DUPLEX\t(ADVERTISE_10_HALF | ADVERTISE_100_HALF)\n\n#define AUTONEG_ADVERTISE_SPEED_DEFAULT\t\tE1000_ALL_SPEED_DUPLEX\n\n/* LED Control */\n#define E1000_PHY_LED0_MODE_MASK\t0x00000007\n#define E1000_PHY_LED0_IVRT\t\t0x00000008\n#define E1000_PHY_LED0_MASK\t\t0x0000001F\n\n#define E1000_LEDCTL_LED0_MODE_MASK\t0x0000000F\n#define E1000_LEDCTL_LED0_MODE_SHIFT\t0\n#define E1000_LEDCTL_LED0_IVRT\t\t0x00000040\n#define E1000_LEDCTL_LED0_BLINK\t\t0x00000080\n\n#define E1000_LEDCTL_MODE_LINK_UP\t0x2\n#define E1000_LEDCTL_MODE_LED_ON\t0xE\n#define E1000_LEDCTL_MODE_LED_OFF\t0xF\n\n/* Transmit Descriptor bit definitions */\n#define E1000_TXD_DTYP_D\t0x00100000 /* Data Descriptor */\n#define E1000_TXD_DTYP_C\t0x00000000 /* Context Descriptor */\n#define E1000_TXD_POPTS_IXSM\t0x01       /* Insert IP checksum */\n#define E1000_TXD_POPTS_TXSM\t0x02       /* Insert TCP/UDP checksum */\n#define E1000_TXD_CMD_EOP\t0x01000000 /* End of Packet */\n#define E1000_TXD_CMD_IFCS\t0x02000000 /* Insert FCS (Ethernet CRC) */\n#define E1000_TXD_CMD_IC\t0x04000000 /* Insert Checksum */\n#define E1000_TXD_CMD_RS\t0x08000000 /* Report Status */\n#define E1000_TXD_CMD_RPS\t0x10000000 /* Report Packet Sent */\n#define E1000_TXD_CMD_DEXT\t0x20000000 /* Desc extension (0 = legacy) */\n#define E1000_TXD_CMD_VLE\t0x40000000 /* Add VLAN tag */\n#define E1000_TXD_CMD_IDE\t0x80000000 /* Enable Tidv register */\n#define E1000_TXD_STAT_DD\t0x00000001 /* Descriptor Done */\n#define E1000_TXD_STAT_EC\t0x00000002 /* Excess Collisions */\n#define E1000_TXD_STAT_LC\t0x00000004 /* Late Collisions */\n#define E1000_TXD_STAT_TU\t0x00000008 /* Transmit underrun */\n#define E1000_TXD_CMD_TCP\t0x01000000 /* TCP packet */\n#define E1000_TXD_CMD_IP\t0x02000000 /* IP packet */\n#define E1000_TXD_CMD_TSE\t0x04000000 /* TCP Seg enable */\n#define E1000_TXD_STAT_TC\t0x00000004 /* Tx Underrun */\n#define E1000_TXD_EXTCMD_TSTAMP\t0x00000010 /* IEEE1588 Timestamp packet */\n\n/* Transmit Control */\n#define E1000_TCTL_EN\t\t0x00000002 /* enable Tx */\n#define E1000_TCTL_PSP\t\t0x00000008 /* pad short packets */\n#define E1000_TCTL_CT\t\t0x00000ff0 /* collision threshold */\n#define E1000_TCTL_COLD\t\t0x003ff000 /* collision distance */\n#define E1000_TCTL_RTLC\t\t0x01000000 /* Re-transmit on late collision */\n#define E1000_TCTL_MULR\t\t0x10000000 /* Multiple request support */\n\n/* Transmit Arbitration Count */\n#define E1000_TARC0_ENABLE\t0x00000400 /* Enable Tx Queue 0 */\n\n/* SerDes Control */\n#define E1000_SCTL_DISABLE_SERDES_LOOPBACK\t0x0400\n#define E1000_SCTL_ENABLE_SERDES_LOOPBACK\t0x0410\n\n/* Receive Checksum Control */\n#define E1000_RXCSUM_IPOFL\t0x00000100 /* IPv4 checksum offload */\n#define E1000_RXCSUM_TUOFL\t0x00000200 /* TCP / UDP checksum offload */\n#define E1000_RXCSUM_CRCOFL\t0x00000800 /* CRC32 offload enable */\n#define E1000_RXCSUM_IPPCSE\t0x00001000 /* IP payload checksum enable */\n#define E1000_RXCSUM_PCSD\t0x00002000 /* packet checksum disabled */\n\n/* Header split receive */\n#define E1000_RFCTL_NFSW_DIS\t\t0x00000040\n#define E1000_RFCTL_NFSR_DIS\t\t0x00000080\n#define E1000_RFCTL_ACK_DIS\t\t0x00001000\n#define E1000_RFCTL_EXTEN\t\t0x00008000\n#define E1000_RFCTL_IPV6_EX_DIS\t\t0x00010000\n#define E1000_RFCTL_NEW_IPV6_EXT_DIS\t0x00020000\n#define E1000_RFCTL_LEF\t\t\t0x00040000\n\n/* Collision related configuration parameters */\n#define E1000_COLLISION_THRESHOLD\t15\n#define E1000_CT_SHIFT\t\t\t4\n#define E1000_COLLISION_DISTANCE\t63\n#define E1000_COLD_SHIFT\t\t12\n\n/* Default values for the transmit IPG register */\n#define DEFAULT_82542_TIPG_IPGT\t\t10\n#define DEFAULT_82543_TIPG_IPGT_FIBER\t9\n#define DEFAULT_82543_TIPG_IPGT_COPPER\t8\n\n#define E1000_TIPG_IPGT_MASK\t\t0x000003FF\n\n#define DEFAULT_82542_TIPG_IPGR1\t2\n#define DEFAULT_82543_TIPG_IPGR1\t8\n#define E1000_TIPG_IPGR1_SHIFT\t\t10\n\n#define DEFAULT_82542_TIPG_IPGR2\t10\n#define DEFAULT_82543_TIPG_IPGR2\t6\n#define DEFAULT_80003ES2LAN_TIPG_IPGR2\t7\n#define E1000_TIPG_IPGR2_SHIFT\t\t20\n\n/* Ethertype field values */\n#define ETHERNET_IEEE_VLAN_TYPE\t\t0x8100  /* 802.3ac packet */\n\n#define ETHERNET_FCS_SIZE\t\t4\n#define MAX_JUMBO_FRAME_SIZE\t\t0x3F00\n/* The datasheet maximum supported RX size is 9.5KB (9728 bytes) */\n#define MAX_RX_JUMBO_FRAME_SIZE\t\t0x2600\n#define E1000_TX_PTR_GAP\t\t0x1F\n\n/* Extended Configuration Control and Size */\n#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP\t0x00000020\n#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE\t0x00000001\n#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE\t0x00000008\n#define E1000_EXTCNF_CTRL_SWFLAG\t\t0x00000020\n#define E1000_EXTCNF_CTRL_GATE_PHY_CFG\t\t0x00000080\n#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK\t0x00FF0000\n#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT\t16\n#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK\t0x0FFF0000\n#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT\t16\n\n#define E1000_PHY_CTRL_D0A_LPLU\t\t\t0x00000002\n#define E1000_PHY_CTRL_NOND0A_LPLU\t\t0x00000004\n#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE\t0x00000008\n#define E1000_PHY_CTRL_GBE_DISABLE\t\t0x00000040\n\n#define E1000_KABGTXD_BGSQLBIAS\t\t\t0x00050000\n\n/* Low Power IDLE Control */\n#define E1000_LPIC_LPIET_SHIFT\t\t24\t/* Low Power Idle Entry Time */\n\n/* PBA constants */\n#define E1000_PBA_8K\t\t0x0008    /* 8KB */\n#define E1000_PBA_10K\t\t0x000A    /* 10KB */\n#define E1000_PBA_12K\t\t0x000C    /* 12KB */\n#define E1000_PBA_14K\t\t0x000E    /* 14KB */\n#define E1000_PBA_16K\t\t0x0010    /* 16KB */\n#define E1000_PBA_18K\t\t0x0012\n#define E1000_PBA_20K\t\t0x0014\n#define E1000_PBA_22K\t\t0x0016\n#define E1000_PBA_24K\t\t0x0018\n#define E1000_PBA_26K\t\t0x001A\n#define E1000_PBA_30K\t\t0x001E\n#define E1000_PBA_32K\t\t0x0020\n#define E1000_PBA_34K\t\t0x0022\n#define E1000_PBA_35K\t\t0x0023\n#define E1000_PBA_38K\t\t0x0026\n#define E1000_PBA_40K\t\t0x0028\n#define E1000_PBA_48K\t\t0x0030    /* 48KB */\n#define E1000_PBA_64K\t\t0x0040    /* 64KB */\n\n#define E1000_PBA_RXA_MASK\t0xFFFF\n\n#define E1000_PBS_16K\t\tE1000_PBA_16K\n\n/* Uncorrectable/correctable ECC Error counts and enable bits */\n#define E1000_PBECCSTS_CORR_ERR_CNT_MASK\t0x000000FF\n#define E1000_PBECCSTS_UNCORR_ERR_CNT_MASK\t0x0000FF00\n#define E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT\t8\n#define E1000_PBECCSTS_ECC_ENABLE\t\t0x00010000\n\n#define IFS_MAX\t\t\t80\n#define IFS_MIN\t\t\t40\n#define IFS_RATIO\t\t4\n#define IFS_STEP\t\t10\n#define MIN_NUM_XMITS\t\t1000\n\n/* SW Semaphore Register */\n#define E1000_SWSM_SMBI\t\t0x00000001 /* Driver Semaphore bit */\n#define E1000_SWSM_SWESMBI\t0x00000002 /* FW Semaphore bit */\n#define E1000_SWSM_DRV_LOAD\t0x00000008 /* Driver Loaded Bit */\n\n#define E1000_SWSM2_LOCK\t0x00000002 /* Secondary driver semaphore bit */\n\n/* Interrupt Cause Read */\n#define E1000_ICR_TXDW\t\t0x00000001 /* Transmit desc written back */\n#define E1000_ICR_TXQE\t\t0x00000002 /* Transmit Queue empty */\n#define E1000_ICR_LSC\t\t0x00000004 /* Link Status Change */\n#define E1000_ICR_RXSEQ\t\t0x00000008 /* Rx sequence error */\n#define E1000_ICR_RXDMT0\t0x00000010 /* Rx desc min. threshold (0) */\n#define E1000_ICR_RXO\t\t0x00000040 /* Rx overrun */\n#define E1000_ICR_RXT0\t\t0x00000080 /* Rx timer intr (ring 0) */\n#define E1000_ICR_VMMB\t\t0x00000100 /* VM MB event */\n#define E1000_ICR_RXCFG\t\t0x00000400 /* Rx /c/ ordered set */\n#define E1000_ICR_GPI_EN0\t0x00000800 /* GP Int 0 */\n#define E1000_ICR_GPI_EN1\t0x00001000 /* GP Int 1 */\n#define E1000_ICR_GPI_EN2\t0x00002000 /* GP Int 2 */\n#define E1000_ICR_GPI_EN3\t0x00004000 /* GP Int 3 */\n#define E1000_ICR_TXD_LOW\t0x00008000\n#define E1000_ICR_MNG\t\t0x00040000 /* Manageability event */\n#define E1000_ICR_ECCER\t\t0x00400000 /* Uncorrectable ECC Error */\n#define E1000_ICR_TS\t\t0x00080000 /* Time Sync Interrupt */\n#define E1000_ICR_DRSTA\t\t0x40000000 /* Device Reset Asserted */\n/* If this bit asserted, the driver should claim the interrupt */\n#define E1000_ICR_INT_ASSERTED\t0x80000000\n#define E1000_ICR_DOUTSYNC\t0x10000000 /* NIC DMA out of sync */\n#define E1000_ICR_RXQ0\t\t0x00100000 /* Rx Queue 0 Interrupt */\n#define E1000_ICR_RXQ1\t\t0x00200000 /* Rx Queue 1 Interrupt */\n#define E1000_ICR_TXQ0\t\t0x00400000 /* Tx Queue 0 Interrupt */\n#define E1000_ICR_TXQ1\t\t0x00800000 /* Tx Queue 1 Interrupt */\n#define E1000_ICR_OTHER\t\t0x01000000 /* Other Interrupts */\n#define E1000_ICR_FER\t\t0x00400000 /* Fatal Error */\n\n#define E1000_ICR_THS\t\t0x00800000 /* ICR.THS: Thermal Sensor Event*/\n#define E1000_ICR_MDDET\t\t0x10000000 /* Malicious Driver Detect */\n\n#define E1000_ITR_MASK\t\t0x000FFFFF /* ITR value bitfield */\n#define E1000_ITR_MULT\t\t256 /* ITR mulitplier in nsec */\n\n/* PBA ECC Register */\n#define E1000_PBA_ECC_COUNTER_MASK\t0xFFF00000 /* ECC counter mask */\n#define E1000_PBA_ECC_COUNTER_SHIFT\t20 /* ECC counter shift value */\n#define E1000_PBA_ECC_CORR_EN\t0x00000001 /* Enable ECC error correction */\n#define E1000_PBA_ECC_STAT_CLR\t0x00000002 /* Clear ECC error counter */\n#define E1000_PBA_ECC_INT_EN\t0x00000004 /* Enable ICR bit 5 on ECC error */\n\n/* Extended Interrupt Cause Read */\n#define E1000_EICR_RX_QUEUE0\t0x00000001 /* Rx Queue 0 Interrupt */\n#define E1000_EICR_RX_QUEUE1\t0x00000002 /* Rx Queue 1 Interrupt */\n#define E1000_EICR_RX_QUEUE2\t0x00000004 /* Rx Queue 2 Interrupt */\n#define E1000_EICR_RX_QUEUE3\t0x00000008 /* Rx Queue 3 Interrupt */\n#define E1000_EICR_TX_QUEUE0\t0x00000100 /* Tx Queue 0 Interrupt */\n#define E1000_EICR_TX_QUEUE1\t0x00000200 /* Tx Queue 1 Interrupt */\n#define E1000_EICR_TX_QUEUE2\t0x00000400 /* Tx Queue 2 Interrupt */\n#define E1000_EICR_TX_QUEUE3\t0x00000800 /* Tx Queue 3 Interrupt */\n#define E1000_EICR_TCP_TIMER\t0x40000000 /* TCP Timer */\n#define E1000_EICR_OTHER\t0x80000000 /* Interrupt Cause Active */\n/* TCP Timer */\n#define E1000_TCPTIMER_KS\t0x00000100 /* KickStart */\n#define E1000_TCPTIMER_COUNT_ENABLE\t0x00000200 /* Count Enable */\n#define E1000_TCPTIMER_COUNT_FINISH\t0x00000400 /* Count finish */\n#define E1000_TCPTIMER_LOOP\t0x00000800 /* Loop */\n\n/* This defines the bits that are set in the Interrupt Mask\n * Set/Read Register.  Each bit is documented below:\n *   o RXT0   = Receiver Timer Interrupt (ring 0)\n *   o TXDW   = Transmit Descriptor Written Back\n *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)\n *   o RXSEQ  = Receive Sequence Error\n *   o LSC    = Link Status Change\n */\n#define IMS_ENABLE_MASK ( \\\n\tE1000_IMS_RXT0   |    \\\n\tE1000_IMS_TXDW   |    \\\n\tE1000_IMS_RXDMT0 |    \\\n\tE1000_IMS_RXSEQ  |    \\\n\tE1000_IMS_LSC)\n\n/* Interrupt Mask Set */\n#define E1000_IMS_TXDW\t\tE1000_ICR_TXDW    /* Tx desc written back */\n#define E1000_IMS_TXQE\t\tE1000_ICR_TXQE    /* Transmit Queue empty */\n#define E1000_IMS_LSC\t\tE1000_ICR_LSC     /* Link Status Change */\n#define E1000_IMS_VMMB\t\tE1000_ICR_VMMB    /* Mail box activity */\n#define E1000_IMS_RXSEQ\t\tE1000_ICR_RXSEQ   /* Rx sequence error */\n#define E1000_IMS_RXDMT0\tE1000_ICR_RXDMT0  /* Rx desc min. threshold */\n#define E1000_IMS_RXO\t\tE1000_ICR_RXO     /* Rx overrun */\n#define E1000_IMS_RXT0\t\tE1000_ICR_RXT0    /* Rx timer intr */\n#define E1000_IMS_TXD_LOW\tE1000_ICR_TXD_LOW\n#define E1000_IMS_ECCER\t\tE1000_ICR_ECCER   /* Uncorrectable ECC Error */\n#define E1000_IMS_TS\t\tE1000_ICR_TS      /* Time Sync Interrupt */\n#define E1000_IMS_DRSTA\t\tE1000_ICR_DRSTA   /* Device Reset Asserted */\n#define E1000_IMS_DOUTSYNC\tE1000_ICR_DOUTSYNC /* NIC DMA out of sync */\n#define E1000_IMS_RXQ0\t\tE1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */\n#define E1000_IMS_RXQ1\t\tE1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */\n#define E1000_IMS_TXQ0\t\tE1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */\n#define E1000_IMS_TXQ1\t\tE1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */\n#define E1000_IMS_OTHER\t\tE1000_ICR_OTHER /* Other Interrupts */\n#define E1000_IMS_FER\t\tE1000_ICR_FER /* Fatal Error */\n\n#define E1000_IMS_THS\t\tE1000_ICR_THS /* ICR.TS: Thermal Sensor Event*/\n#define E1000_IMS_MDDET\t\tE1000_ICR_MDDET /* Malicious Driver Detect */\n/* Extended Interrupt Mask Set */\n#define E1000_EIMS_RX_QUEUE0\tE1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */\n#define E1000_EIMS_RX_QUEUE1\tE1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */\n#define E1000_EIMS_RX_QUEUE2\tE1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */\n#define E1000_EIMS_RX_QUEUE3\tE1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */\n#define E1000_EIMS_TX_QUEUE0\tE1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */\n#define E1000_EIMS_TX_QUEUE1\tE1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */\n#define E1000_EIMS_TX_QUEUE2\tE1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */\n#define E1000_EIMS_TX_QUEUE3\tE1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */\n#define E1000_EIMS_TCP_TIMER\tE1000_EICR_TCP_TIMER /* TCP Timer */\n#define E1000_EIMS_OTHER\tE1000_EICR_OTHER   /* Interrupt Cause Active */\n\n/* Interrupt Cause Set */\n#define E1000_ICS_LSC\t\tE1000_ICR_LSC       /* Link Status Change */\n#define E1000_ICS_RXSEQ\t\tE1000_ICR_RXSEQ     /* Rx sequence error */\n#define E1000_ICS_RXDMT0\tE1000_ICR_RXDMT0    /* Rx desc min. threshold */\n\n/* Extended Interrupt Cause Set */\n#define E1000_EICS_RX_QUEUE0\tE1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */\n#define E1000_EICS_RX_QUEUE1\tE1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */\n#define E1000_EICS_RX_QUEUE2\tE1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */\n#define E1000_EICS_RX_QUEUE3\tE1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */\n#define E1000_EICS_TX_QUEUE0\tE1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */\n#define E1000_EICS_TX_QUEUE1\tE1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */\n#define E1000_EICS_TX_QUEUE2\tE1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */\n#define E1000_EICS_TX_QUEUE3\tE1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */\n#define E1000_EICS_TCP_TIMER\tE1000_EICR_TCP_TIMER /* TCP Timer */\n#define E1000_EICS_OTHER\tE1000_EICR_OTHER   /* Interrupt Cause Active */\n\n#define E1000_EITR_ITR_INT_MASK\t0x0000FFFF\n/* E1000_EITR_CNT_IGNR is only for 82576 and newer */\n#define E1000_EITR_CNT_IGNR\t0x80000000 /* Don't reset counters on write */\n#define E1000_EITR_INTERVAL 0x00007FFC\n\n/* Transmit Descriptor Control */\n#define E1000_TXDCTL_PTHRESH\t0x0000003F /* TXDCTL Prefetch Threshold */\n#define E1000_TXDCTL_HTHRESH\t0x00003F00 /* TXDCTL Host Threshold */\n#define E1000_TXDCTL_WTHRESH\t0x003F0000 /* TXDCTL Writeback Threshold */\n#define E1000_TXDCTL_GRAN\t0x01000000 /* TXDCTL Granularity */\n#define E1000_TXDCTL_FULL_TX_DESC_WB\t0x01010000 /* GRAN=1, WTHRESH=1 */\n#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */\n/* Enable the counting of descriptors still to be processed. */\n#define E1000_TXDCTL_COUNT_DESC\t0x00400000\n\n/* Flow Control Constants */\n#define FLOW_CONTROL_ADDRESS_LOW\t0x00C28001\n#define FLOW_CONTROL_ADDRESS_HIGH\t0x00000100\n#define FLOW_CONTROL_TYPE\t\t0x8808\n\n/* 802.1q VLAN Packet Size */\n#define VLAN_TAG_SIZE\t\t\t4    /* 802.3ac tag (not DMA'd) */\n#define E1000_VLAN_FILTER_TBL_SIZE\t128  /* VLAN Filter Table (4096 bits) */\n\n/* Receive Address\n * Number of high/low register pairs in the RAR. The RAR (Receive Address\n * Registers) holds the directed and multicast addresses that we monitor.\n * Technically, we have 16 spots.  However, we reserve one of these spots\n * (RAR[15]) for our directed address used by controllers with\n * manageability enabled, allowing us room for 15 multicast addresses.\n */\n#define E1000_RAR_ENTRIES\t15\n#define E1000_RAH_AV\t\t0x80000000 /* Receive descriptor valid */\n#define E1000_RAL_MAC_ADDR_LEN\t4\n#define E1000_RAH_MAC_ADDR_LEN\t2\n#define E1000_RAH_QUEUE_MASK_82575\t0x000C0000\n#define E1000_RAH_POOL_1\t0x00040000\n\n/* Error Codes */\n#define E1000_SUCCESS\t\t\t0\n#define E1000_ERR_NVM\t\t\t1\n#define E1000_ERR_PHY\t\t\t2\n#define E1000_ERR_CONFIG\t\t3\n#define E1000_ERR_PARAM\t\t\t4\n#define E1000_ERR_MAC_INIT\t\t5\n#define E1000_ERR_PHY_TYPE\t\t6\n#define E1000_ERR_RESET\t\t\t9\n#define E1000_ERR_MASTER_REQUESTS_PENDING\t10\n#define E1000_ERR_HOST_INTERFACE_COMMAND\t11\n#define E1000_BLK_PHY_RESET\t\t12\n#define E1000_ERR_SWFW_SYNC\t\t13\n#define E1000_NOT_IMPLEMENTED\t\t14\n#define E1000_ERR_MBX\t\t\t15\n#define E1000_ERR_INVALID_ARGUMENT\t16\n#define E1000_ERR_NO_SPACE\t\t17\n#define E1000_ERR_NVM_PBA_SECTION\t18\n#define E1000_ERR_I2C\t\t\t19\n#define E1000_ERR_INVM_VALUE_NOT_FOUND\t20\n\n/* Loop limit on how long we wait for auto-negotiation to complete */\n#define FIBER_LINK_UP_LIMIT\t\t50\n#define COPPER_LINK_UP_LIMIT\t\t10\n#define PHY_AUTO_NEG_LIMIT\t\t45\n#define PHY_FORCE_LIMIT\t\t\t20\n/* Number of 100 microseconds we wait for PCI Express master disable */\n#define MASTER_DISABLE_TIMEOUT\t\t800\n/* Number of milliseconds we wait for PHY configuration done after MAC reset */\n#define PHY_CFG_TIMEOUT\t\t\t100\n/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */\n#define MDIO_OWNERSHIP_TIMEOUT\t\t10\n/* Number of milliseconds for NVM auto read done after MAC reset. */\n#define AUTO_READ_DONE_TIMEOUT\t\t10\n\n/* Flow Control */\n#define E1000_FCRTH_RTH\t\t0x0000FFF8 /* Mask Bits[15:3] for RTH */\n#define E1000_FCRTL_RTL\t\t0x0000FFF8 /* Mask Bits[15:3] for RTL */\n#define E1000_FCRTL_XONE\t0x80000000 /* Enable XON frame transmission */\n\n/* Transmit Configuration Word */\n#define E1000_TXCW_FD\t\t0x00000020 /* TXCW full duplex */\n#define E1000_TXCW_PAUSE\t0x00000080 /* TXCW sym pause request */\n#define E1000_TXCW_ASM_DIR\t0x00000100 /* TXCW astm pause direction */\n#define E1000_TXCW_PAUSE_MASK\t0x00000180 /* TXCW pause request mask */\n#define E1000_TXCW_ANE\t\t0x80000000 /* Auto-neg enable */\n\n/* Receive Configuration Word */\n#define E1000_RXCW_CW\t\t0x0000ffff /* RxConfigWord mask */\n#define E1000_RXCW_IV\t\t0x08000000 /* Receive config invalid */\n#define E1000_RXCW_C\t\t0x20000000 /* Receive config */\n#define E1000_RXCW_SYNCH\t0x40000000 /* Receive config synch */\n\n#define E1000_TSYNCTXCTL_VALID\t\t0x00000001 /* Tx timestamp valid */\n#define E1000_TSYNCTXCTL_ENABLED\t0x00000010 /* enable Tx timestamping */\n\n/* HH Time Sync */\n#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK\t0x0000F000 /* max delay */\n#define E1000_TSYNCTXCTL_SYNC_COMP_ERR\t\t0x20000000 /* sync err */\n#define E1000_TSYNCTXCTL_SYNC_COMP\t\t0x40000000 /* sync complete */\n#define E1000_TSYNCTXCTL_START_SYNC\t\t0x80000000 /* initiate sync */\n\n#define E1000_TSYNCRXCTL_VALID\t\t0x00000001 /* Rx timestamp valid */\n#define E1000_TSYNCRXCTL_TYPE_MASK\t0x0000000E /* Rx type mask */\n#define E1000_TSYNCRXCTL_TYPE_L2_V2\t0x00\n#define E1000_TSYNCRXCTL_TYPE_L4_V1\t0x02\n#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2\t0x04\n#define E1000_TSYNCRXCTL_TYPE_ALL\t0x08\n#define E1000_TSYNCRXCTL_TYPE_EVENT_V2\t0x0A\n#define E1000_TSYNCRXCTL_ENABLED\t0x00000010 /* enable Rx timestamping */\n#define E1000_TSYNCRXCTL_SYSCFI\t\t0x00000020 /* Sys clock frequency */\n\n#define E1000_RXMTRL_PTP_V1_SYNC_MESSAGE\t0x00000000\n#define E1000_RXMTRL_PTP_V1_DELAY_REQ_MESSAGE\t0x00010000\n\n#define E1000_RXMTRL_PTP_V2_SYNC_MESSAGE\t0x00000000\n#define E1000_RXMTRL_PTP_V2_DELAY_REQ_MESSAGE\t0x01000000\n\n#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK\t\t0x000000FF\n#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE\t\t0x00\n#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE\t0x01\n#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE\t0x02\n#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE\t0x03\n#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE\t0x04\n\n#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK\t\t0x00000F00\n#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE\t\t0x0000\n#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE\t0x0100\n#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE\t0x0200\n#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE\t0x0300\n#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE\t0x0800\n#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE\t0x0900\n#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE 0x0A00\n#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE\t0x0B00\n#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE\t0x0C00\n#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE\t0x0D00\n\n#define E1000_TIMINCA_16NS_SHIFT\t24\n#define E1000_TIMINCA_INCPERIOD_SHIFT\t24\n#define E1000_TIMINCA_INCVALUE_MASK\t0x00FFFFFF\n\n#define E1000_TSICR_TXTS\t\t0x00000002\n#define E1000_TSIM_TXTS\t\t\t0x00000002\n/* TUPLE Filtering Configuration */\n#define E1000_TTQF_DISABLE_MASK\t\t0xF0008000 /* TTQF Disable Mask */\n#define E1000_TTQF_QUEUE_ENABLE\t\t0x100   /* TTQF Queue Enable Bit */\n#define E1000_TTQF_PROTOCOL_MASK\t0xFF    /* TTQF Protocol Mask */\n/* TTQF TCP Bit, shift with E1000_TTQF_PROTOCOL SHIFT */\n#define E1000_TTQF_PROTOCOL_TCP\t\t0x0\n/* TTQF UDP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */\n#define E1000_TTQF_PROTOCOL_UDP\t\t0x1\n/* TTQF SCTP Bit, shift with E1000_TTQF_PROTOCOL_SHIFT */\n#define E1000_TTQF_PROTOCOL_SCTP\t0x2\n#define E1000_TTQF_PROTOCOL_SHIFT\t5       /* TTQF Protocol Shift */\n#define E1000_TTQF_QUEUE_SHIFT\t\t16      /* TTQF Queue Shfit */\n#define E1000_TTQF_RX_QUEUE_MASK\t0x70000 /* TTQF Queue Mask */\n#define E1000_TTQF_MASK_ENABLE\t\t0x10000000 /* TTQF Mask Enable Bit */\n#define E1000_IMIR_CLEAR_MASK\t\t0xF001FFFF /* IMIR Reg Clear Mask */\n#define E1000_IMIR_PORT_BYPASS\t\t0x20000 /* IMIR Port Bypass Bit */\n#define E1000_IMIR_PRIORITY_SHIFT\t29 /* IMIR Priority Shift */\n#define E1000_IMIREXT_CLEAR_MASK\t0x7FFFF /* IMIREXT Reg Clear Mask */\n\n#define E1000_MDICNFG_EXT_MDIO\t\t0x80000000 /* MDI ext/int destination */\n#define E1000_MDICNFG_COM_MDIO\t\t0x40000000 /* MDI shared w/ lan 0 */\n#define E1000_MDICNFG_PHY_MASK\t\t0x03E00000\n#define E1000_MDICNFG_PHY_SHIFT\t\t21\n\n#define E1000_MEDIA_PORT_COPPER\t\t\t1\n#define E1000_MEDIA_PORT_OTHER\t\t\t2\n#define E1000_M88E1112_AUTO_COPPER_SGMII\t0x2\n#define E1000_M88E1112_AUTO_COPPER_BASEX\t0x3\n#define E1000_M88E1112_STATUS_LINK\t\t0x0004 /* Interface Link Bit */\n#define E1000_M88E1112_MAC_CTRL_1\t\t0x10\n#define E1000_M88E1112_MAC_CTRL_1_MODE_MASK\t0x0380 /* Mode Select */\n#define E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT\t7\n#define E1000_M88E1112_PAGE_ADDR\t\t0x16\n#define E1000_M88E1112_STATUS\t\t\t0x01\n\n#define E1000_THSTAT_LOW_EVENT\t\t0x20000000 /* Low thermal threshold */\n#define E1000_THSTAT_MID_EVENT\t\t0x00200000 /* Mid thermal threshold */\n#define E1000_THSTAT_HIGH_EVENT\t\t0x00002000 /* High thermal threshold */\n#define E1000_THSTAT_PWR_DOWN\t\t0x00000001 /* Power Down Event */\n#define E1000_THSTAT_LINK_THROTTLE\t0x00000002 /* Link Spd Throttle Event */\n\n/* I350 EEE defines */\n#define E1000_IPCNFG_EEE_1G_AN\t\t0x00000008 /* IPCNFG EEE Ena 1G AN */\n#define E1000_IPCNFG_EEE_100M_AN\t0x00000004 /* IPCNFG EEE Ena 100M AN */\n#define E1000_EEER_TX_LPI_EN\t\t0x00010000 /* EEER Tx LPI Enable */\n#define E1000_EEER_RX_LPI_EN\t\t0x00020000 /* EEER Rx LPI Enable */\n#define E1000_EEER_LPI_FC\t\t0x00040000 /* EEER Ena on Flow Cntrl */\n/* EEE status */\n#define E1000_EEER_EEE_NEG\t\t0x20000000 /* EEE capability nego */\n#define E1000_EEER_RX_LPI_STATUS\t0x40000000 /* Rx in LPI state */\n#define E1000_EEER_TX_LPI_STATUS\t0x80000000 /* Tx in LPI state */\n#define E1000_EEE_LP_ADV_ADDR_I350\t0x040F     /* EEE LP Advertisement */\n#define E1000_M88E1543_PAGE_ADDR\t0x16       /* Page Offset Register */\n#define E1000_M88E1543_EEE_CTRL_1\t0x0\n#define E1000_M88E1543_EEE_CTRL_1_MS\t0x0001     /* EEE Master/Slave */\n#define E1000_M88E1543_FIBER_CTRL\t0x0        /* Fiber Control Register */\n#define E1000_EEE_ADV_DEV_I354\t\t7\n#define E1000_EEE_ADV_ADDR_I354\t\t60\n#define E1000_EEE_ADV_100_SUPPORTED\t(1 << 1)   /* 100BaseTx EEE Supported */\n#define E1000_EEE_ADV_1000_SUPPORTED\t(1 << 2)   /* 1000BaseT EEE Supported */\n#define E1000_PCS_STATUS_DEV_I354\t3\n#define E1000_PCS_STATUS_ADDR_I354\t1\n#define E1000_PCS_STATUS_RX_LPI_RCVD\t0x0400\n#define E1000_PCS_STATUS_TX_LPI_RCVD\t0x0800\n#define E1000_M88E1512_CFG_REG_1\t0x0010\n#define E1000_M88E1512_CFG_REG_2\t0x0011\n#define E1000_M88E1512_CFG_REG_3\t0x0007\n#define E1000_M88E1512_MODE\t\t0x0014\n#define E1000_EEE_SU_LPI_CLK_STP\t0x00800000 /* EEE LPI Clock Stop */\n#define E1000_EEE_LP_ADV_DEV_I210\t7          /* EEE LP Adv Device */\n#define E1000_EEE_LP_ADV_ADDR_I210\t61         /* EEE LP Adv Register */\n/* PCI Express Control */\n#define E1000_GCR_RXD_NO_SNOOP\t\t0x00000001\n#define E1000_GCR_RXDSCW_NO_SNOOP\t0x00000002\n#define E1000_GCR_RXDSCR_NO_SNOOP\t0x00000004\n#define E1000_GCR_TXD_NO_SNOOP\t\t0x00000008\n#define E1000_GCR_TXDSCW_NO_SNOOP\t0x00000010\n#define E1000_GCR_TXDSCR_NO_SNOOP\t0x00000020\n#define E1000_GCR_CMPL_TMOUT_MASK\t0x0000F000\n#define E1000_GCR_CMPL_TMOUT_10ms\t0x00001000\n#define E1000_GCR_CMPL_TMOUT_RESEND\t0x00010000\n#define E1000_GCR_CAP_VER2\t\t0x00040000\n\n#define PCIE_NO_SNOOP_ALL\t(E1000_GCR_RXD_NO_SNOOP | \\\n\t\t\t\t E1000_GCR_RXDSCW_NO_SNOOP | \\\n\t\t\t\t E1000_GCR_RXDSCR_NO_SNOOP | \\\n\t\t\t\t E1000_GCR_TXD_NO_SNOOP    | \\\n\t\t\t\t E1000_GCR_TXDSCW_NO_SNOOP | \\\n\t\t\t\t E1000_GCR_TXDSCR_NO_SNOOP)\n\n#define E1000_MMDAC_FUNC_DATA\t0x4000 /* Data, no post increment */\n\n/* mPHY address control and data registers */\n#define E1000_MPHY_ADDR_CTL\t\t0x0024 /* Address Control Reg */\n#define E1000_MPHY_ADDR_CTL_OFFSET_MASK\t0xFFFF0000\n#define E1000_MPHY_DATA\t\t\t0x0E10 /* Data Register */\n\n/* AFE CSR Offset for PCS CLK */\n#define E1000_MPHY_PCS_CLK_REG_OFFSET\t0x0004\n/* Override for near end digital loopback. */\n#define E1000_MPHY_PCS_CLK_REG_DIGINELBEN\t0x10\n\n/* PHY Control Register */\n#define MII_CR_SPEED_SELECT_MSB\t0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */\n#define MII_CR_COLL_TEST_ENABLE\t0x0080  /* Collision test enable */\n#define MII_CR_FULL_DUPLEX\t0x0100  /* FDX =1, half duplex =0 */\n#define MII_CR_RESTART_AUTO_NEG\t0x0200  /* Restart auto negotiation */\n#define MII_CR_ISOLATE\t\t0x0400  /* Isolate PHY from MII */\n#define MII_CR_POWER_DOWN\t0x0800  /* Power down */\n#define MII_CR_AUTO_NEG_EN\t0x1000  /* Auto Neg Enable */\n#define MII_CR_SPEED_SELECT_LSB\t0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */\n#define MII_CR_LOOPBACK\t\t0x4000  /* 0 = normal, 1 = loopback */\n#define MII_CR_RESET\t\t0x8000  /* 0 = normal, 1 = PHY reset */\n#define MII_CR_SPEED_1000\t0x0040\n#define MII_CR_SPEED_100\t0x2000\n#define MII_CR_SPEED_10\t\t0x0000\n\n/* PHY Status Register */\n#define MII_SR_EXTENDED_CAPS\t0x0001 /* Extended register capabilities */\n#define MII_SR_JABBER_DETECT\t0x0002 /* Jabber Detected */\n#define MII_SR_LINK_STATUS\t0x0004 /* Link Status 1 = link */\n#define MII_SR_AUTONEG_CAPS\t0x0008 /* Auto Neg Capable */\n#define MII_SR_REMOTE_FAULT\t0x0010 /* Remote Fault Detect */\n#define MII_SR_AUTONEG_COMPLETE\t0x0020 /* Auto Neg Complete */\n#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */\n#define MII_SR_EXTENDED_STATUS\t0x0100 /* Ext. status info in Reg 0x0F */\n#define MII_SR_100T2_HD_CAPS\t0x0200 /* 100T2 Half Duplex Capable */\n#define MII_SR_100T2_FD_CAPS\t0x0400 /* 100T2 Full Duplex Capable */\n#define MII_SR_10T_HD_CAPS\t0x0800 /* 10T   Half Duplex Capable */\n#define MII_SR_10T_FD_CAPS\t0x1000 /* 10T   Full Duplex Capable */\n#define MII_SR_100X_HD_CAPS\t0x2000 /* 100X  Half Duplex Capable */\n#define MII_SR_100X_FD_CAPS\t0x4000 /* 100X  Full Duplex Capable */\n#define MII_SR_100T4_CAPS\t0x8000 /* 100T4 Capable */\n\n/* Autoneg Advertisement Register */\n#define NWAY_AR_SELECTOR_FIELD\t0x0001   /* indicates IEEE 802.3 CSMA/CD */\n#define NWAY_AR_10T_HD_CAPS\t0x0020   /* 10T   Half Duplex Capable */\n#define NWAY_AR_10T_FD_CAPS\t0x0040   /* 10T   Full Duplex Capable */\n#define NWAY_AR_100TX_HD_CAPS\t0x0080   /* 100TX Half Duplex Capable */\n#define NWAY_AR_100TX_FD_CAPS\t0x0100   /* 100TX Full Duplex Capable */\n#define NWAY_AR_100T4_CAPS\t0x0200   /* 100T4 Capable */\n#define NWAY_AR_PAUSE\t\t0x0400   /* Pause operation desired */\n#define NWAY_AR_ASM_DIR\t\t0x0800   /* Asymmetric Pause Direction bit */\n#define NWAY_AR_REMOTE_FAULT\t0x2000   /* Remote Fault detected */\n#define NWAY_AR_NEXT_PAGE\t0x8000   /* Next Page ability supported */\n\n/* Link Partner Ability Register (Base Page) */\n#define NWAY_LPAR_SELECTOR_FIELD\t0x0000 /* LP protocol selector field */\n#define NWAY_LPAR_10T_HD_CAPS\t\t0x0020 /* LP 10T Half Dplx Capable */\n#define NWAY_LPAR_10T_FD_CAPS\t\t0x0040 /* LP 10T Full Dplx Capable */\n#define NWAY_LPAR_100TX_HD_CAPS\t\t0x0080 /* LP 100TX Half Dplx Capable */\n#define NWAY_LPAR_100TX_FD_CAPS\t\t0x0100 /* LP 100TX Full Dplx Capable */\n#define NWAY_LPAR_100T4_CAPS\t\t0x0200 /* LP is 100T4 Capable */\n#define NWAY_LPAR_PAUSE\t\t\t0x0400 /* LP Pause operation desired */\n#define NWAY_LPAR_ASM_DIR\t\t0x0800 /* LP Asym Pause Direction bit */\n#define NWAY_LPAR_REMOTE_FAULT\t\t0x2000 /* LP detected Remote Fault */\n#define NWAY_LPAR_ACKNOWLEDGE\t\t0x4000 /* LP rx'd link code word */\n#define NWAY_LPAR_NEXT_PAGE\t\t0x8000 /* Next Page ability supported */\n\n/* Autoneg Expansion Register */\n#define NWAY_ER_LP_NWAY_CAPS\t\t0x0001 /* LP has Auto Neg Capability */\n#define NWAY_ER_PAGE_RXD\t\t0x0002 /* LP 10T Half Dplx Capable */\n#define NWAY_ER_NEXT_PAGE_CAPS\t\t0x0004 /* LP 10T Full Dplx Capable */\n#define NWAY_ER_LP_NEXT_PAGE_CAPS\t0x0008 /* LP 100TX Half Dplx Capable */\n#define NWAY_ER_PAR_DETECT_FAULT\t0x0010 /* LP 100TX Full Dplx Capable */\n\n/* 1000BASE-T Control Register */\n#define CR_1000T_ASYM_PAUSE\t0x0080 /* Advertise asymmetric pause bit */\n#define CR_1000T_HD_CAPS\t0x0100 /* Advertise 1000T HD capability */\n#define CR_1000T_FD_CAPS\t0x0200 /* Advertise 1000T FD capability  */\n/* 1=Repeater/switch device port 0=DTE device */\n#define CR_1000T_REPEATER_DTE\t0x0400\n/* 1=Configure PHY as Master 0=Configure PHY as Slave */\n#define CR_1000T_MS_VALUE\t0x0800\n/* 1=Master/Slave manual config value 0=Automatic Master/Slave config */\n#define CR_1000T_MS_ENABLE\t0x1000\n#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */\n#define CR_1000T_TEST_MODE_1\t0x2000 /* Transmit Waveform test */\n#define CR_1000T_TEST_MODE_2\t0x4000 /* Master Transmit Jitter test */\n#define CR_1000T_TEST_MODE_3\t0x6000 /* Slave Transmit Jitter test */\n#define CR_1000T_TEST_MODE_4\t0x8000 /* Transmitter Distortion test */\n\n/* 1000BASE-T Status Register */\n#define SR_1000T_IDLE_ERROR_CNT\t\t0x00FF /* Num idle err since last rd */\n#define SR_1000T_ASYM_PAUSE_DIR\t\t0x0100 /* LP asym pause direction bit */\n#define SR_1000T_LP_HD_CAPS\t\t0x0400 /* LP is 1000T HD capable */\n#define SR_1000T_LP_FD_CAPS\t\t0x0800 /* LP is 1000T FD capable */\n#define SR_1000T_REMOTE_RX_STATUS\t0x1000 /* Remote receiver OK */\n#define SR_1000T_LOCAL_RX_STATUS\t0x2000 /* Local receiver OK */\n#define SR_1000T_MS_CONFIG_RES\t\t0x4000 /* 1=Local Tx Master, 0=Slave */\n#define SR_1000T_MS_CONFIG_FAULT\t0x8000 /* Master/Slave config fault */\n\n#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT\t5\n\n/* PHY 1000 MII Register/Bit Definitions */\n/* PHY Registers defined by IEEE */\n#define PHY_CONTROL\t\t0x00 /* Control Register */\n#define PHY_STATUS\t\t0x01 /* Status Register */\n#define PHY_ID1\t\t\t0x02 /* Phy Id Reg (word 1) */\n#define PHY_ID2\t\t\t0x03 /* Phy Id Reg (word 2) */\n#define PHY_AUTONEG_ADV\t\t0x04 /* Autoneg Advertisement */\n#define PHY_LP_ABILITY\t\t0x05 /* Link Partner Ability (Base Page) */\n#define PHY_AUTONEG_EXP\t\t0x06 /* Autoneg Expansion Reg */\n#define PHY_NEXT_PAGE_TX\t0x07 /* Next Page Tx */\n#define PHY_LP_NEXT_PAGE\t0x08 /* Link Partner Next Page */\n#define PHY_1000T_CTRL\t\t0x09 /* 1000Base-T Control Reg */\n#define PHY_1000T_STATUS\t0x0A /* 1000Base-T Status Reg */\n#define PHY_EXT_STATUS\t\t0x0F /* Extended Status Reg */\n\n#define PHY_CONTROL_LB\t\t0x4000 /* PHY Loopback bit */\n\n/* NVM Control */\n#define E1000_EECD_SK\t\t0x00000001 /* NVM Clock */\n#define E1000_EECD_CS\t\t0x00000002 /* NVM Chip Select */\n#define E1000_EECD_DI\t\t0x00000004 /* NVM Data In */\n#define E1000_EECD_DO\t\t0x00000008 /* NVM Data Out */\n#define E1000_EECD_REQ\t\t0x00000040 /* NVM Access Request */\n#define E1000_EECD_GNT\t\t0x00000080 /* NVM Access Grant */\n#define E1000_EECD_PRES\t\t0x00000100 /* NVM Present */\n#define E1000_EECD_SIZE\t\t0x00000200 /* NVM Size (0=64 word 1=256 word) */\n#define E1000_EECD_BLOCKED\t0x00008000 /* Bit banging access blocked flag */\n#define E1000_EECD_ABORT\t0x00010000 /* NVM operation aborted flag */\n#define E1000_EECD_TIMEOUT\t0x00020000 /* NVM read operation timeout flag */\n#define E1000_EECD_ERROR_CLR\t0x00040000 /* NVM error status clear bit */\n/* NVM Addressing bits based on type 0=small, 1=large */\n#define E1000_EECD_ADDR_BITS\t0x00000400\n#define E1000_EECD_TYPE\t\t0x00002000 /* NVM Type (1-SPI, 0-Microwire) */\n#define E1000_NVM_GRANT_ATTEMPTS\t1000 /* NVM # attempts to gain grant */\n#define E1000_EECD_AUTO_RD\t\t0x00000200  /* NVM Auto Read done */\n#define E1000_EECD_SIZE_EX_MASK\t\t0x00007800  /* NVM Size */\n#define E1000_EECD_SIZE_EX_SHIFT\t11\n#define E1000_EECD_FLUPD\t\t0x00080000 /* Update FLASH */\n#define E1000_EECD_AUPDEN\t\t0x00100000 /* Ena Auto FLASH update */\n#define E1000_EECD_SEC1VAL\t\t0x00400000 /* Sector One Valid */\n#define E1000_EECD_SEC1VAL_VALID_MASK\t(E1000_EECD_AUTO_RD | E1000_EECD_PRES)\n#define E1000_EECD_FLUPD_I210\t\t0x00800000 /* Update FLASH */\n#define E1000_EECD_FLUDONE_I210\t\t0x04000000 /* Update FLASH done */\n#define E1000_EECD_FLASH_DETECTED_I210\t0x00080000 /* FLASH detected */\n#define E1000_EECD_SEC1VAL_I210\t\t0x02000000 /* Sector One Valid */\n#define E1000_FLUDONE_ATTEMPTS\t\t20000\n#define E1000_EERD_EEWR_MAX_COUNT\t512 /* buffered EEPROM words rw */\n#define E1000_I210_FIFO_SEL_RX\t\t0x00\n#define E1000_I210_FIFO_SEL_TX_QAV(_i)\t(0x02 + (_i))\n#define E1000_I210_FIFO_SEL_TX_LEGACY\tE1000_I210_FIFO_SEL_TX_QAV(0)\n#define E1000_I210_FIFO_SEL_BMC2OS_TX\t0x06\n#define E1000_I210_FIFO_SEL_BMC2OS_RX\t0x01\n\n#define E1000_I210_FLASH_SECTOR_SIZE\t0x1000 /* 4KB FLASH sector unit size */\n/* Secure FLASH mode requires removing MSb */\n#define E1000_I210_FW_PTR_MASK\t\t0x7FFF\n/* Firmware code revision field word offset*/\n#define E1000_I210_FW_VER_OFFSET\t328\n\n#define E1000_NVM_RW_REG_DATA\t16  /* Offset to data in NVM read/write regs */\n#define E1000_NVM_RW_REG_DONE\t2   /* Offset to READ/WRITE done bit */\n#define E1000_NVM_RW_REG_START\t1   /* Start operation */\n#define E1000_NVM_RW_ADDR_SHIFT\t2   /* Shift to the address bits */\n#define E1000_NVM_POLL_WRITE\t1   /* Flag for polling for write complete */\n#define E1000_NVM_POLL_READ\t0   /* Flag for polling for read complete */\n#define E1000_FLASH_UPDATES\t2000\n\n/* NVM Word Offsets */\n#define NVM_COMPAT\t\t\t0x0003\n#define NVM_ID_LED_SETTINGS\t\t0x0004\n#define NVM_SERDES_AMPLITUDE\t\t0x0006 /* SERDES output amplitude */\n#define NVM_PHY_CLASS_WORD\t\t0x0007\n#define E1000_I210_NVM_FW_MODULE_PTR\t0x0010\n#define E1000_I350_NVM_FW_MODULE_PTR\t0x0051\n#define NVM_FUTURE_INIT_WORD1\t\t0x0019\n#define NVM_MAC_ADDR\t\t\t0x0000\n#define NVM_SUB_DEV_ID\t\t\t0x000B\n#define NVM_SUB_VEN_ID\t\t\t0x000C\n#define NVM_DEV_ID\t\t\t0x000D\n#define NVM_VEN_ID\t\t\t0x000E\n#define NVM_INIT_CTRL_2\t\t\t0x000F\n#define NVM_INIT_CTRL_4\t\t\t0x0013\n#define NVM_LED_1_CFG\t\t\t0x001C\n#define NVM_LED_0_2_CFG\t\t\t0x001F\n\n#define NVM_COMPAT_VALID_CSUM\t\t0x0001\n#define NVM_FUTURE_INIT_WORD1_VALID_CSUM\t0x0040\n\n#define NVM_INIT_CONTROL2_REG\t\t0x000F\n#define NVM_INIT_CONTROL3_PORT_B\t0x0014\n#define NVM_INIT_3GIO_3\t\t\t0x001A\n#define NVM_SWDEF_PINS_CTRL_PORT_0\t0x0020\n#define NVM_INIT_CONTROL3_PORT_A\t0x0024\n#define NVM_CFG\t\t\t\t0x0012\n#define NVM_ALT_MAC_ADDR_PTR\t\t0x0037\n#define NVM_CHECKSUM_REG\t\t0x003F\n#define NVM_COMPATIBILITY_REG_3\t\t0x0003\n#define NVM_COMPATIBILITY_BIT_MASK\t0x8000\n\n#define E1000_NVM_CFG_DONE_PORT_0\t0x040000 /* MNG config cycle done */\n#define E1000_NVM_CFG_DONE_PORT_1\t0x080000 /* ...for second port */\n#define E1000_NVM_CFG_DONE_PORT_2\t0x100000 /* ...for third port */\n#define E1000_NVM_CFG_DONE_PORT_3\t0x200000 /* ...for fourth port */\n\n#define NVM_82580_LAN_FUNC_OFFSET(a)\t((a) ? (0x40 + (0x40 * (a))) : 0)\n\n/* Mask bits for fields in Word 0x24 of the NVM */\n#define NVM_WORD24_COM_MDIO\t\t0x0008 /* MDIO interface shared */\n#define NVM_WORD24_EXT_MDIO\t\t0x0004 /* MDIO accesses routed extrnl */\n/* Offset of Link Mode bits for 82575/82576 */\n#define NVM_WORD24_LNK_MODE_OFFSET\t8\n/* Offset of Link Mode bits for 82580 up */\n#define NVM_WORD24_82580_LNK_MODE_OFFSET\t4\n\n\n/* Mask bits for fields in Word 0x0f of the NVM */\n#define NVM_WORD0F_PAUSE_MASK\t\t0x3000\n#define NVM_WORD0F_PAUSE\t\t0x1000\n#define NVM_WORD0F_ASM_DIR\t\t0x2000\n#define NVM_WORD0F_SWPDIO_EXT_MASK\t0x00F0\n\n/* Mask bits for fields in Word 0x1a of the NVM */\n#define NVM_WORD1A_ASPM_MASK\t\t0x000C\n\n/* Mask bits for fields in Word 0x03 of the EEPROM */\n#define NVM_COMPAT_LOM\t\t\t0x0800\n\n/* length of string needed to store PBA number */\n#define E1000_PBANUM_LENGTH\t\t11\n\n/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */\n#define NVM_SUM\t\t\t\t0xBABA\n\n/* PBA (printed board assembly) number words */\n#define NVM_PBA_OFFSET_0\t\t8\n#define NVM_PBA_OFFSET_1\t\t9\n#define NVM_PBA_PTR_GUARD\t\t0xFAFA\n#define NVM_RESERVED_WORD\t\t0xFFFF\n#define NVM_PHY_CLASS_A\t\t\t0x8000\n#define NVM_SERDES_AMPLITUDE_MASK\t0x000F\n#define NVM_SIZE_MASK\t\t\t0x1C00\n#define NVM_SIZE_SHIFT\t\t\t10\n#define NVM_WORD_SIZE_BASE_SHIFT\t6\n#define NVM_SWDPIO_EXT_SHIFT\t\t4\n\n/* NVM Commands - Microwire */\n#define NVM_READ_OPCODE_MICROWIRE\t0x6  /* NVM read opcode */\n#define NVM_WRITE_OPCODE_MICROWIRE\t0x5  /* NVM write opcode */\n#define NVM_ERASE_OPCODE_MICROWIRE\t0x7  /* NVM erase opcode */\n#define NVM_EWEN_OPCODE_MICROWIRE\t0x13 /* NVM erase/write enable */\n#define NVM_EWDS_OPCODE_MICROWIRE\t0x10 /* NVM erase/write disable */\n\n/* NVM Commands - SPI */\n#define NVM_MAX_RETRY_SPI\t5000 /* Max wait of 5ms, for RDY signal */\n#define NVM_READ_OPCODE_SPI\t0x03 /* NVM read opcode */\n#define NVM_WRITE_OPCODE_SPI\t0x02 /* NVM write opcode */\n#define NVM_A8_OPCODE_SPI\t0x08 /* opcode bit-3 = address bit-8 */\n#define NVM_WREN_OPCODE_SPI\t0x06 /* NVM set Write Enable latch */\n#define NVM_RDSR_OPCODE_SPI\t0x05 /* NVM read Status register */\n\n/* SPI NVM Status Register */\n#define NVM_STATUS_RDY_SPI\t0x01\n\n/* Word definitions for ID LED Settings */\n#define ID_LED_RESERVED_0000\t0x0000\n#define ID_LED_RESERVED_FFFF\t0xFFFF\n#define ID_LED_DEFAULT\t\t((ID_LED_OFF1_ON2  << 12) | \\\n\t\t\t\t (ID_LED_OFF1_OFF2 <<  8) | \\\n\t\t\t\t (ID_LED_DEF1_DEF2 <<  4) | \\\n\t\t\t\t (ID_LED_DEF1_DEF2))\n#define ID_LED_DEF1_DEF2\t0x1\n#define ID_LED_DEF1_ON2\t\t0x2\n#define ID_LED_DEF1_OFF2\t0x3\n#define ID_LED_ON1_DEF2\t\t0x4\n#define ID_LED_ON1_ON2\t\t0x5\n#define ID_LED_ON1_OFF2\t\t0x6\n#define ID_LED_OFF1_DEF2\t0x7\n#define ID_LED_OFF1_ON2\t\t0x8\n#define ID_LED_OFF1_OFF2\t0x9\n\n#define IGP_ACTIVITY_LED_MASK\t0xFFFFF0FF\n#define IGP_ACTIVITY_LED_ENABLE\t0x0300\n#define IGP_LED3_MODE\t\t0x07000000\n\n/* PCI/PCI-X/PCI-EX Config space */\n#define PCIX_COMMAND_REGISTER\t\t0xE6\n#define PCIX_STATUS_REGISTER_LO\t\t0xE8\n#define PCIX_STATUS_REGISTER_HI\t\t0xEA\n#define PCI_HEADER_TYPE_REGISTER\t0x0E\n#define PCIE_LINK_STATUS\t\t0x12\n#define PCIE_DEVICE_CONTROL2\t\t0x28\n\n#define PCIX_COMMAND_MMRBC_MASK\t\t0x000C\n#define PCIX_COMMAND_MMRBC_SHIFT\t0x2\n#define PCIX_STATUS_HI_MMRBC_MASK\t0x0060\n#define PCIX_STATUS_HI_MMRBC_SHIFT\t0x5\n#define PCIX_STATUS_HI_MMRBC_4K\t\t0x3\n#define PCIX_STATUS_HI_MMRBC_2K\t\t0x2\n#define PCIX_STATUS_LO_FUNC_MASK\t0x7\n#define PCI_HEADER_TYPE_MULTIFUNC\t0x80\n#define PCIE_LINK_WIDTH_MASK\t\t0x3F0\n#define PCIE_LINK_WIDTH_SHIFT\t\t4\n#define PCIE_LINK_SPEED_MASK\t\t0x0F\n#define PCIE_LINK_SPEED_2500\t\t0x01\n#define PCIE_LINK_SPEED_5000\t\t0x02\n#define PCIE_DEVICE_CONTROL2_16ms\t0x0005\n\n#ifndef ETH_ADDR_LEN\n#define ETH_ADDR_LEN\t\t\t6\n#endif\n\n#define PHY_REVISION_MASK\t\t0xFFFFFFF0\n#define MAX_PHY_REG_ADDRESS\t\t0x1F  /* 5 bit address bus (0-0x1F) */\n#define MAX_PHY_MULTI_PAGE_REG\t\t0xF\n\n/* Bit definitions for valid PHY IDs.\n * I = Integrated\n * E = External\n */\n#define M88E1000_E_PHY_ID\t0x01410C50\n#define M88E1000_I_PHY_ID\t0x01410C30\n#define M88E1011_I_PHY_ID\t0x01410C20\n#define IGP01E1000_I_PHY_ID\t0x02A80380\n#define M88E1111_I_PHY_ID\t0x01410CC0\n#define M88E1543_E_PHY_ID\t0x01410EA0\n#define M88E1512_E_PHY_ID\t0x01410DD0\n#define M88E1112_E_PHY_ID\t0x01410C90\n#define I347AT4_E_PHY_ID\t0x01410DC0\n#define M88E1340M_E_PHY_ID\t0x01410DF0\n#define GG82563_E_PHY_ID\t0x01410CA0\n#define IGP03E1000_E_PHY_ID\t0x02A80390\n#define IFE_E_PHY_ID\t\t0x02A80330\n#define IFE_PLUS_E_PHY_ID\t0x02A80320\n#define IFE_C_E_PHY_ID\t\t0x02A80310\n#define BME1000_E_PHY_ID\t0x01410CB0\n#define BME1000_E_PHY_ID_R2\t0x01410CB1\n#define I82577_E_PHY_ID\t\t0x01540050\n#define I82578_E_PHY_ID\t\t0x004DD040\n#define I82579_E_PHY_ID\t\t0x01540090\n#define I217_E_PHY_ID\t\t0x015400A0\n#define I82580_I_PHY_ID\t\t0x015403A0\n#define I350_I_PHY_ID\t\t0x015403B0\n#define I210_I_PHY_ID\t\t0x01410C00\n#define IGP04E1000_E_PHY_ID\t0x02A80391\n#define M88_VENDOR\t\t0x0141\n\n/* M88E1000 Specific Registers */\n#define M88E1000_PHY_SPEC_CTRL\t\t0x10  /* PHY Specific Control Reg */\n#define M88E1000_PHY_SPEC_STATUS\t0x11  /* PHY Specific Status Reg */\n#define M88E1000_EXT_PHY_SPEC_CTRL\t0x14  /* Extended PHY Specific Cntrl */\n#define M88E1000_RX_ERR_CNTR\t\t0x15  /* Receive Error Counter */\n\n#define M88E1000_PHY_EXT_CTRL\t\t0x1A  /* PHY extend control register */\n#define M88E1000_PHY_PAGE_SELECT\t0x1D  /* Reg 29 for pg number setting */\n#define M88E1000_PHY_GEN_CONTROL\t0x1E  /* meaning depends on reg 29 */\n#define M88E1000_PHY_VCO_REG_BIT8\t0x100 /* Bits 8 & 11 are adjusted for */\n#define M88E1000_PHY_VCO_REG_BIT11\t0x800 /* improved BER performance */\n\n/* M88E1000 PHY Specific Control Register */\n#define M88E1000_PSCR_POLARITY_REVERSAL\t0x0002 /* 1=Polarity Reverse enabled */\n/* MDI Crossover Mode bits 6:5 Manual MDI configuration */\n#define M88E1000_PSCR_MDI_MANUAL_MODE\t0x0000\n#define M88E1000_PSCR_MDIX_MANUAL_MODE\t0x0020  /* Manual MDIX configuration */\n/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */\n#define M88E1000_PSCR_AUTO_X_1000T\t0x0040\n/* Auto crossover enabled all speeds */\n#define M88E1000_PSCR_AUTO_X_MODE\t0x0060\n#define M88E1000_PSCR_ASSERT_CRS_ON_TX\t0x0800 /* 1=Assert CRS on Tx */\n\n/* M88E1000 PHY Specific Status Register */\n#define M88E1000_PSSR_REV_POLARITY\t0x0002 /* 1=Polarity reversed */\n#define M88E1000_PSSR_DOWNSHIFT\t\t0x0020 /* 1=Downshifted */\n#define M88E1000_PSSR_MDIX\t\t0x0040 /* 1=MDIX; 0=MDI */\n/* 0 = <50M\n * 1 = 50-80M\n * 2 = 80-110M\n * 3 = 110-140M\n * 4 = >140M\n */\n#define M88E1000_PSSR_CABLE_LENGTH\t0x0380\n#define M88E1000_PSSR_LINK\t\t0x0400 /* 1=Link up, 0=Link down */\n#define M88E1000_PSSR_SPD_DPLX_RESOLVED\t0x0800 /* 1=Speed & Duplex resolved */\n#define M88E1000_PSSR_DPLX\t\t0x2000 /* 1=Duplex 0=Half Duplex */\n#define M88E1000_PSSR_SPEED\t\t0xC000 /* Speed, bits 14:15 */\n#define M88E1000_PSSR_100MBS\t\t0x4000 /* 01=100Mbs */\n#define M88E1000_PSSR_1000MBS\t\t0x8000 /* 10=1000Mbs */\n\n#define M88E1000_PSSR_CABLE_LENGTH_SHIFT\t7\n\n/* Number of times we will attempt to autonegotiate before downshifting if we\n * are the master\n */\n#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK\t0x0C00\n#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X\t0x0000\n/* Number of times we will attempt to autonegotiate before downshifting if we\n * are the slave\n */\n#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK\t0x0300\n#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X\t0x0100\n#define M88E1000_EPSCR_TX_CLK_25\t0x0070 /* 25  MHz TX_CLK */\n\n/* Intel I347AT4 Registers */\n#define I347AT4_PCDL\t\t0x10 /* PHY Cable Diagnostics Length */\n#define I347AT4_PCDC\t\t0x15 /* PHY Cable Diagnostics Control */\n#define I347AT4_PAGE_SELECT\t0x16\n\n/* I347AT4 Extended PHY Specific Control Register */\n\n/* Number of times we will attempt to autonegotiate before downshifting if we\n * are the master\n */\n#define I347AT4_PSCR_DOWNSHIFT_ENABLE\t0x0800\n#define I347AT4_PSCR_DOWNSHIFT_MASK\t0x7000\n#define I347AT4_PSCR_DOWNSHIFT_1X\t0x0000\n#define I347AT4_PSCR_DOWNSHIFT_2X\t0x1000\n#define I347AT4_PSCR_DOWNSHIFT_3X\t0x2000\n#define I347AT4_PSCR_DOWNSHIFT_4X\t0x3000\n#define I347AT4_PSCR_DOWNSHIFT_5X\t0x4000\n#define I347AT4_PSCR_DOWNSHIFT_6X\t0x5000\n#define I347AT4_PSCR_DOWNSHIFT_7X\t0x6000\n#define I347AT4_PSCR_DOWNSHIFT_8X\t0x7000\n\n/* I347AT4 PHY Cable Diagnostics Control */\n#define I347AT4_PCDC_CABLE_LENGTH_UNIT\t0x0400 /* 0=cm 1=meters */\n\n/* M88E1112 only registers */\n#define M88E1112_VCT_DSP_DISTANCE\t0x001A\n\n/* M88EC018 Rev 2 specific DownShift settings */\n#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK\t0x0E00\n#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X\t0x0800\n\n#define I82578_EPSCR_DOWNSHIFT_ENABLE\t\t0x0020\n#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK\t0x001C\n\n/* BME1000 PHY Specific Control Register */\n#define BME1000_PSCR_ENABLE_DOWNSHIFT\t0x0800 /* 1 = enable downshift */\n\n/* Bits...\n * 15-5: page\n * 4-0: register offset\n */\n#define GG82563_PAGE_SHIFT\t5\n#define GG82563_REG(page, reg)\t\\\n\t(((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))\n#define GG82563_MIN_ALT_REG\t30\n\n/* GG82563 Specific Registers */\n#define GG82563_PHY_SPEC_CTRL\t\tGG82563_REG(0, 16) /* PHY Spec Cntrl */\n#define GG82563_PHY_PAGE_SELECT\t\tGG82563_REG(0, 22) /* Page Select */\n#define GG82563_PHY_SPEC_CTRL_2\t\tGG82563_REG(0, 26) /* PHY Spec Cntrl2 */\n#define GG82563_PHY_PAGE_SELECT_ALT\tGG82563_REG(0, 29) /* Alt Page Select */\n\n/* MAC Specific Control Register */\n#define GG82563_PHY_MAC_SPEC_CTRL\tGG82563_REG(2, 21)\n\n#define GG82563_PHY_DSP_DISTANCE\tGG82563_REG(5, 26) /* DSP Distance */\n\n/* Page 193 - Port Control Registers */\n/* Kumeran Mode Control */\n#define GG82563_PHY_KMRN_MODE_CTRL\tGG82563_REG(193, 16)\n#define GG82563_PHY_PWR_MGMT_CTRL\tGG82563_REG(193, 20) /* Pwr Mgt Ctrl */\n\n/* Page 194 - KMRN Registers */\n#define GG82563_PHY_INBAND_CTRL\t\tGG82563_REG(194, 18) /* Inband Ctrl */\n\n/* MDI Control */\n#define E1000_MDIC_REG_MASK\t0x001F0000\n#define E1000_MDIC_REG_SHIFT\t16\n#define E1000_MDIC_PHY_MASK\t0x03E00000\n#define E1000_MDIC_PHY_SHIFT\t21\n#define E1000_MDIC_OP_WRITE\t0x04000000\n#define E1000_MDIC_OP_READ\t0x08000000\n#define E1000_MDIC_READY\t0x10000000\n#define E1000_MDIC_ERROR\t0x40000000\n#define E1000_MDIC_DEST\t\t0x80000000\n\n/* SerDes Control */\n#define E1000_GEN_CTL_READY\t\t0x80000000\n#define E1000_GEN_CTL_ADDRESS_SHIFT\t8\n#define E1000_GEN_POLL_TIMEOUT\t\t640\n\n/* LinkSec register fields */\n#define E1000_LSECTXCAP_SUM_MASK\t0x00FF0000\n#define E1000_LSECTXCAP_SUM_SHIFT\t16\n#define E1000_LSECRXCAP_SUM_MASK\t0x00FF0000\n#define E1000_LSECRXCAP_SUM_SHIFT\t16\n\n#define E1000_LSECTXCTRL_EN_MASK\t0x00000003\n#define E1000_LSECTXCTRL_DISABLE\t0x0\n#define E1000_LSECTXCTRL_AUTH\t\t0x1\n#define E1000_LSECTXCTRL_AUTH_ENCRYPT\t0x2\n#define E1000_LSECTXCTRL_AISCI\t\t0x00000020\n#define E1000_LSECTXCTRL_PNTHRSH_MASK\t0xFFFFFF00\n#define E1000_LSECTXCTRL_RSV_MASK\t0x000000D8\n\n#define E1000_LSECRXCTRL_EN_MASK\t0x0000000C\n#define E1000_LSECRXCTRL_EN_SHIFT\t2\n#define E1000_LSECRXCTRL_DISABLE\t0x0\n#define E1000_LSECRXCTRL_CHECK\t\t0x1\n#define E1000_LSECRXCTRL_STRICT\t\t0x2\n#define E1000_LSECRXCTRL_DROP\t\t0x3\n#define E1000_LSECRXCTRL_PLSH\t\t0x00000040\n#define E1000_LSECRXCTRL_RP\t\t0x00000080\n#define E1000_LSECRXCTRL_RSV_MASK\t0xFFFFFF33\n\n/* Tx Rate-Scheduler Config fields */\n#define E1000_RTTBCNRC_RS_ENA\t\t0x80000000\n#define E1000_RTTBCNRC_RF_DEC_MASK\t0x00003FFF\n#define E1000_RTTBCNRC_RF_INT_SHIFT\t14\n#define E1000_RTTBCNRC_RF_INT_MASK\t\\\n\t(E1000_RTTBCNRC_RF_DEC_MASK << E1000_RTTBCNRC_RF_INT_SHIFT)\n\n/* DMA Coalescing register fields */\n/* DMA Coalescing Watchdog Timer */\n#define E1000_DMACR_DMACWT_MASK\t\t0x00003FFF\n/* DMA Coalescing Rx Threshold */\n#define E1000_DMACR_DMACTHR_MASK\t0x00FF0000\n#define E1000_DMACR_DMACTHR_SHIFT\t16\n/* Lx when no PCIe transactions */\n#define E1000_DMACR_DMAC_LX_MASK\t0x30000000\n#define E1000_DMACR_DMAC_LX_SHIFT\t28\n#define E1000_DMACR_DMAC_EN\t\t0x80000000 /* Enable DMA Coalescing */\n/* DMA Coalescing BMC-to-OS Watchdog Enable */\n#define E1000_DMACR_DC_BMC2OSW_EN\t0x00008000\n\n/* DMA Coalescing Transmit Threshold */\n#define E1000_DMCTXTH_DMCTTHR_MASK\t0x00000FFF\n\n#define E1000_DMCTLX_TTLX_MASK\t\t0x00000FFF /* Time to LX request */\n\n/* Rx Traffic Rate Threshold */\n#define E1000_DMCRTRH_UTRESH_MASK\t0x0007FFFF\n/* Rx packet rate in current window */\n#define E1000_DMCRTRH_LRPRCW\t\t0x80000000\n\n/* DMA Coal Rx Traffic Current Count */\n#define E1000_DMCCNT_CCOUNT_MASK\t0x01FFFFFF\n\n/* Flow ctrl Rx Threshold High val */\n#define E1000_FCRTC_RTH_COAL_MASK\t0x0003FFF0\n#define E1000_FCRTC_RTH_COAL_SHIFT\t4\n/* Lx power decision based on DMA coal */\n#define E1000_PCIEMISC_LX_DECISION\t0x00000080\n\n#define E1000_RXPBS_CFG_TS_EN\t\t0x80000000 /* Timestamp in Rx buffer */\n#define E1000_RXPBS_SIZE_I210_MASK\t0x0000003F /* Rx packet buffer size */\n#define E1000_TXPB0S_SIZE_I210_MASK\t0x0000003F /* Tx packet buffer 0 size */\n#define I210_RXPBSIZE_DEFAULT\t\t0x000000A2 /* RXPBSIZE default */\n#define I210_TXPBSIZE_DEFAULT\t\t0x04000014 /* TXPBSIZE default */\n\n#define E1000_DOBFFCTL_OBFFTHR_MASK\t0x000000FF /* OBFF threshold */\n#define E1000_DOBFFCTL_EXIT_ACT_MASK\t0x01000000 /* Exit active CB */\n\n/* Proxy Filter Control */\n#define E1000_PROXYFC_D0\t\t0x00000001 /* Enable offload in D0 */\n#define E1000_PROXYFC_EX\t\t0x00000004 /* Directed exact proxy */\n#define E1000_PROXYFC_MC\t\t0x00000008 /* Directed MC Proxy */\n#define E1000_PROXYFC_BC\t\t0x00000010 /* Broadcast Proxy Enable */\n#define E1000_PROXYFC_ARP_DIRECTED\t0x00000020 /* Directed ARP Proxy Ena */\n#define E1000_PROXYFC_IPV4\t\t0x00000040 /* Directed IPv4 Enable */\n#define E1000_PROXYFC_IPV6\t\t0x00000080 /* Directed IPv6 Enable */\n#define E1000_PROXYFC_NS\t\t0x00000200 /* IPv6 Neighbor Solicitation */\n#define E1000_PROXYFC_ARP\t\t0x00000800 /* ARP Request Proxy Ena */\n/* Proxy Status */\n#define E1000_PROXYS_CLEAR\t\t0xFFFFFFFF /* Clear */\n\n/* Firmware Status */\n#define E1000_FWSTS_FWRI\t\t0x80000000 /* FW Reset Indication */\n/* VF Control */\n#define E1000_VTCTRL_RST\t\t0x04000000 /* Reset VF */\n\n#define E1000_STATUS_LAN_ID_MASK\t0x00000000C /* Mask for Lan ID field */\n/* Lan ID bit field offset in status register */\n#define E1000_STATUS_LAN_ID_OFFSET\t2\n#define E1000_VFTA_ENTRIES\t\t128\n#define E1000_UNUSEDARG\n#ifndef ERROR_REPORT\n#define ERROR_REPORT(fmt)\tdo { } while (0)\n#endif /* ERROR_REPORT */\n#endif /* _E1000_DEFINES_H_ */\n"
  },
  {
    "path": "include/xhyve/support/e1000_regs.h",
    "content": "/******************************************************************************\n  SPDX-License-Identifier: BSD-3-Clause\n\n  Copyright (c) 2001-2015, Intel Corporation\n  All rights reserved.\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions are met:\n\n   1. Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n\n   2. Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n\n   3. Neither the name of the Intel Corporation nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\n  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n  POSSIBILITY OF SUCH DAMAGE.\n\n******************************************************************************/\n/*$FreeBSD$*/\n\n#ifndef _E1000_REGS_H_\n#define _E1000_REGS_H_\n\n#define E1000_CTRL\t0x00000  /* Device Control - RW */\n#define E1000_CTRL_DUP\t0x00004  /* Device Control Duplicate (Shadow) - RW */\n#define E1000_STATUS\t0x00008  /* Device Status - RO */\n#define E1000_EECD\t0x00010  /* EEPROM/Flash Control - RW */\n#define E1000_EERD\t0x00014  /* EEPROM Read - RW */\n#define E1000_CTRL_EXT\t0x00018  /* Extended Device Control - RW */\n#define E1000_FLA\t0x0001C  /* Flash Access - RW */\n#define E1000_MDIC\t0x00020  /* MDI Control - RW */\n#define E1000_MDICNFG\t0x00E04  /* MDI Config - RW */\n#define E1000_REGISTER_SET_SIZE\t\t0x20000 /* CSR Size */\n#define E1000_EEPROM_INIT_CTRL_WORD_2\t0x0F /* EEPROM Init Ctrl Word 2 */\n#define E1000_EEPROM_PCIE_CTRL_WORD_2\t0x28 /* EEPROM PCIe Ctrl Word 2 */\n#define E1000_BARCTRL\t\t\t0x5BBC /* BAR ctrl reg */\n#define E1000_BARCTRL_FLSIZE\t\t0x0700 /* BAR ctrl Flsize */\n#define E1000_BARCTRL_CSRSIZE\t\t0x2000 /* BAR ctrl CSR size */\n#define E1000_MPHY_ADDR_CTRL\t0x0024 /* GbE MPHY Address Control */\n#define E1000_MPHY_DATA\t\t0x0E10 /* GBE MPHY Data */\n#define E1000_MPHY_STAT\t\t0x0E0C /* GBE MPHY Statistics */\n#define E1000_PPHY_CTRL\t\t0x5b48 /* PCIe PHY Control */\n#define E1000_I350_BARCTRL\t\t0x5BFC /* BAR ctrl reg */\n#define E1000_I350_DTXMXPKTSZ\t\t0x355C /* Maximum sent packet size reg*/\n#define E1000_SCTL\t0x00024  /* SerDes Control - RW */\n#define E1000_FCAL\t0x00028  /* Flow Control Address Low - RW */\n#define E1000_FCAH\t0x0002C  /* Flow Control Address High -RW */\n#define E1000_FEXT\t0x0002C  /* Future Extended - RW */\n#define E1000_FEXTNVM\t0x00028  /* Future Extended NVM - RW */\n#define E1000_FEXTNVM3\t0x0003C  /* Future Extended NVM 3 - RW */\n#define E1000_FEXTNVM4\t0x00024  /* Future Extended NVM 4 - RW */\n#define E1000_FEXTNVM6\t0x00010  /* Future Extended NVM 6 - RW */\n#define E1000_FEXTNVM7\t0x000E4  /* Future Extended NVM 7 - RW */\n#define E1000_FEXTNVM9\t0x5BB4  /* Future Extended NVM 9 - RW */\n#define E1000_FEXTNVM11\t0x5BBC  /* Future Extended NVM 11 - RW */\n#define E1000_PCIEANACFG\t0x00F18 /* PCIE Analog Config */\n#define E1000_FCT\t0x00030  /* Flow Control Type - RW */\n#define E1000_CONNSW\t0x00034  /* Copper/Fiber switch control - RW */\n#define E1000_VET\t0x00038  /* VLAN Ether Type - RW */\n#define E1000_ICR\t0x000C0  /* Interrupt Cause Read - R/clr */\n#define E1000_ITR\t0x000C4  /* Interrupt Throttling Rate - RW */\n#define E1000_ICS\t0x000C8  /* Interrupt Cause Set - WO */\n#define E1000_IMS\t0x000D0  /* Interrupt Mask Set - RW */\n#define E1000_IMC\t0x000D8  /* Interrupt Mask Clear - WO */\n#define E1000_IAM\t0x000E0  /* Interrupt Acknowledge Auto Mask */\n#define E1000_IVAR\t0x000E4  /* Interrupt Vector Allocation Register - RW */\n#define E1000_SVCR\t0x000F0\n#define E1000_SVT\t0x000F4\n#define E1000_LPIC\t0x000FC  /* Low Power IDLE control */\n#define E1000_RCTL\t0x00100  /* Rx Control - RW */\n#define E1000_FCTTV\t0x00170  /* Flow Control Transmit Timer Value - RW */\n#define E1000_TXCW\t0x00178  /* Tx Configuration Word - RW */\n#define E1000_RXCW\t0x00180  /* Rx Configuration Word - RO */\n#define E1000_PBA_ECC\t0x01100  /* PBA ECC Register */\n#define E1000_EICR\t0x01580  /* Ext. Interrupt Cause Read - R/clr */\n#define E1000_EITR(_n)\t(0x01680 + (0x4 * (_n)))\n#define E1000_EICS\t0x01520  /* Ext. Interrupt Cause Set - W0 */\n#define E1000_EIMS\t0x01524  /* Ext. Interrupt Mask Set/Read - RW */\n#define E1000_EIMC\t0x01528  /* Ext. Interrupt Mask Clear - WO */\n#define E1000_EIAC\t0x0152C  /* Ext. Interrupt Auto Clear - RW */\n#define E1000_EIAM\t0x01530  /* Ext. Interrupt Ack Auto Clear Mask - RW */\n#define E1000_GPIE\t0x01514  /* General Purpose Interrupt Enable - RW */\n#define E1000_IVAR0\t0x01700  /* Interrupt Vector Allocation (array) - RW */\n#define E1000_IVAR_MISC\t0x01740 /* IVAR for \"other\" causes - RW */\n#define E1000_TCTL\t0x00400  /* Tx Control - RW */\n#define E1000_TCTL_EXT\t0x00404  /* Extended Tx Control - RW */\n#define E1000_TIPG\t0x00410  /* Tx Inter-packet gap -RW */\n#define E1000_TBT\t0x00448  /* Tx Burst Timer - RW */\n#define E1000_AIT\t0x00458  /* Adaptive Interframe Spacing Throttle - RW */\n#define E1000_LEDCTL\t0x00E00  /* LED Control - RW */\n#define E1000_LEDMUX\t0x08130  /* LED MUX Control */\n#define E1000_EXTCNF_CTRL\t0x00F00  /* Extended Configuration Control */\n#define E1000_EXTCNF_SIZE\t0x00F08  /* Extended Configuration Size */\n#define E1000_PHY_CTRL\t0x00F10  /* PHY Control Register in CSR */\n#define E1000_POEMB\tE1000_PHY_CTRL /* PHY OEM Bits */\n#define E1000_PBA\t0x01000  /* Packet Buffer Allocation - RW */\n#define E1000_PBS\t0x01008  /* Packet Buffer Size */\n#define E1000_PBECCSTS\t0x0100C  /* Packet Buffer ECC Status - RW */\n#define E1000_IOSFPC\t0x00F28  /* TX corrupted data  */\n#define E1000_EEMNGCTL\t0x01010  /* MNG EEprom Control */\n#define E1000_EEMNGCTL_I210\t0x01010  /* i210 MNG EEprom Mode Control */\n#define E1000_EEARBC\t0x01024  /* EEPROM Auto Read Bus Control */\n#define E1000_EEARBC_I210\t0x12024 /* EEPROM Auto Read Bus Control */\n#define E1000_FLASHT\t0x01028  /* FLASH Timer Register */\n#define E1000_EEWR\t0x0102C  /* EEPROM Write Register - RW */\n#define E1000_FLSWCTL\t0x01030  /* FLASH control register */\n#define E1000_FLSWDATA\t0x01034  /* FLASH data register */\n#define E1000_FLSWCNT\t0x01038  /* FLASH Access Counter */\n#define E1000_FLOP\t0x0103C  /* FLASH Opcode Register */\n#define E1000_I2CCMD\t0x01028  /* SFPI2C Command Register - RW */\n#define E1000_I2CPARAMS\t0x0102C /* SFPI2C Parameters Register - RW */\n#define E1000_I2CBB_EN\t0x00000100  /* I2C - Bit Bang Enable */\n#define E1000_I2C_CLK_OUT\t0x00000200  /* I2C- Clock */\n#define E1000_I2C_DATA_OUT\t0x00000400  /* I2C- Data Out */\n#define E1000_I2C_DATA_OE_N\t0x00000800  /* I2C- Data Output Enable */\n#define E1000_I2C_DATA_IN\t0x00001000  /* I2C- Data In */\n#define E1000_I2C_CLK_OE_N\t0x00002000  /* I2C- Clock Output Enable */\n#define E1000_I2C_CLK_IN\t0x00004000  /* I2C- Clock In */\n#define E1000_I2C_CLK_STRETCH_DIS\t0x00008000 /* I2C- Dis Clk Stretching */\n#define E1000_WDSTP\t0x01040  /* Watchdog Setup - RW */\n#define E1000_SWDSTS\t0x01044  /* SW Device Status - RW */\n#define E1000_FRTIMER\t0x01048  /* Free Running Timer - RW */\n#define E1000_TCPTIMER\t0x0104C  /* TCP Timer - RW */\n#define E1000_VPDDIAG\t0x01060  /* VPD Diagnostic - RO */\n#define E1000_ICR_V2\t0x01500  /* Intr Cause - new location - RC */\n#define E1000_ICS_V2\t0x01504  /* Intr Cause Set - new location - WO */\n#define E1000_IMS_V2\t0x01508  /* Intr Mask Set/Read - new location - RW */\n#define E1000_IMC_V2\t0x0150C  /* Intr Mask Clear - new location - WO */\n#define E1000_IAM_V2\t0x01510  /* Intr Ack Auto Mask - new location - RW */\n#define E1000_ERT\t0x02008  /* Early Rx Threshold - RW */\n#define E1000_FCRTL\t0x02160  /* Flow Control Receive Threshold Low - RW */\n#define E1000_FCRTH\t0x02168  /* Flow Control Receive Threshold High - RW */\n#define E1000_PSRCTL\t0x02170  /* Packet Split Receive Control - RW */\n#define E1000_RDFH\t0x02410  /* Rx Data FIFO Head - RW */\n#define E1000_RDFT\t0x02418  /* Rx Data FIFO Tail - RW */\n#define E1000_RDFHS\t0x02420  /* Rx Data FIFO Head Saved - RW */\n#define E1000_RDFTS\t0x02428  /* Rx Data FIFO Tail Saved - RW */\n#define E1000_RDFPC\t0x02430  /* Rx Data FIFO Packet Count - RW */\n#define E1000_PBRTH\t0x02458  /* PB Rx Arbitration Threshold - RW */\n#define E1000_FCRTV\t0x02460  /* Flow Control Refresh Timer Value - RW */\n/* Split and Replication Rx Control - RW */\n#define E1000_RDPUMB\t0x025CC  /* DMA Rx Descriptor uC Mailbox - RW */\n#define E1000_RDPUAD\t0x025D0  /* DMA Rx Descriptor uC Addr Command - RW */\n#define E1000_RDPUWD\t0x025D4  /* DMA Rx Descriptor uC Data Write - RW */\n#define E1000_RDPURD\t0x025D8  /* DMA Rx Descriptor uC Data Read - RW */\n#define E1000_RDPUCTL\t0x025DC  /* DMA Rx Descriptor uC Control - RW */\n#define E1000_PBDIAG\t0x02458  /* Packet Buffer Diagnostic - RW */\n#define E1000_RXPBS\t0x02404  /* Rx Packet Buffer Size - RW */\n#define E1000_IRPBS\t0x02404 /* Same as RXPBS, renamed for newer Si - RW */\n#define E1000_PBRWAC\t0x024E8 /* Rx packet buffer wrap around counter - RO */\n#define E1000_RDTR\t0x02820  /* Rx Delay Timer - RW */\n#define E1000_RADV\t0x0282C  /* Rx Interrupt Absolute Delay Timer - RW */\n#define E1000_EMIADD\t0x10     /* Extended Memory Indirect Address */\n#define E1000_EMIDATA\t0x11     /* Extended Memory Indirect Data */\n#define E1000_SRWR\t\t0x12018  /* Shadow Ram Write Register - RW */\n#define E1000_I210_FLMNGCTL\t0x12038\n#define E1000_I210_FLMNGDATA\t0x1203C\n#define E1000_I210_FLMNGCNT\t0x12040\n\n#define E1000_I210_FLSWCTL\t0x12048\n#define E1000_I210_FLSWDATA\t0x1204C\n#define E1000_I210_FLSWCNT\t0x12050\n\n#define E1000_I210_FLA\t\t0x1201C\n\n#define E1000_INVM_DATA_REG(_n)\t(0x12120 + 4*(_n))\n#define E1000_INVM_SIZE\t\t64 /* Number of INVM Data Registers */\n\n/* QAV Tx mode control register */\n#define E1000_I210_TQAVCTRL\t0x3570\n\n/* QAV Tx mode control register bitfields masks */\n/* QAV enable */\n#define E1000_TQAVCTRL_MODE\t\t\t(1 << 0)\n/* Fetching arbitration type */\n#define E1000_TQAVCTRL_FETCH_ARB\t\t(1 << 4)\n/* Fetching timer enable */\n#define E1000_TQAVCTRL_FETCH_TIMER_ENABLE\t(1 << 5)\n/* Launch arbitration type */\n#define E1000_TQAVCTRL_LAUNCH_ARB\t\t(1 << 8)\n/* Launch timer enable */\n#define E1000_TQAVCTRL_LAUNCH_TIMER_ENABLE\t(1 << 9)\n/* SP waits for SR enable */\n#define E1000_TQAVCTRL_SP_WAIT_SR\t\t(1 << 10)\n/* Fetching timer correction */\n#define E1000_TQAVCTRL_FETCH_TIMER_DELTA_OFFSET\t16\n#define E1000_TQAVCTRL_FETCH_TIMER_DELTA\t\\\n\t\t\t(0xFFFF << E1000_TQAVCTRL_FETCH_TIMER_DELTA_OFFSET)\n\n/* High credit registers where _n can be 0 or 1. */\n#define E1000_I210_TQAVHC(_n)\t\t\t(0x300C + 0x40 * (_n))\n\n/* Queues fetch arbitration priority control register */\n#define E1000_I210_TQAVARBCTRL\t\t\t0x3574\n/* Queues priority masks where _n and _p can be 0-3. */\n#define E1000_TQAVARBCTRL_QUEUE_PRI(_n, _p)\t((_p) << (2 * (_n)))\n/* QAV Tx mode control registers where _n can be 0 or 1. */\n#define E1000_I210_TQAVCC(_n)\t\t\t(0x3004 + 0x40 * (_n))\n\n/* QAV Tx mode control register bitfields masks */\n#define E1000_TQAVCC_IDLE_SLOPE\t\t0xFFFF /* Idle slope */\n#define E1000_TQAVCC_KEEP_CREDITS\t(1 << 30) /* Keep credits opt enable */\n#define E1000_TQAVCC_QUEUE_MODE\t\t(1U << 31) /* SP vs. SR Tx mode */\n\n/* Good transmitted packets counter registers */\n#define E1000_PQGPTC(_n)\t\t(0x010014 + (0x100 * (_n)))\n\n/* Queues packet buffer size masks where _n can be 0-3 and _s 0-63 [kB] */\n#define E1000_I210_TXPBS_SIZE(_n, _s)\t((_s) << (6 * (_n)))\n\n#define E1000_MMDAC\t\t\t13 /* MMD Access Control */\n#define E1000_MMDAAD\t\t\t14 /* MMD Access Address/Data */\n\n/* Convenience macros\n *\n * Note: \"_n\" is the queue number of the register to be written to.\n *\n * Example usage:\n * E1000_RDBAL_REG(current_rx_queue)\n */\n#define E1000_RDBAL(_n)\t((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C000 + ((_n) * 0x40)))\n#define E1000_RDBAH(_n)\t((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C004 + ((_n) * 0x40)))\n#define E1000_RDLEN(_n)\t((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C008 + ((_n) * 0x40)))\n#define E1000_SRRCTL(_n)\t((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \\\n\t\t\t\t (0x0C00C + ((_n) * 0x40)))\n#define E1000_RDH(_n)\t((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C010 + ((_n) * 0x40)))\n#define E1000_RXCTL(_n)\t((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C014 + ((_n) * 0x40)))\n#define E1000_DCA_RXCTRL(_n)\tE1000_RXCTL(_n)\n#define E1000_RDT(_n)\t((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C018 + ((_n) * 0x40)))\n#define E1000_RXDCTL(_n)\t((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \\\n\t\t\t\t (0x0C028 + ((_n) * 0x40)))\n#define E1000_RQDPC(_n)\t((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \\\n\t\t\t (0x0C030 + ((_n) * 0x40)))\n#define E1000_TDBAL(_n)\t((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \\\n\t\t\t (0x0E000 + ((_n) * 0x40)))\n#define E1000_TDBAH(_n)\t((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \\\n\t\t\t (0x0E004 + ((_n) * 0x40)))\n#define E1000_TDLEN(_n)\t((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \\\n\t\t\t (0x0E008 + ((_n) * 0x40)))\n#define E1000_TDH(_n)\t((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \\\n\t\t\t (0x0E010 + ((_n) * 0x40)))\n#define E1000_TXCTL(_n)\t((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \\\n\t\t\t (0x0E014 + ((_n) * 0x40)))\n#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)\n#define E1000_TDT(_n)\t((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \\\n\t\t\t (0x0E018 + ((_n) * 0x40)))\n#define E1000_TXDCTL(_n)\t((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \\\n\t\t\t\t (0x0E028 + ((_n) * 0x40)))\n#define E1000_TDWBAL(_n)\t((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \\\n\t\t\t\t (0x0E038 + ((_n) * 0x40)))\n#define E1000_TDWBAH(_n)\t((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \\\n\t\t\t\t (0x0E03C + ((_n) * 0x40)))\n#define E1000_TARC(_n)\t\t(0x03840 + ((_n) * 0x100))\n#define E1000_RSRPD\t\t0x02C00  /* Rx Small Packet Detect - RW */\n#define E1000_RAID\t\t0x02C08  /* Receive Ack Interrupt Delay - RW */\n#define E1000_TXDMAC\t\t0x03000  /* Tx DMA Control - RW */\n#define E1000_KABGTXD\t\t0x03004  /* AFE Band Gap Transmit Ref Data */\n#define E1000_PSRTYPE(_i)\t(0x05480 + ((_i) * 4))\n#define E1000_RAL(_i)\t\t(((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \\\n\t\t\t\t (0x054E0 + ((_i - 16) * 8)))\n#define E1000_RAH(_i)\t\t(((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \\\n\t\t\t\t (0x054E4 + ((_i - 16) * 8)))\n#define E1000_SHRAL(_i)\t\t(0x05438 + ((_i) * 8))\n#define E1000_SHRAH(_i)\t\t(0x0543C + ((_i) * 8))\n#define E1000_IP4AT_REG(_i)\t(0x05840 + ((_i) * 8))\n#define E1000_IP6AT_REG(_i)\t(0x05880 + ((_i) * 4))\n#define E1000_WUPM_REG(_i)\t(0x05A00 + ((_i) * 4))\n#define E1000_FFMT_REG(_i)\t(0x09000 + ((_i) * 8))\n#define E1000_FFVT_REG(_i)\t(0x09800 + ((_i) * 8))\n#define E1000_FFLT_REG(_i)\t(0x05F00 + ((_i) * 8))\n#define E1000_PBSLAC\t\t0x03100  /* Pkt Buffer Slave Access Control */\n#define E1000_PBSLAD(_n)\t(0x03110 + (0x4 * (_n)))  /* Pkt Buffer DWORD */\n#define E1000_TXPBS\t\t0x03404  /* Tx Packet Buffer Size - RW */\n/* Same as TXPBS, renamed for newer Si - RW */\n#define E1000_ITPBS\t\t0x03404\n#define E1000_TDFH\t\t0x03410  /* Tx Data FIFO Head - RW */\n#define E1000_TDFT\t\t0x03418  /* Tx Data FIFO Tail - RW */\n#define E1000_TDFHS\t\t0x03420  /* Tx Data FIFO Head Saved - RW */\n#define E1000_TDFTS\t\t0x03428  /* Tx Data FIFO Tail Saved - RW */\n#define E1000_TDFPC\t\t0x03430  /* Tx Data FIFO Packet Count - RW */\n#define E1000_TDPUMB\t\t0x0357C  /* DMA Tx Desc uC Mail Box - RW */\n#define E1000_TDPUAD\t\t0x03580  /* DMA Tx Desc uC Addr Command - RW */\n#define E1000_TDPUWD\t\t0x03584  /* DMA Tx Desc uC Data Write - RW */\n#define E1000_TDPURD\t\t0x03588  /* DMA Tx Desc uC Data  Read  - RW */\n#define E1000_TDPUCTL\t\t0x0358C  /* DMA Tx Desc uC Control - RW */\n#define E1000_DTXCTL\t\t0x03590  /* DMA Tx Control - RW */\n#define E1000_DTXTCPFLGL\t0x0359C /* DMA Tx Control flag low - RW */\n#define E1000_DTXTCPFLGH\t0x035A0 /* DMA Tx Control flag high - RW */\n/* DMA Tx Max Total Allow Size Reqs - RW */\n#define E1000_DTXMXSZRQ\t\t0x03540\n#define E1000_TIDV\t0x03820  /* Tx Interrupt Delay Value - RW */\n#define E1000_TADV\t0x0382C  /* Tx Interrupt Absolute Delay Val - RW */\n#define E1000_TSPMT\t0x03830  /* TCP Segmentation PAD & Min Threshold - RW */\n#define E1000_CRCERRS\t0x04000  /* CRC Error Count - R/clr */\n#define E1000_ALGNERRC\t0x04004  /* Alignment Error Count - R/clr */\n#define E1000_SYMERRS\t0x04008  /* Symbol Error Count - R/clr */\n#define E1000_RXERRC\t0x0400C  /* Receive Error Count - R/clr */\n#define E1000_MPC\t0x04010  /* Missed Packet Count - R/clr */\n#define E1000_SCC\t0x04014  /* Single Collision Count - R/clr */\n#define E1000_ECOL\t0x04018  /* Excessive Collision Count - R/clr */\n#define E1000_MCC\t0x0401C  /* Multiple Collision Count - R/clr */\n#define E1000_LATECOL\t0x04020  /* Late Collision Count - R/clr */\n#define E1000_COLC\t0x04028  /* Collision Count - R/clr */\n#define E1000_DC\t0x04030  /* Defer Count - R/clr */\n#define E1000_TNCRS\t0x04034  /* Tx-No CRS - R/clr */\n#define E1000_SEC\t0x04038  /* Sequence Error Count - R/clr */\n#define E1000_CEXTERR\t0x0403C  /* Carrier Extension Error Count - R/clr */\n#define E1000_RLEC\t0x04040  /* Receive Length Error Count - R/clr */\n#define E1000_XONRXC\t0x04048  /* XON Rx Count - R/clr */\n#define E1000_XONTXC\t0x0404C  /* XON Tx Count - R/clr */\n#define E1000_XOFFRXC\t0x04050  /* XOFF Rx Count - R/clr */\n#define E1000_XOFFTXC\t0x04054  /* XOFF Tx Count - R/clr */\n#define E1000_FCRUC\t0x04058  /* Flow Control Rx Unsupported Count- R/clr */\n#define E1000_PRC64\t0x0405C  /* Packets Rx (64 bytes) - R/clr */\n#define E1000_PRC127\t0x04060  /* Packets Rx (65-127 bytes) - R/clr */\n#define E1000_PRC255\t0x04064  /* Packets Rx (128-255 bytes) - R/clr */\n#define E1000_PRC511\t0x04068  /* Packets Rx (255-511 bytes) - R/clr */\n#define E1000_PRC1023\t0x0406C  /* Packets Rx (512-1023 bytes) - R/clr */\n#define E1000_PRC1522\t0x04070  /* Packets Rx (1024-1522 bytes) - R/clr */\n#define E1000_GPRC\t0x04074  /* Good Packets Rx Count - R/clr */\n#define E1000_BPRC\t0x04078  /* Broadcast Packets Rx Count - R/clr */\n#define E1000_MPRC\t0x0407C  /* Multicast Packets Rx Count - R/clr */\n#define E1000_GPTC\t0x04080  /* Good Packets Tx Count - R/clr */\n#define E1000_GORCL\t0x04088  /* Good Octets Rx Count Low - R/clr */\n#define E1000_GORCH\t0x0408C  /* Good Octets Rx Count High - R/clr */\n#define E1000_GOTCL\t0x04090  /* Good Octets Tx Count Low - R/clr */\n#define E1000_GOTCH\t0x04094  /* Good Octets Tx Count High - R/clr */\n#define E1000_RNBC\t0x040A0  /* Rx No Buffers Count - R/clr */\n#define E1000_RUC\t0x040A4  /* Rx Undersize Count - R/clr */\n#define E1000_RFC\t0x040A8  /* Rx Fragment Count - R/clr */\n#define E1000_ROC\t0x040AC  /* Rx Oversize Count - R/clr */\n#define E1000_RJC\t0x040B0  /* Rx Jabber Count - R/clr */\n#define E1000_MGTPRC\t0x040B4  /* Management Packets Rx Count - R/clr */\n#define E1000_MGTPDC\t0x040B8  /* Management Packets Dropped Count - R/clr */\n#define E1000_MGTPTC\t0x040BC  /* Management Packets Tx Count - R/clr */\n#define E1000_TORL\t0x040C0  /* Total Octets Rx Low - R/clr */\n#define E1000_TORH\t0x040C4  /* Total Octets Rx High - R/clr */\n#define E1000_TOTL\t0x040C8  /* Total Octets Tx Low - R/clr */\n#define E1000_TOTH\t0x040CC  /* Total Octets Tx High - R/clr */\n#define E1000_TPR\t0x040D0  /* Total Packets Rx - R/clr */\n#define E1000_TPT\t0x040D4  /* Total Packets Tx - R/clr */\n#define E1000_PTC64\t0x040D8  /* Packets Tx (64 bytes) - R/clr */\n#define E1000_PTC127\t0x040DC  /* Packets Tx (65-127 bytes) - R/clr */\n#define E1000_PTC255\t0x040E0  /* Packets Tx (128-255 bytes) - R/clr */\n#define E1000_PTC511\t0x040E4  /* Packets Tx (256-511 bytes) - R/clr */\n#define E1000_PTC1023\t0x040E8  /* Packets Tx (512-1023 bytes) - R/clr */\n#define E1000_PTC1522\t0x040EC  /* Packets Tx (1024-1522 Bytes) - R/clr */\n#define E1000_MPTC\t0x040F0  /* Multicast Packets Tx Count - R/clr */\n#define E1000_BPTC\t0x040F4  /* Broadcast Packets Tx Count - R/clr */\n#define E1000_TSCTC\t0x040F8  /* TCP Segmentation Context Tx - R/clr */\n#define E1000_TSCTFC\t0x040FC  /* TCP Segmentation Context Tx Fail - R/clr */\n#define E1000_IAC\t0x04100  /* Interrupt Assertion Count */\n#define E1000_ICRXPTC\t0x04104  /* Interrupt Cause Rx Pkt Timer Expire Count */\n#define E1000_ICRXATC\t0x04108  /* Interrupt Cause Rx Abs Timer Expire Count */\n#define E1000_ICTXPTC\t0x0410C  /* Interrupt Cause Tx Pkt Timer Expire Count */\n#define E1000_ICTXATC\t0x04110  /* Interrupt Cause Tx Abs Timer Expire Count */\n#define E1000_ICTXQEC\t0x04118  /* Interrupt Cause Tx Queue Empty Count */\n#define E1000_ICTXQMTC\t0x0411C  /* Interrupt Cause Tx Queue Min Thresh Count */\n#define E1000_ICRXDMTC\t0x04120  /* Interrupt Cause Rx Desc Min Thresh Count */\n#define E1000_ICRXOC\t0x04124  /* Interrupt Cause Receiver Overrun Count */\n#define E1000_CRC_OFFSET\t0x05F50  /* CRC Offset register */\n\n#define E1000_VFGPRC\t0x00F10\n#define E1000_VFGORC\t0x00F18\n#define E1000_VFMPRC\t0x00F3C\n#define E1000_VFGPTC\t0x00F14\n#define E1000_VFGOTC\t0x00F34\n#define E1000_VFGOTLBC\t0x00F50\n#define E1000_VFGPTLBC\t0x00F44\n#define E1000_VFGORLBC\t0x00F48\n#define E1000_VFGPRLBC\t0x00F40\n/* Virtualization statistical counters */\n#define E1000_PFVFGPRC(_n)\t(0x010010 + (0x100 * (_n)))\n#define E1000_PFVFGPTC(_n)\t(0x010014 + (0x100 * (_n)))\n#define E1000_PFVFGORC(_n)\t(0x010018 + (0x100 * (_n)))\n#define E1000_PFVFGOTC(_n)\t(0x010034 + (0x100 * (_n)))\n#define E1000_PFVFMPRC(_n)\t(0x010038 + (0x100 * (_n)))\n#define E1000_PFVFGPRLBC(_n)\t(0x010040 + (0x100 * (_n)))\n#define E1000_PFVFGPTLBC(_n)\t(0x010044 + (0x100 * (_n)))\n#define E1000_PFVFGORLBC(_n)\t(0x010048 + (0x100 * (_n)))\n#define E1000_PFVFGOTLBC(_n)\t(0x010050 + (0x100 * (_n)))\n\n/* LinkSec */\n#define E1000_LSECTXUT\t\t0x04300  /* Tx Untagged Pkt Cnt */\n#define E1000_LSECTXPKTE\t0x04304  /* Encrypted Tx Pkts Cnt */\n#define E1000_LSECTXPKTP\t0x04308  /* Protected Tx Pkt Cnt */\n#define E1000_LSECTXOCTE\t0x0430C  /* Encrypted Tx Octets Cnt */\n#define E1000_LSECTXOCTP\t0x04310  /* Protected Tx Octets Cnt */\n#define E1000_LSECRXUT\t\t0x04314  /* Untagged non-Strict Rx Pkt Cnt */\n#define E1000_LSECRXOCTD\t0x0431C  /* Rx Octets Decrypted Count */\n#define E1000_LSECRXOCTV\t0x04320  /* Rx Octets Validated */\n#define E1000_LSECRXBAD\t\t0x04324  /* Rx Bad Tag */\n#define E1000_LSECRXNOSCI\t0x04328  /* Rx Packet No SCI Count */\n#define E1000_LSECRXUNSCI\t0x0432C  /* Rx Packet Unknown SCI Count */\n#define E1000_LSECRXUNCH\t0x04330  /* Rx Unchecked Packets Count */\n#define E1000_LSECRXDELAY\t0x04340  /* Rx Delayed Packet Count */\n#define E1000_LSECRXLATE\t0x04350  /* Rx Late Packets Count */\n#define E1000_LSECRXOK(_n)\t(0x04360 + (0x04 * (_n))) /* Rx Pkt OK Cnt */\n#define E1000_LSECRXINV(_n)\t(0x04380 + (0x04 * (_n))) /* Rx Invalid Cnt */\n#define E1000_LSECRXNV(_n)\t(0x043A0 + (0x04 * (_n))) /* Rx Not Valid Cnt */\n#define E1000_LSECRXUNSA\t0x043C0  /* Rx Unused SA Count */\n#define E1000_LSECRXNUSA\t0x043D0  /* Rx Not Using SA Count */\n#define E1000_LSECTXCAP\t\t0x0B000  /* Tx Capabilities Register - RO */\n#define E1000_LSECRXCAP\t\t0x0B300  /* Rx Capabilities Register - RO */\n#define E1000_LSECTXCTRL\t0x0B004  /* Tx Control - RW */\n#define E1000_LSECRXCTRL\t0x0B304  /* Rx Control - RW */\n#define E1000_LSECTXSCL\t\t0x0B008  /* Tx SCI Low - RW */\n#define E1000_LSECTXSCH\t\t0x0B00C  /* Tx SCI High - RW */\n#define E1000_LSECTXSA\t\t0x0B010  /* Tx SA0 - RW */\n#define E1000_LSECTXPN0\t\t0x0B018  /* Tx SA PN 0 - RW */\n#define E1000_LSECTXPN1\t\t0x0B01C  /* Tx SA PN 1 - RW */\n#define E1000_LSECRXSCL\t\t0x0B3D0  /* Rx SCI Low - RW */\n#define E1000_LSECRXSCH\t\t0x0B3E0  /* Rx SCI High - RW */\n/* LinkSec Tx 128-bit Key 0 - WO */\n#define E1000_LSECTXKEY0(_n)\t(0x0B020 + (0x04 * (_n)))\n/* LinkSec Tx 128-bit Key 1 - WO */\n#define E1000_LSECTXKEY1(_n)\t(0x0B030 + (0x04 * (_n)))\n#define E1000_LSECRXSA(_n)\t(0x0B310 + (0x04 * (_n))) /* Rx SAs - RW */\n#define E1000_LSECRXPN(_n)\t(0x0B330 + (0x04 * (_n))) /* Rx SAs - RW */\n/* LinkSec Rx Keys  - where _n is the SA no. and _m the 4 dwords of the 128 bit\n * key - RW.\n */\n#define E1000_LSECRXKEY(_n, _m)\t(0x0B350 + (0x10 * (_n)) + (0x04 * (_m)))\n\n#define E1000_SSVPC\t\t0x041A0 /* Switch Security Violation Pkt Cnt */\n#define E1000_IPSCTRL\t\t0xB430  /* IpSec Control Register */\n#define E1000_IPSRXCMD\t\t0x0B408 /* IPSec Rx Command Register - RW */\n#define E1000_IPSRXIDX\t\t0x0B400 /* IPSec Rx Index - RW */\n/* IPSec Rx IPv4/v6 Address - RW */\n#define E1000_IPSRXIPADDR(_n)\t(0x0B420 + (0x04 * (_n)))\n/* IPSec Rx 128-bit Key - RW */\n#define E1000_IPSRXKEY(_n)\t(0x0B410 + (0x04 * (_n)))\n#define E1000_IPSRXSALT\t\t0x0B404  /* IPSec Rx Salt - RW */\n#define E1000_IPSRXSPI\t\t0x0B40C  /* IPSec Rx SPI - RW */\n/* IPSec Tx 128-bit Key - RW */\n#define E1000_IPSTXKEY(_n)\t(0x0B460 + (0x04 * (_n)))\n#define E1000_IPSTXSALT\t\t0x0B454  /* IPSec Tx Salt - RW */\n#define E1000_IPSTXIDX\t\t0x0B450  /* IPSec Tx SA IDX - RW */\n#define E1000_PCS_CFG0\t0x04200  /* PCS Configuration 0 - RW */\n#define E1000_PCS_LCTL\t0x04208  /* PCS Link Control - RW */\n#define E1000_PCS_LSTAT\t0x0420C  /* PCS Link Status - RO */\n#define E1000_CBTMPC\t0x0402C  /* Circuit Breaker Tx Packet Count */\n#define E1000_HTDPMC\t0x0403C  /* Host Transmit Discarded Packets */\n#define E1000_CBRDPC\t0x04044  /* Circuit Breaker Rx Dropped Count */\n#define E1000_CBRMPC\t0x040FC  /* Circuit Breaker Rx Packet Count */\n#define E1000_RPTHC\t0x04104  /* Rx Packets To Host */\n#define E1000_HGPTC\t0x04118  /* Host Good Packets Tx Count */\n#define E1000_HTCBDPC\t0x04124  /* Host Tx Circuit Breaker Dropped Count */\n#define E1000_HGORCL\t0x04128  /* Host Good Octets Received Count Low */\n#define E1000_HGORCH\t0x0412C  /* Host Good Octets Received Count High */\n#define E1000_HGOTCL\t0x04130  /* Host Good Octets Transmit Count Low */\n#define E1000_HGOTCH\t0x04134  /* Host Good Octets Transmit Count High */\n#define E1000_LENERRS\t0x04138  /* Length Errors Count */\n#define E1000_SCVPC\t0x04228  /* SerDes/SGMII Code Violation Pkt Count */\n#define E1000_HRMPC\t0x0A018  /* Header Redirection Missed Packet Count */\n#define E1000_PCS_ANADV\t0x04218  /* AN advertisement - RW */\n#define E1000_PCS_LPAB\t0x0421C  /* Link Partner Ability - RW */\n#define E1000_PCS_NPTX\t0x04220  /* AN Next Page Transmit - RW */\n#define E1000_PCS_LPABNP\t0x04224 /* Link Partner Ability Next Pg - RW */\n#define E1000_RXCSUM\t0x05000  /* Rx Checksum Control - RW */\n#define E1000_RLPML\t0x05004  /* Rx Long Packet Max Length */\n#define E1000_RFCTL\t0x05008  /* Receive Filter Control*/\n#define E1000_MTA\t0x05200  /* Multicast Table Array - RW Array */\n#define E1000_RA\t0x05400  /* Receive Address - RW Array */\n#define E1000_RA2\t0x054E0  /* 2nd half of Rx address array - RW Array */\n#define E1000_VFTA\t0x05600  /* VLAN Filter Table Array - RW Array */\n#define E1000_VT_CTL\t0x0581C  /* VMDq Control - RW */\n#define E1000_CIAA\t0x05B88  /* Config Indirect Access Address - RW */\n#define E1000_CIAD\t0x05B8C  /* Config Indirect Access Data - RW */\n#define E1000_VFQA0\t0x0B000  /* VLAN Filter Queue Array 0 - RW Array */\n#define E1000_VFQA1\t0x0B200  /* VLAN Filter Queue Array 1 - RW Array */\n#define E1000_WUC\t0x05800  /* Wakeup Control - RW */\n#define E1000_WUFC\t0x05808  /* Wakeup Filter Control - RW */\n#define E1000_WUS\t0x05810  /* Wakeup Status - RO */\n#define E1000_MANC\t0x05820  /* Management Control - RW */\n#define E1000_IPAV\t0x05838  /* IP Address Valid - RW */\n#define E1000_IP4AT\t0x05840  /* IPv4 Address Table - RW Array */\n#define E1000_IP6AT\t0x05880  /* IPv6 Address Table - RW Array */\n#define E1000_WUPL\t0x05900  /* Wakeup Packet Length - RW */\n#define E1000_WUPM\t0x05A00  /* Wakeup Packet Memory - RO A */\n#define E1000_PBACL\t0x05B68  /* MSIx PBA Clear - Read/Write 1's to clear */\n#define E1000_FFLT\t0x05F00  /* Flexible Filter Length Table - RW Array */\n#define E1000_HOST_IF\t0x08800  /* Host Interface */\n#define E1000_HIBBA\t0x8F40   /* Host Interface Buffer Base Address */\n/* Flexible Host Filter Table */\n#define E1000_FHFT(_n)\t(0x09000 + ((_n) * 0x100))\n/* Ext Flexible Host Filter Table */\n#define E1000_FHFT_EXT(_n)\t(0x09A00 + ((_n) * 0x100))\n\n\n#define E1000_KMRNCTRLSTA\t0x00034 /* MAC-PHY interface - RW */\n#define E1000_MANC2H\t\t0x05860 /* Management Control To Host - RW */\n/* Management Decision Filters */\n#define E1000_MDEF(_n)\t\t(0x05890 + (4 * (_n)))\n#define E1000_SW_FW_SYNC\t0x05B5C /* SW-FW Synchronization - RW */\n#define E1000_CCMCTL\t0x05B48 /* CCM Control Register */\n#define E1000_GIOCTL\t0x05B44 /* GIO Analog Control Register */\n#define E1000_SCCTL\t0x05B4C /* PCIc PLL Configuration Register */\n#define E1000_GCR\t0x05B00 /* PCI-Ex Control */\n#define E1000_GCR2\t0x05B64 /* PCI-Ex Control #2 */\n#define E1000_GSCL_1\t0x05B10 /* PCI-Ex Statistic Control #1 */\n#define E1000_GSCL_2\t0x05B14 /* PCI-Ex Statistic Control #2 */\n#define E1000_GSCL_3\t0x05B18 /* PCI-Ex Statistic Control #3 */\n#define E1000_GSCL_4\t0x05B1C /* PCI-Ex Statistic Control #4 */\n#define E1000_FACTPS\t0x05B30 /* Function Active and Power State to MNG */\n#define E1000_SWSM\t0x05B50 /* SW Semaphore */\n#define E1000_FWSM\t0x05B54 /* FW Semaphore */\n/* Driver-only SW semaphore (not used by BOOT agents) */\n#define E1000_SWSM2\t0x05B58\n#define E1000_DCA_ID\t0x05B70 /* DCA Requester ID Information - RO */\n#define E1000_DCA_CTRL\t0x05B74 /* DCA Control - RW */\n#define E1000_UFUSE\t0x05B78 /* UFUSE - RO */\n#define E1000_FFLT_DBG\t0x05F04 /* Debug Register */\n#define E1000_HICR\t0x08F00 /* Host Interface Control */\n#define E1000_FWSTS\t0x08F0C /* FW Status */\n\n/* RSS registers */\n#define E1000_CPUVEC\t0x02C10 /* CPU Vector Register - RW */\n#define E1000_MRQC\t0x05818 /* Multiple Receive Control - RW */\n#define E1000_IMIR(_i)\t(0x05A80 + ((_i) * 4))  /* Immediate Interrupt */\n#define E1000_IMIREXT(_i)\t(0x05AA0 + ((_i) * 4)) /* Immediate INTR Ext*/\n#define E1000_IMIRVP\t\t0x05AC0 /* Immediate INT Rx VLAN Priority -RW */\n#define E1000_MSIXBM(_i)\t(0x01600 + ((_i) * 4)) /* MSI-X Alloc Reg -RW */\n#define E1000_RETA(_i)\t(0x05C00 + ((_i) * 4)) /* Redirection Table - RW */\n#define E1000_RSSRK(_i)\t(0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */\n#define E1000_RSSIM\t0x05864 /* RSS Interrupt Mask */\n#define E1000_RSSIR\t0x05868 /* RSS Interrupt Request */\n/* VT Registers */\n#define E1000_SWPBS\t0x03004 /* Switch Packet Buffer Size - RW */\n#define E1000_MBVFICR\t0x00C80 /* Mailbox VF Cause - RWC */\n#define E1000_MBVFIMR\t0x00C84 /* Mailbox VF int Mask - RW */\n#define E1000_VFLRE\t0x00C88 /* VF Register Events - RWC */\n#define E1000_VFRE\t0x00C8C /* VF Receive Enables */\n#define E1000_VFTE\t0x00C90 /* VF Transmit Enables */\n#define E1000_QDE\t0x02408 /* Queue Drop Enable - RW */\n#define E1000_DTXSWC\t0x03500 /* DMA Tx Switch Control - RW */\n#define E1000_WVBR\t0x03554 /* VM Wrong Behavior - RWS */\n#define E1000_RPLOLR\t0x05AF0 /* Replication Offload - RW */\n#define E1000_UTA\t0x0A000 /* Unicast Table Array - RW */\n#define E1000_IOVCTL\t0x05BBC /* IOV Control Register */\n#define E1000_VMRCTL\t0X05D80 /* Virtual Mirror Rule Control */\n#define E1000_VMRVLAN\t0x05D90 /* Virtual Mirror Rule VLAN */\n#define E1000_VMRVM\t0x05DA0 /* Virtual Mirror Rule VM */\n#define E1000_MDFB\t0x03558 /* Malicious Driver free block */\n#define E1000_LVMMC\t0x03548 /* Last VM Misbehavior cause */\n#define E1000_TXSWC\t0x05ACC /* Tx Switch Control */\n#define E1000_SCCRL\t0x05DB0 /* Storm Control Control */\n#define E1000_BSCTRH\t0x05DB8 /* Broadcast Storm Control Threshold */\n#define E1000_MSCTRH\t0x05DBC /* Multicast Storm Control Threshold */\n/* These act per VF so an array friendly macro is used */\n#define E1000_V2PMAILBOX(_n)\t(0x00C40 + (4 * (_n)))\n#define E1000_P2VMAILBOX(_n)\t(0x00C00 + (4 * (_n)))\n#define E1000_VMBMEM(_n)\t(0x00800 + (64 * (_n)))\n#define E1000_VFVMBMEM(_n)\t(0x00800 + (_n))\n#define E1000_VMOLR(_n)\t\t(0x05AD0 + (4 * (_n)))\n/* VLAN Virtual Machine Filter - RW */\n#define E1000_VLVF(_n)\t\t(0x05D00 + (4 * (_n)))\n#define E1000_VMVIR(_n)\t\t(0x03700 + (4 * (_n)))\n#define E1000_DVMOLR(_n)\t(0x0C038 + (0x40 * (_n))) /* DMA VM offload */\n#define E1000_VTCTRL(_n)\t(0x10000 + (0x100 * (_n))) /* VT Control */\n#define E1000_TSYNCRXCTL\t0x0B620 /* Rx Time Sync Control register - RW */\n#define E1000_TSYNCTXCTL\t0x0B614 /* Tx Time Sync Control register - RW */\n#define E1000_TSYNCRXCFG\t0x05F50 /* Time Sync Rx Configuration - RW */\n#define E1000_RXSTMPL\t0x0B624 /* Rx timestamp Low - RO */\n#define E1000_RXSTMPH\t0x0B628 /* Rx timestamp High - RO */\n#define E1000_RXSATRL\t0x0B62C /* Rx timestamp attribute low - RO */\n#define E1000_RXSATRH\t0x0B630 /* Rx timestamp attribute high - RO */\n#define E1000_TXSTMPL\t0x0B618 /* Tx timestamp value Low - RO */\n#define E1000_TXSTMPH\t0x0B61C /* Tx timestamp value High - RO */\n#define E1000_SYSTIML\t0x0B600 /* System time register Low - RO */\n#define E1000_SYSTIMH\t0x0B604 /* System time register High - RO */\n#define E1000_TIMINCA\t0x0B608 /* Increment attributes register - RW */\n#define E1000_TIMADJL\t0x0B60C /* Time sync time adjustment offset Low - RW */\n#define E1000_TIMADJH\t0x0B610 /* Time sync time adjustment offset High - RW */\n#define E1000_TSAUXC\t0x0B640 /* Timesync Auxiliary Control register */\n#define\tE1000_SYSSTMPL\t0x0B648 /* HH Timesync system stamp low register */\n#define\tE1000_SYSSTMPH\t0x0B64C /* HH Timesync system stamp hi register */\n#define\tE1000_PLTSTMPL\t0x0B640 /* HH Timesync platform stamp low register */\n#define\tE1000_PLTSTMPH\t0x0B644 /* HH Timesync platform stamp hi register */\n#define E1000_SYSTIMR\t0x0B6F8 /* System time register Residue */\n#define E1000_TSICR\t0x0B66C /* Interrupt Cause Register */\n#define E1000_TSIM\t0x0B674 /* Interrupt Mask Register */\n#define E1000_RXMTRL\t0x0B634 /* Time sync Rx EtherType and Msg Type - RW */\n#define E1000_RXUDP\t0x0B638 /* Time Sync Rx UDP Port - RW */\n\n/* Filtering Registers */\n#define E1000_SAQF(_n)\t(0x05980 + (4 * (_n))) /* Source Address Queue Fltr */\n#define E1000_DAQF(_n)\t(0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */\n#define E1000_SPQF(_n)\t(0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */\n#define E1000_FTQF(_n)\t(0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */\n#define E1000_TTQF(_n)\t(0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */\n#define E1000_SYNQF(_n)\t(0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */\n#define E1000_ETQF(_n)\t(0x05CB0 + (4 * (_n))) /* EType Queue Fltr */\n\n#define E1000_RTTDCS\t0x3600 /* Reedtown Tx Desc plane control and status */\n#define E1000_RTTPCS\t0x3474 /* Reedtown Tx Packet Plane control and status */\n#define E1000_RTRPCS\t0x2474 /* Rx packet plane control and status */\n#define E1000_RTRUP2TC\t0x05AC4 /* Rx User Priority to Traffic Class */\n#define E1000_RTTUP2TC\t0x0418 /* Transmit User Priority to Traffic Class */\n/* Tx Desc plane TC Rate-scheduler config */\n#define E1000_RTTDTCRC(_n)\t(0x3610 + ((_n) * 4))\n/* Tx Packet plane TC Rate-Scheduler Config */\n#define E1000_RTTPTCRC(_n)\t(0x3480 + ((_n) * 4))\n/* Rx Packet plane TC Rate-Scheduler Config */\n#define E1000_RTRPTCRC(_n)\t(0x2480 + ((_n) * 4))\n/* Tx Desc Plane TC Rate-Scheduler Status */\n#define E1000_RTTDTCRS(_n)\t(0x3630 + ((_n) * 4))\n/* Tx Desc Plane TC Rate-Scheduler MMW */\n#define E1000_RTTDTCRM(_n)\t(0x3650 + ((_n) * 4))\n/* Tx Packet plane TC Rate-Scheduler Status */\n#define E1000_RTTPTCRS(_n)\t(0x34A0 + ((_n) * 4))\n/* Tx Packet plane TC Rate-scheduler MMW */\n#define E1000_RTTPTCRM(_n)\t(0x34C0 + ((_n) * 4))\n/* Rx Packet plane TC Rate-Scheduler Status */\n#define E1000_RTRPTCRS(_n)\t(0x24A0 + ((_n) * 4))\n/* Rx Packet plane TC Rate-Scheduler MMW */\n#define E1000_RTRPTCRM(_n)\t(0x24C0 + ((_n) * 4))\n/* Tx Desc plane VM Rate-Scheduler MMW*/\n#define E1000_RTTDVMRM(_n)\t(0x3670 + ((_n) * 4))\n/* Tx BCN Rate-Scheduler MMW */\n#define E1000_RTTBCNRM(_n)\t(0x3690 + ((_n) * 4))\n#define E1000_RTTDQSEL\t0x3604  /* Tx Desc Plane Queue Select */\n#define E1000_RTTDVMRC\t0x3608  /* Tx Desc Plane VM Rate-Scheduler Config */\n#define E1000_RTTDVMRS\t0x360C  /* Tx Desc Plane VM Rate-Scheduler Status */\n#define E1000_RTTBCNRC\t0x36B0  /* Tx BCN Rate-Scheduler Config */\n#define E1000_RTTBCNRS\t0x36B4  /* Tx BCN Rate-Scheduler Status */\n#define E1000_RTTBCNCR\t0xB200  /* Tx BCN Control Register */\n#define E1000_RTTBCNTG\t0x35A4  /* Tx BCN Tagging */\n#define E1000_RTTBCNCP\t0xB208  /* Tx BCN Congestion point */\n#define E1000_RTRBCNCR\t0xB20C  /* Rx BCN Control Register */\n#define E1000_RTTBCNRD\t0x36B8  /* Tx BCN Rate Drift */\n#define E1000_PFCTOP\t0x1080  /* Priority Flow Control Type and Opcode */\n#define E1000_RTTBCNIDX\t0xB204  /* Tx BCN Congestion Point */\n#define E1000_RTTBCNACH\t0x0B214 /* Tx BCN Control High */\n#define E1000_RTTBCNACL\t0x0B210 /* Tx BCN Control Low */\n\n/* DMA Coalescing registers */\n#define E1000_DMACR\t0x02508 /* Control Register */\n#define E1000_DMCTXTH\t0x03550 /* Transmit Threshold */\n#define E1000_DMCTLX\t0x02514 /* Time to Lx Request */\n#define E1000_DMCRTRH\t0x05DD0 /* Receive Packet Rate Threshold */\n#define E1000_DMCCNT\t0x05DD4 /* Current Rx Count */\n#define E1000_FCRTC\t0x02170 /* Flow Control Rx high watermark */\n#define E1000_PCIEMISC\t0x05BB8 /* PCIE misc config register */\n\n/* PCIe Parity Status Register */\n#define E1000_PCIEERRSTS\t0x05BA8\n\n#define E1000_PROXYS\t0x5F64 /* Proxying Status */\n#define E1000_PROXYFC\t0x5F60 /* Proxying Filter Control */\n/* Thermal sensor configuration and status registers */\n#define E1000_THMJT\t0x08100 /* Junction Temperature */\n#define E1000_THLOWTC\t0x08104 /* Low Threshold Control */\n#define E1000_THMIDTC\t0x08108 /* Mid Threshold Control */\n#define E1000_THHIGHTC\t0x0810C /* High Threshold Control */\n#define E1000_THSTAT\t0x08110 /* Thermal Sensor Status */\n\n/* Energy Efficient Ethernet \"EEE\" registers */\n#define E1000_IPCNFG\t0x0E38 /* Internal PHY Configuration */\n#define E1000_LTRC\t0x01A0 /* Latency Tolerance Reporting Control */\n#define E1000_EEER\t0x0E30 /* Energy Efficient Ethernet \"EEE\"*/\n#define E1000_EEE_SU\t0x0E34 /* EEE Setup */\n#define E1000_TLPIC\t0x4148 /* EEE Tx LPI Count - TLPIC */\n#define E1000_RLPIC\t0x414C /* EEE Rx LPI Count - RLPIC */\n\n/* OS2BMC Registers */\n#define E1000_B2OSPC\t0x08FE0 /* BMC2OS packets sent by BMC */\n#define E1000_B2OGPRC\t0x04158 /* BMC2OS packets received by host */\n#define E1000_O2BGPTC\t0x08FE4 /* OS2BMC packets received by BMC */\n#define E1000_O2BSPC\t0x0415C /* OS2BMC packets transmitted by host */\n\n#define E1000_DOBFFCTL\t0x3F24 /* DMA OBFF Control Register */\n\n\n#endif\n"
  },
  {
    "path": "include/xhyve/support/i8253reg.h",
    "content": "/*-\n * Copyright (c) 1993 The Regents of the University of California.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tfrom: Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp\n * $FreeBSD$\n */\n\n/*\n * Register definitions for the Intel 8253 Programmable Interval Timer.\n *\n * This chip has three independent 16-bit down counters that can be\n * read on the fly.  There are three mode registers and three countdown\n * registers.  The countdown registers are addressed directly, via the\n * first three I/O ports.  The three mode registers are accessed via\n * the fourth I/O port, with two bits in the mode byte indicating the\n * register.  (Why are hardware interfaces always so braindead?).\n *\n * To write a value into the countdown register, the mode register\n * is first programmed with a command indicating the which byte of\n * the two byte register is to be modified.  The three possibilities\n * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then\n * msb (TMR_MR_BOTH).\n *\n * To read the current value (\"on the fly\") from the countdown register,\n * you write a \"latch\" command into the mode register, then read the stable\n * value from the corresponding I/O port.  For example, you write\n * TMR_MR_LATCH into the corresponding mode register.  Presumably,\n * after doing this, a write operation to the I/O port would result\n * in undefined behavior (but hopefully not fry the chip).\n * Reading in this manner has no side effects.\n */\n\n/*\n * Macros for specifying values to be written into a mode register.\n */\n\n#pragma once\n\n#define\tTIMER_REG_CNTR0\t0\t/* timer 0 counter port */\n#define\tTIMER_REG_CNTR1\t1\t/* timer 1 counter port */\n#define\tTIMER_REG_CNTR2\t2\t/* timer 2 counter port */\n#define\tTIMER_REG_MODE\t3\t/* timer mode port */\n#define\t\tTIMER_SEL0\t0x00\t/* select counter 0 */\n#define\t\tTIMER_SEL1\t0x40\t/* select counter 1 */\n#define\t\tTIMER_SEL2\t0x80\t/* select counter 2 */\n#define\t\tTIMER_INTTC\t0x00\t/* mode 0, intr on terminal cnt */\n#define\t\tTIMER_ONESHOT\t0x02\t/* mode 1, one shot */\n#define\t\tTIMER_RATEGEN\t0x04\t/* mode 2, rate generator */\n#define\t\tTIMER_SQWAVE\t0x06\t/* mode 3, square wave */\n#define\t\tTIMER_SWSTROBE\t0x08\t/* mode 4, s/w triggered strobe */\n#define\t\tTIMER_HWSTROBE\t0x0a\t/* mode 5, h/w triggered strobe */\n#define\t\tTIMER_LATCH\t0x00\t/* latch counter for reading */\n#define\t\tTIMER_LSB\t0x10\t/* r/w counter LSB */\n#define\t\tTIMER_MSB\t0x20\t/* r/w counter MSB */\n#define\t\tTIMER_16BIT\t0x30\t/* r/w counter 16 bits, LSB first */\n#define\t\tTIMER_BCD\t0x01\t/* count in BCD */\n"
  },
  {
    "path": "include/xhyve/support/i8259.h",
    "content": "/*-\n * Copyright (c) 2003 Peter Wemm\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * Register defintions for the i8259A programmable interrupt controller.\n */\n\n#pragma once\n\n/* Initialization control word 1. Written to even address. */\n#define\tICW1_IC4\t0x01\t\t/* ICW4 present */\n#define\tICW1_SNGL\t0x02\t\t/* 1 = single, 0 = cascaded */\n#define\tICW1_ADI\t0x04\t\t/* 1 = 4, 0 = 8 byte vectors */\n#define\tICW1_LTIM\t0x08\t\t/* 1 = level trigger, 0 = edge */\n#define\tICW1_RESET\t0x10\t\t/* must be 1 */\n/* 0x20 - 0x80 - in 8080/8085 mode only */\n\n/* Initialization control word 2. Written to the odd address. */\n/* No definitions, it is the base vector of the IDT for 8086 mode */\n\n/* Initialization control word 3. Written to the odd address. */\n/* For a master PIC, bitfield indicating a slave 8259 on given input */\n/* For slave, lower 3 bits are the slave's ID binary id on master */\n\n/* Initialization control word 4. Written to the odd address. */\n#define\tICW4_8086\t0x01\t\t/* 1 = 8086, 0 = 8080 */\n#define\tICW4_AEOI\t0x02\t\t/* 1 = Auto EOI */\n#define\tICW4_MS\t\t0x04\t\t/* 1 = buffered master, 0 = slave */\n#define\tICW4_BUF\t0x08\t\t/* 1 = enable buffer mode */\n#define\tICW4_SFNM\t0x10\t\t/* 1 = special fully nested mode */\n\n/* Operation control words.  Written after initialization. */\n\n/* Operation control word type 1 */\n/*\n * No definitions.  Written to the odd address.  Bitmask for interrupts.\n * 1 = disabled.\n */\n\n/* Operation control word type 2.  Bit 3 (0x08) must be zero. Even address. */\n#define\tOCW2_L0\t\t0x01\t\t/* Level */\n#define\tOCW2_L1\t\t0x02\n#define\tOCW2_L2\t\t0x04\n/* 0x08 must be 0 to select OCW2 vs OCW3 */\n/* 0x10 must be 0 to select OCW2 vs ICW1 */\n#define\tOCW2_EOI\t0x20\t\t/* 1 = EOI */\n#define\tOCW2_SL\t\t0x40\t\t/* EOI mode */\n#define\tOCW2_R\t\t0x80\t\t/* EOI mode */\n\n/* Operation control word type 3.  Bit 3 (0x08) must be set. Even address. */\n#define\tOCW3_RIS\t0x01\t\t/* 1 = read IS, 0 = read IR */\n#define\tOCW3_RR\t\t0x02\t\t/* register read */\n#define\tOCW3_P\t\t0x04\t\t/* poll mode command */\n/* 0x08 must be 1 to select OCW3 vs OCW2 */\n#define\tOCW3_SEL\t0x08\t\t/* must be 1 */\n/* 0x10 must be 0 to select OCW3 vs ICW1 */\n#define\tOCW3_SMM\t0x20\t\t/* special mode mask */\n#define\tOCW3_ESMM\t0x40\t\t/* enable SMM */\n"
  },
  {
    "path": "include/xhyve/support/linker_set.h",
    "content": "/*-\n * Copyright (c) 1999 John D. Polstra\n * Copyright (c) 1999,2001 Peter Wemm <peter@FreeBSD.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/* xhyve: sort of working linker sets for MachO */\n\n#pragma once\n\n#define\t__GLOBL1(sym) __asm__(\".globl \" #sym)\n#define\t__GLOBL(sym) __GLOBL1(sym)\n#define\t__section(x) __attribute__((__section__(x)))\n\n/*\n * The following macros are used to declare global sets of objects, which\n * are collected by the linker into a `linker_set' as defined below.\n * For ELF, this is done by constructing a separate segment for each set.\n */\n\n#define\t__MAKE_SET_CONST const\n\n/*\n * Private macros, not to be used outside this header file.\n */\n#define __MAKE_SET(set, sym) \\\n\t__GLOBL(__CONCAT(__start_set_,set)); \\\n\t__GLOBL(__CONCAT(__stop_set_,set)); \\\n\tstatic void const * __MAKE_SET_CONST \\\n\t__set_##set##_sym_##sym __section(\"__\"#set\",__set\") \\\n\t__used = &(sym)\n\n/*\n * Public macros.\n */\n#define TEXT_SET(set, sym)\t__MAKE_SET(set, sym)\n#define DATA_SET(set, sym)\t__MAKE_SET(set, sym)\n#define BSS_SET(set, sym)\t__MAKE_SET(set, sym)\n#define ABS_SET(set, sym)\t__MAKE_SET(set, sym)\n#define SET_ENTRY(set, sym)\t__MAKE_SET(set, sym)\n\n/*\n * Initialize before referring to a given linker set.\n */\n#define SET_DECLARE(set, ptype) \\\n \textern ptype __weak *__CONCAT(__start_set_,set) \\\n \t\t__asm(\"segment$start$__\"#set); \\\n \textern ptype __weak *__CONCAT(__stop_set_,set) \\\n \t\t__asm(\"segment$end$__\"#set)\n\n#define SET_BEGIN(set) \\\n\t(&__CONCAT(__start_set_,set))\n#define SET_LIMIT(set) \\\n\t(&__CONCAT(__stop_set_,set))\n\n/*\n * Iterate over all the elements of a set.\n *\n * Sets always contain addresses of things, and \"pvar\" points to words\n * containing those addresses.  Thus is must be declared as \"type **pvar\",\n * and the address of each set item is obtained inside the loop by \"*pvar\".\n */\n#define SET_FOREACH(pvar, set) \\\n\tfor (pvar = SET_BEGIN(set); pvar < SET_LIMIT(set); pvar++)\n\n#define SET_ITEM(set, i) \\\n\t((SET_BEGIN(set))[i])\n\n/*\n * Provide a count of the items in a set.\n */\n#define SET_COUNT(set) \\\n\t(SET_LIMIT(set) - SET_BEGIN(set))\n"
  },
  {
    "path": "include/xhyve/support/misc.h",
    "content": "#pragma once\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#define UNUSED __attribute__ ((unused))\n#define CTASSERT(x) _Static_assert ((x), \"CTASSERT\")\n#define XHYVE_PAGE_SIZE 0x1000\n#define XHYVE_PAGE_MASK (XHYVE_PAGE_SIZE - 1)\n#define XHYVE_PAGE_SHIFT 12\n#define __aligned(x) __attribute__ ((aligned ((x))))\n#define __packed __attribute__ ((packed))\n#define nitems(x) (sizeof((x)) / sizeof((x)[0]))\n#define powerof2(x)\t((((x)-1)&(x))==0)\n#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */\n#define nitems(x) (sizeof((x)) / sizeof((x)[0]))\n#define min(x, y) (((x) < (y)) ? (x) : (y))\n\n#define xhyve_abort(...) \\\n\tdo { \\\n\t\tfprintf(stderr, __VA_ARGS__); \\\n\t\tabort(); \\\n\t} while (0)\n\n#define xhyve_warn(...) \\\n\tdo { \\\n\t\tfprintf(stderr, __VA_ARGS__); \\\n\t} while (0)\n\n#ifdef XHYVE_CONFIG_ASSERT\n#define KASSERT(exp, msg) if (!(exp)) xhyve_abort msg\n#define KWARN(exp, msg) if (!(exp)) xhyve_warn msg\n#else\n#define KASSERT(exp, msg) if (0) xhyve_abort msg\n#define KWARN(exp, msg) if (0) xhyve_warn msg\n#endif\n\n#define FALSE 0\n#define TRUE 1\n\n#define XHYVE_PROT_READ 1\n#define XHYVE_PROT_WRITE 2\n#define XHYVE_PROT_EXECUTE 4\n\n#define\tVM_SUCCESS 0\n\n/* sys/sys/types.h */\ntypedef\tunsigned char u_char;\ntypedef\tunsigned short u_short;\ntypedef\tunsigned int u_int;\ntypedef\tunsigned long u_long;\n\nstatic inline void cpuid_count(uint32_t ax, uint32_t cx, uint32_t *p) {\n\t__asm__ __volatile__ (\"cpuid\"\n\t\t: \"=a\" (p[0]), \"=b\" (p[1]), \"=c\" (p[2]), \"=d\" (p[3])\n\t\t:  \"0\" (ax), \"c\" (cx));\n}\n\nstatic inline void do_cpuid(unsigned ax, unsigned *p) {\n\t__asm__ __volatile__ (\"cpuid\"\n\t\t: \"=a\" (p[0]), \"=b\" (p[1]), \"=c\" (p[2]), \"=d\" (p[3])\n\t\t:  \"0\" (ax));\n}\n\n/*\n * read_uint16_unaligned, write_uint16_unaligned,\n * read_uint32_unaligned, write_uint32_unaligned\n * read_uint64_unaligned, write_uint64_unaligned\n *\n * Routines to handle unaligned reads/writes - these are nop on AMD64 but routing\n * the reads through these bottlenecks silences the warning and provides a place\n * to put #if code to handle architectures where aligment matters (if it is ever needed).\n */\n\nstatic inline uint16_t read_uint16_unaligned(void *pointer) {\n    uint16_t *castPointer = (uint16_t *)pointer;\n    return *castPointer;\n}\n\nstatic inline void write_uint16_unaligned(void *pointer, uint16_t data) {\n    uint16_t *castPointer = (uint16_t *)pointer;\n    *castPointer = data;\n}\n\nstatic inline uint32_t read_uint32_unaligned(void *pointer) {\n    uint32_t *castPointer = (uint32_t *)pointer;\n    return *castPointer;\n}\n\nstatic inline void write_uint32_unaligned(void *pointer, uint32_t data) {\n    uint32_t *castPointer = (uint32_t *)pointer;\n    *castPointer = data;\n}\n\nstatic inline uint64_t read_uint64_unaligned(void *pointer) {\n    uint64_t *castPointer = (uint64_t *)pointer;\n    return *castPointer;\n}\n\nstatic inline void write_uint64_unaligned(void *pointer, uint64_t data) {\n    uint64_t *castPointer = (uint64_t *)pointer;\n    *castPointer = data;\n}\n"
  },
  {
    "path": "include/xhyve/support/mptable.h",
    "content": "/*-\n * Copyright (c) 1996, by Steve Passe\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. The name of the developer may NOT be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/misc.h>\n\nenum busTypes {\n    NOBUS = 0,\n    CBUS = 1,\n    CBUSII = 2,\n    EISA = 3,\n    ISA = 6,\n    MCA = 9,\n    PCI = 13,\n    XPRESS = 18,\n    MAX_BUSTYPE = 18,\n    UNKNOWN_BUSTYPE = 0xff\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\n\n/* MP Floating Pointer Structure */\ntypedef struct MPFPS {\n\tuint8_t\tsignature[4];\n\tuint32_t pap;\n\tuint8_t\tlength;\n\tuint8_t\tspec_rev;\n\tuint8_t\tchecksum;\n\tuint8_t\tconfig_type;\n\tuint8_t\tmpfb2;\n\tuint8_t\tmpfb3;\n\tuint8_t\tmpfb4;\n\tuint8_t\tmpfb5;\n} __packed *mpfps_t;\n\n#define\tMPFB2_IMCR_PRESENT\t0x80\n#define\tMPFB2_MUL_CLK_SRCS\t0x40\n\n/* MP Configuration Table Header */\ntypedef struct MPCTH {\n\tuint8_t\tsignature[4];\n\tuint16_t base_table_length;\n\tuint8_t\tspec_rev;\n\tuint8_t\tchecksum;\n\tuint8_t\toem_id[8];\n\tuint8_t\tproduct_id[12];\n\tuint32_t oem_table_pointer;\n\tuint16_t oem_table_size;\n\tuint16_t entry_count;\n\tuint32_t apic_address;\n\tuint16_t extended_table_length;\n\tuint8_t\textended_table_checksum;\n\tuint8_t\treserved;\n} __packed *mpcth_t;\n\n/* Base table entries */\n\n#define\tMPCT_ENTRY_PROCESSOR\t0\n#define\tMPCT_ENTRY_BUS\t\t1\n#define\tMPCT_ENTRY_IOAPIC\t2\n#define\tMPCT_ENTRY_INT\t\t3\n#define\tMPCT_ENTRY_LOCAL_INT\t4\n\ntypedef struct PROCENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tapic_id;\n\tuint8_t\tapic_version;\n\tuint8_t\tcpu_flags;\n\tuint32_t cpu_signature;\n\tuint32_t feature_flags;\n\tuint32_t reserved1;\n\tuint32_t reserved2;\n} __packed *proc_entry_ptr;\n\n#define PROCENTRY_FLAG_EN\t0x01\n#define PROCENTRY_FLAG_BP\t0x02\n\ntypedef struct BUSENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tbus_id;\n\tuint8_t\tbus_type[6];\n} __packed *bus_entry_ptr;\n\ntypedef struct IOAPICENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tapic_id;\n\tuint8_t\tapic_version;\n\tuint8_t\tapic_flags;\n\tuint32_t apic_address;\n} __packed *io_apic_entry_ptr;\n\n#define IOAPICENTRY_FLAG_EN\t0x01\n\ntypedef struct INTENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tint_type;\n\tuint16_t int_flags;\n\tuint8_t\tsrc_bus_id;\n\tuint8_t\tsrc_bus_irq;\n\tuint8_t\tdst_apic_id;\n\tuint8_t\tdst_apic_int;\n} __packed *int_entry_ptr;\n\n#define\tINTENTRY_TYPE_INT  \t0\n#define\tINTENTRY_TYPE_NMI\t1\n#define\tINTENTRY_TYPE_SMI\t2\n#define\tINTENTRY_TYPE_EXTINT\t3\n\n#define\tINTENTRY_FLAGS_POLARITY\t\t\t0x3\n#define\tINTENTRY_FLAGS_POLARITY_CONFORM\t\t0x0\n#define\tINTENTRY_FLAGS_POLARITY_ACTIVEHI\t0x1\n#define\tINTENTRY_FLAGS_POLARITY_ACTIVELO\t0x3\n#define\tINTENTRY_FLAGS_TRIGGER\t\t\t0xc\n#define\tINTENTRY_FLAGS_TRIGGER_CONFORM\t\t0x0\n#define\tINTENTRY_FLAGS_TRIGGER_EDGE\t\t0x4\n#define\tINTENTRY_FLAGS_TRIGGER_LEVEL\t\t0xc\n\n/* Extended table entries */\n\ntypedef\tstruct EXTENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tlength;\n} __packed *ext_entry_ptr;\n\n#define\tMPCT_EXTENTRY_SAS\t0x80\n#define\tMPCT_EXTENTRY_BHD\t0x81\n#define\tMPCT_EXTENTRY_CBASM\t0x82\n\ntypedef struct SASENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tlength;\n\tuint8_t\tbus_id;\n\tuint8_t\taddress_type;\n\tuint64_t address_base;\n\tuint64_t address_length;\n} __packed *sas_entry_ptr;\n\n#define\tSASENTRY_TYPE_IO\t0\n#define\tSASENTRY_TYPE_MEMORY\t1\n#define\tSASENTRY_TYPE_PREFETCH\t2\n\ntypedef struct BHDENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tlength;\n\tuint8_t\tbus_id;\n\tuint8_t\tbus_info;\n\tuint8_t\tparent_bus;\n\tuint8_t\treserved[3];\n} __packed *bhd_entry_ptr;\n\n#define\tBHDENTRY_INFO_SUBTRACTIVE_DECODE\t0x1\n\ntypedef struct CBASMENTRY {\n\tuint8_t\ttype;\n\tuint8_t\tlength;\n\tuint8_t\tbus_id;\n\tuint8_t\taddress_mod;\n\tuint32_t predefined_range;\n} __packed *cbasm_entry_ptr;\n\n#define\tCBASMENTRY_ADDRESS_MOD_ADD\t\t0x0\n#define\tCBASMENTRY_ADDRESS_MOD_SUBTRACT\t\t0x1\n\n#define\tCBASMENTRY_RANGE_ISA_IO\t\t0\n#define\tCBASMENTRY_RANGE_VGA_IO\t\t1\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "include/xhyve/support/ns16550.h",
    "content": "/*-\n * Copyright (c) 1991 The Regents of the University of California.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tfrom: @(#)ns16550.h\t7.1 (Berkeley) 5/9/91\n * $FreeBSD$\n */\n\n/*\n * NS8250... UART registers.\n */\n\n/* 8250 registers #[0-6]. */\n\n#pragma once\n\n#define\tcom_data\t0\t/* data register (R/W) */\n#define\tREG_DATA\tcom_data\n\n#define\tcom_ier\t\t1\t/* interrupt enable register (W) */\n#define\tREG_IER\t\tcom_ier\n#define\tIER_ERXRDY\t0x1\n#define\tIER_ETXRDY\t0x2\n#define\tIER_ERLS\t0x4\n#define\tIER_EMSC\t0x8\n\n#define\tIER_BITS\t\"\\20\\1ERXRDY\\2ETXRDY\\3ERLS\\4EMSC\"\n\n#define\tcom_iir\t\t2\t/* interrupt identification register (R) */\n#define\tREG_IIR\t\tcom_iir\n#define\tIIR_IMASK\t0xf\n#define\tIIR_RXTOUT\t0xc\n#define\tIIR_BUSY\t0x7\n#define\tIIR_RLS\t\t0x6\n#define\tIIR_RXRDY\t0x4\n#define\tIIR_TXRDY\t0x2\n#define\tIIR_NOPEND\t0x1\n#define\tIIR_MLSC\t0x0\n#define\tIIR_FIFO_MASK\t0xc0\t/* set if FIFOs are enabled */\n\n#define\tIIR_BITS\t\"\\20\\1NOPEND\\2TXRDY\\3RXRDY\"\n\n#define\tcom_lcr\t\t3\t/* line control register (R/W) */\n#define\tcom_cfcr\tcom_lcr\t/* character format control register (R/W) */\n#define\tREG_LCR\t\tcom_lcr\n#define\tLCR_DLAB\t0x80\n#define\tCFCR_DLAB\tLCR_DLAB\n#define\tLCR_EFR_ENABLE\t0xbf\t/* magic to enable EFR on 16650 up */\n#define\tCFCR_EFR_ENABLE\tLCR_EFR_ENABLE\n#define\tLCR_SBREAK\t0x40\n#define\tCFCR_SBREAK\tLCR_SBREAK\n#define\tLCR_PZERO\t0x30\n#define\tCFCR_PZERO\tLCR_PZERO\n#define\tLCR_PONE\t0x20\n#define\tCFCR_PONE\tLCR_PONE\n#define\tLCR_PEVEN\t0x10\n#define\tCFCR_PEVEN\tLCR_PEVEN\n#define\tLCR_PODD\t0x00\n#define\tCFCR_PODD\tLCR_PODD\n#define\tLCR_PENAB\t0x08\n#define\tCFCR_PENAB\tLCR_PENAB\n#define\tLCR_STOPB\t0x04\n#define\tCFCR_STOPB\tLCR_STOPB\n#define\tLCR_8BITS\t0x03\n#define\tCFCR_8BITS\tLCR_8BITS\n#define\tLCR_7BITS\t0x02\n#define\tCFCR_7BITS\tLCR_7BITS\n#define\tLCR_6BITS\t0x01\n#define\tCFCR_6BITS\tLCR_6BITS\n#define\tLCR_5BITS\t0x00\n#define\tCFCR_5BITS\tLCR_5BITS\n\n#define\tcom_mcr\t\t4\t/* modem control register (R/W) */\n#define\tREG_MCR\t\tcom_mcr\n#define\tMCR_PRESCALE\t0x80\t/* only available on 16650 up */\n#define\tMCR_LOOPBACK\t0x10\n#define\tMCR_IE\t\t0x08\n#define\tMCR_IENABLE\tMCR_IE\n#define\tMCR_DRS\t\t0x04\n#define\tMCR_RTS\t\t0x02\n#define\tMCR_DTR\t\t0x01\n\n#define\tMCR_BITS\t\"\\20\\1DTR\\2RTS\\3DRS\\4IE\\5LOOPBACK\\10PRESCALE\"\n\n#define\tcom_lsr\t\t5\t/* line status register (R/W) */\n#define\tREG_LSR\t\tcom_lsr\n#define\tLSR_RCV_FIFO\t0x80\n#define\tLSR_TEMT\t0x40\n#define\tLSR_TSRE\tLSR_TEMT\n#define\tLSR_THRE\t0x20\n#define\tLSR_TXRDY\tLSR_THRE\n#define\tLSR_BI\t\t0x10\n#define\tLSR_FE\t\t0x08\n#define\tLSR_PE\t\t0x04\n#define\tLSR_OE\t\t0x02\n#define\tLSR_RXRDY\t0x01\n#define\tLSR_RCV_MASK\t0x1f\n\n#define\tLSR_BITS\t\"\\20\\1RXRDY\\2OE\\3PE\\4FE\\5BI\\6THRE\\7TEMT\\10RCV_FIFO\"\n\n#define\tcom_msr\t\t6\t/* modem status register (R/W) */\n#define\tREG_MSR\t\tcom_msr\n#define\tMSR_DCD\t\t0x80\n#define\tMSR_RI\t\t0x40\n#define\tMSR_DSR\t\t0x20\n#define\tMSR_CTS\t\t0x10\n#define\tMSR_DDCD\t0x08\n#define\tMSR_TERI\t0x04\n#define\tMSR_DDSR\t0x02\n#define\tMSR_DCTS\t0x01\n\n#define\tMSR_BITS\t\"\\20\\1DCTS\\2DDSR\\3TERI\\4DDCD\\5CTS\\6DSR\\7RI\\10DCD\"\n\n/* 8250 multiplexed registers #[0-1].  Access enabled by LCR[7]. */\n#define\tcom_dll\t\t0\t/* divisor latch low (R/W) */\n#define\tcom_dlbl\tcom_dll\n#define\tcom_dlm\t\t1\t/* divisor latch high (R/W) */\n#define\tcom_dlbh\tcom_dlm\n#define\tREG_DLL\t\tcom_dll\n#define\tREG_DLH\t\tcom_dlm\n\n/* 16450 register #7.  Not multiplexed. */\n#define\tcom_scr\t\t7\t/* scratch register (R/W) */\n\n/* 16550 register #2.  Not multiplexed. */\n#define\tcom_fcr\t\t2\t/* FIFO control register (W) */\n#define\tcom_fifo\tcom_fcr\n#define\tREG_FCR\t\tcom_fcr\n#define\tFCR_ENABLE\t0x01\n#define\tFIFO_ENABLE\tFCR_ENABLE\n#define\tFCR_RCV_RST\t0x02\n#define\tFIFO_RCV_RST\tFCR_RCV_RST\n#define\tFCR_XMT_RST\t0x04\n#define\tFIFO_XMT_RST\tFCR_XMT_RST\n#define\tFCR_DMA\t\t0x08\n#define\tFIFO_DMA_MODE\tFCR_DMA\n#define\tFCR_RX_LOW\t0x00\n#define\tFIFO_RX_LOW\tFCR_RX_LOW\n#define\tFCR_RX_MEDL\t0x40\n#define\tFIFO_RX_MEDL\tFCR_RX_MEDL\n#define\tFCR_RX_MEDH\t0x80\n#define\tFIFO_RX_MEDH\tFCR_RX_MEDH\n#define\tFCR_RX_HIGH\t0xc0\n#define\tFIFO_RX_HIGH\tFCR_RX_HIGH\n\n#define\tFCR_BITS\t\"\\20\\1ENABLE\\2RCV_RST\\3XMT_RST\\4DMA\"\n\n/* 16650 registers #2,[4-7].  Access enabled by LCR_EFR_ENABLE. */\n\n#define\tcom_efr\t\t2\t/* enhanced features register (R/W) */\n#define\tREG_EFR\t\tcom_efr\n#define\tEFR_CTS\t\t0x80\n#define\tEFR_AUTOCTS\tEFR_CTS\n#define\tEFR_RTS\t\t0x40\n#define\tEFR_AUTORTS\tEFR_RTS\n#define\tEFR_EFE\t\t0x10\t/* enhanced functions enable */\n\n#define\tcom_xon1\t4\t/* XON 1 character (R/W) */\n#define\tcom_xon2\t5\t/* XON 2 character (R/W) */\n#define\tcom_xoff1\t6\t/* XOFF 1 character (R/W) */\n#define\tcom_xoff2\t7\t/* XOFF 2 character (R/W) */\n\n#define DW_REG_USR\t31\t/* DesignWare derived Uart Status Reg */\n#define com_usr\t\t39\t/* Octeon 16750/16550 Uart Status Reg */\n#define REG_USR\t\tcom_usr\n#define USR_BUSY\t1\t/* Uart Busy. Serial transfer in progress */\n#define USR_TXFIFO_NOTFULL 2    /* Uart TX FIFO Not full */\n\n/* 16950 register #1.  Access enabled by ACR[7].  Also requires !LCR[7]. */\n#define\tcom_asr\t\t1\t/* additional status register (R[0-7]/W[0-1]) */\n\n/* 16950 register #3.  R/W access enabled by ACR[7]. */\n#define\tcom_rfl\t\t3\t/* receiver fifo level (R) */\n\n/*\n * 16950 register #4.  Access enabled by ACR[7].  Also requires\n * !LCR_EFR_ENABLE.\n */\n#define\tcom_tfl\t\t4\t/* transmitter fifo level (R) */\n\n/*\n * 16950 register #5.  Accessible if !LCR_EFR_ENABLE.  Read access also\n * requires ACR[6].\n */\n#define\tcom_icr\t\t5\t/* index control register (R/W) */\n\n/*\n * 16950 register #7.  It is the same as com_scr except it has a different\n * abbreviation in the manufacturer's data sheet and it also serves as an\n * index into the Indexed Control register set.\n */\n#define\tcom_spr\t\tcom_scr\t/* scratch pad (and index) register (R/W) */\n#define\tREG_SPR\t\tcom_scr\n\n/*\n * 16950 indexed control registers #[0-0x13].  Access is via index in SPR,\n * data in ICR (if ICR is accessible).\n */\n\n#define\tcom_acr\t\t0\t/* additional control register (R/W) */\n#define\tACR_ASE\t\t0x80\t/* ASR/RFL/TFL enable */\n#define\tACR_ICRE\t0x40\t/* ICR enable */\n#define\tACR_TLE\t\t0x20\t/* TTL/RTL enable */\n\n#define\tcom_cpr\t\t1\t/* clock prescaler register (R/W) */\n#define\tcom_tcr\t\t2\t/* times clock register (R/W) */\n#define\tcom_ttl\t\t4\t/* transmitter trigger level (R/W) */\n#define\tcom_rtl\t\t5\t/* receiver trigger level (R/W) */\n/* ... */\n\n/* Hardware extension mode register for RSB-2000/3000. */\n#define\tcom_emr\t\tcom_msr\n#define\tEMR_EXBUFF\t0x04\n#define\tEMR_CTSFLW\t0x08\n#define\tEMR_DSRFLW\t0x10\n#define\tEMR_RTSFLW\t0x20\n#define\tEMR_DTRFLW\t0x40\n#define\tEMR_EFMODE\t0x80\n"
  },
  {
    "path": "include/xhyve/support/pcireg.h",
    "content": "/*-\n * Copyright (c) 1997, Stefan Esser <se@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n *\n */\n\n#pragma once\n\n/*\n * PCIM_xxx: mask to locate subfield in register\n * PCIR_xxx: config register offset\n * PCIC_xxx: device class\n * PCIS_xxx: device subclass\n * PCIP_xxx: device programming interface\n * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices)\n * PCID_xxx: device ID\n * PCIY_xxx: capability identification number\n * PCIZ_xxx: extended capability identification number\n */\n\n/* some PCI bus constants */\n#define\tPCI_DOMAINMAX\t65535\t/* highest supported domain number */\n#define\tPCI_BUSMAX\t255\t/* highest supported bus number */\n#define\tPCI_SLOTMAX\t31\t/* highest supported slot number */\n#define\tPCI_FUNCMAX\t7\t/* highest supported function number */\n#define\tPCI_REGMAX\t255\t/* highest supported config register addr. */\n#define\tPCIE_REGMAX\t4095\t/* highest supported config register addr. */\n#define\tPCI_MAXHDRTYPE\t2\n\n#define\tPCIE_ARI_SLOTMAX 0\n#define\tPCIE_ARI_FUNCMAX 255\n\n#define\tPCI_RID_BUS_SHIFT\t8\n#define\tPCI_RID_SLOT_SHIFT\t3\n#define\tPCI_RID_FUNC_SHIFT\t0\n\n#define PCI_RID(bus, slot, func) \\\n    ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \\\n    (((slot) & PCI_SLOTMAX) << PCI_RID_SLOT_SHIFT) | \\\n    (((func) & PCI_FUNCMAX) << PCI_RID_FUNC_SHIFT))\n\n#define PCI_ARI_RID(bus, func) \\\n    ((((bus) & PCI_BUSMAX) << PCI_RID_BUS_SHIFT) | \\\n    (((func) & PCIE_ARI_FUNCMAX) << PCI_RID_FUNC_SHIFT))\n\n#define PCI_RID2BUS(rid) (((rid) >> PCI_RID_BUS_SHIFT) & PCI_BUSMAX)\n#define PCI_RID2SLOT(rid) (((rid) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX)\n#define PCI_RID2FUNC(rid) (((rid) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX)\n\n#define PCIE_ARI_RID2SLOT(rid) (0)\n#define PCIE_ARI_RID2FUNC(rid) \\\n    (((rid) >> PCI_RID_FUNC_SHIFT) & PCIE_ARI_FUNCMAX)\n\n#define PCIE_ARI_SLOT(func) (((func) >> PCI_RID_SLOT_SHIFT) & PCI_SLOTMAX)\n#define PCIE_ARI_FUNC(func) (((func) >> PCI_RID_FUNC_SHIFT) & PCI_FUNCMAX)\n\n/* PCI config header registers for all devices */\n\n#define\tPCIR_DEVVENDOR\t0x00\n#define\tPCIR_VENDOR\t0x00\n#define\tPCIR_DEVICE\t0x02\n#define\tPCIR_COMMAND\t0x04\n#define\tPCIM_CMD_PORTEN\t\t0x0001\n#define\tPCIM_CMD_MEMEN\t\t0x0002\n#define\tPCIM_CMD_BUSMASTEREN\t0x0004\n#define\tPCIM_CMD_SPECIALEN\t0x0008\n#define\tPCIM_CMD_MWRICEN\t0x0010\n#define\tPCIM_CMD_PERRESPEN\t0x0040\n#define\tPCIM_CMD_SERRESPEN\t0x0100\n#define\tPCIM_CMD_BACKTOBACK\t0x0200\n#define\tPCIM_CMD_INTxDIS\t0x0400\n#define\tPCIR_STATUS\t0x06\n#define\tPCIM_STATUS_INTxSTATE\t0x0008\n#define\tPCIM_STATUS_CAPPRESENT\t0x0010\n#define\tPCIM_STATUS_66CAPABLE\t0x0020\n#define\tPCIM_STATUS_BACKTOBACK\t0x0080\n#define\tPCIM_STATUS_MDPERR\t0x0100\n#define\tPCIM_STATUS_SEL_FAST\t0x0000\n#define\tPCIM_STATUS_SEL_MEDIMUM\t0x0200\n#define\tPCIM_STATUS_SEL_SLOW\t0x0400\n#define\tPCIM_STATUS_SEL_MASK\t0x0600\n#define\tPCIM_STATUS_STABORT\t0x0800\n#define\tPCIM_STATUS_RTABORT\t0x1000\n#define\tPCIM_STATUS_RMABORT\t0x2000\n#define\tPCIM_STATUS_SERR\t0x4000\n#define\tPCIM_STATUS_PERR\t0x8000\n#define\tPCIR_REVID\t0x08\n#define\tPCIR_PROGIF\t0x09\n#define\tPCIR_SUBCLASS\t0x0a\n#define\tPCIR_CLASS\t0x0b\n#define\tPCIR_CACHELNSZ\t0x0c\n#define\tPCIR_LATTIMER\t0x0d\n#define\tPCIR_HDRTYPE\t0x0e\n#define\tPCIM_HDRTYPE\t\t0x7f\n#define\tPCIM_HDRTYPE_NORMAL\t0x00\n#define\tPCIM_HDRTYPE_BRIDGE\t0x01\n#define\tPCIM_HDRTYPE_CARDBUS\t0x02\n#define\tPCIM_MFDEV\t\t0x80\n#define\tPCIR_BIST\t0x0f\n\n/* Capability Register Offsets */\n\n#define\tPCICAP_ID\t0x0\n#define\tPCICAP_NEXTPTR\t0x1\n\n/* Capability Identification Numbers */\n\n#define\tPCIY_PMG\t0x01\t/* PCI Power Management */\n#define\tPCIY_AGP\t0x02\t/* AGP */\n#define\tPCIY_VPD\t0x03\t/* Vital Product Data */\n#define\tPCIY_SLOTID\t0x04\t/* Slot Identification */\n#define\tPCIY_MSI\t0x05\t/* Message Signaled Interrupts */\n#define\tPCIY_CHSWP\t0x06\t/* CompactPCI Hot Swap */\n#define\tPCIY_PCIX\t0x07\t/* PCI-X */\n#define\tPCIY_HT\t\t0x08\t/* HyperTransport */\n#define\tPCIY_VENDOR\t0x09\t/* Vendor Unique */\n#define\tPCIY_DEBUG\t0x0a\t/* Debug port */\n#define\tPCIY_CRES\t0x0b\t/* CompactPCI central resource control */\n#define\tPCIY_HOTPLUG\t0x0c\t/* PCI Hot-Plug */\n#define\tPCIY_SUBVENDOR\t0x0d\t/* PCI-PCI bridge subvendor ID */\n#define\tPCIY_AGP8X\t0x0e\t/* AGP 8x */\n#define\tPCIY_SECDEV\t0x0f\t/* Secure Device */\n#define\tPCIY_EXPRESS\t0x10\t/* PCI Express */\n#define\tPCIY_MSIX\t0x11\t/* MSI-X */\n#define\tPCIY_SATA\t0x12\t/* SATA */\n#define\tPCIY_PCIAF\t0x13\t/* PCI Advanced Features */\n\n/* Extended Capability Register Fields */\n\n#define\tPCIR_EXTCAP\t0x100\n#define\tPCIM_EXTCAP_ID\t\t0x0000ffff\n#define\tPCIM_EXTCAP_VER\t\t0x000f0000\n#define\tPCIM_EXTCAP_NEXTPTR\t0xfff00000\n#define\tPCI_EXTCAP_ID(ecap)\t((ecap) & PCIM_EXTCAP_ID)\n#define\tPCI_EXTCAP_VER(ecap)\t(((ecap) & PCIM_EXTCAP_VER) >> 16)\n#define\tPCI_EXTCAP_NEXTPTR(ecap) (((ecap) & PCIM_EXTCAP_NEXTPTR) >> 20)\n\n/* Extended Capability Identification Numbers */\n\n#define\tPCIZ_AER\t0x0001\t/* Advanced Error Reporting */\n#define\tPCIZ_VC\t\t0x0002\t/* Virtual Channel if MFVC Ext Cap not set */\n#define\tPCIZ_SERNUM\t0x0003\t/* Device Serial Number */\n#define\tPCIZ_PWRBDGT\t0x0004\t/* Power Budgeting */\n#define\tPCIZ_RCLINK_DCL\t0x0005\t/* Root Complex Link Declaration */\n#define\tPCIZ_RCLINK_CTL\t0x0006\t/* Root Complex Internal Link Control */\n#define\tPCIZ_RCEC_ASSOC\t0x0007\t/* Root Complex Event Collector Association */\n#define\tPCIZ_MFVC\t0x0008\t/* Multi-Function Virtual Channel */\n#define\tPCIZ_VC2\t0x0009\t/* Virtual Channel if MFVC Ext Cap set */\n#define\tPCIZ_RCRB\t0x000a\t/* RCRB Header */\n#define\tPCIZ_VENDOR\t0x000b\t/* Vendor Unique */\n#define\tPCIZ_CAC\t0x000c\t/* Configuration Access Correction -- obsolete */\n#define\tPCIZ_ACS\t0x000d\t/* Access Control Services */\n#define\tPCIZ_ARI\t0x000e\t/* Alternative Routing-ID Interpretation */\n#define\tPCIZ_ATS\t0x000f\t/* Address Translation Services */\n#define\tPCIZ_SRIOV\t0x0010\t/* Single Root IO Virtualization */\n#define\tPCIZ_MRIOV\t0x0011\t/* Multiple Root IO Virtualization */\n#define\tPCIZ_MULTICAST\t0x0012\t/* Multicast */\n#define\tPCIZ_PAGE_REQ\t0x0013\t/* Page Request */\n#define\tPCIZ_AMD\t0x0014\t/* Reserved for AMD */\n#define\tPCIZ_RESIZE_BAR\t0x0015\t/* Resizable BAR */\n#define\tPCIZ_DPA\t0x0016\t/* Dynamic Power Allocation */\n#define\tPCIZ_TPH_REQ\t0x0017\t/* TPH Requester */\n#define\tPCIZ_LTR\t0x0018\t/* Latency Tolerance Reporting */\n#define\tPCIZ_SEC_PCIE\t0x0019\t/* Secondary PCI Express */\n#define\tPCIZ_PMUX\t0x001a\t/* Protocol Multiplexing */\n#define\tPCIZ_PASID\t0x001b\t/* Process Address Space ID */\n#define\tPCIZ_LN_REQ\t0x001c\t/* LN Requester */\n#define\tPCIZ_DPC\t0x001d\t/* Downstream Porto Containment */\n#define\tPCIZ_L1PM\t0x001e\t/* L1 PM Substates */\n\n/* config registers for header type 0 devices */\n\n#define\tPCIR_BARS\t0x10\n#define\tPCIR_BAR(x)\t\t(PCIR_BARS + (x) * 4)\n#define\tPCIR_MAX_BAR_0\t\t5\n#define\tPCI_RID2BAR(rid)\t(((rid) - PCIR_BARS) / 4)\n#define\tPCI_BAR_IO(x)\t\t(((x) & PCIM_BAR_SPACE) == PCIM_BAR_IO_SPACE)\n#define\tPCI_BAR_MEM(x)\t\t(((x) & PCIM_BAR_SPACE) == PCIM_BAR_MEM_SPACE)\n#define\tPCIM_BAR_SPACE\t\t0x00000001\n#define\tPCIM_BAR_MEM_SPACE\t0\n#define\tPCIM_BAR_IO_SPACE\t1\n#define\tPCIM_BAR_MEM_TYPE\t0x00000006\n#define\tPCIM_BAR_MEM_32\t\t0\n#define\tPCIM_BAR_MEM_1MB\t2\t/* Locate below 1MB in PCI <= 2.1 */\n#define\tPCIM_BAR_MEM_64\t\t4\n#define\tPCIM_BAR_MEM_PREFETCH\t0x00000008\n#define\tPCIM_BAR_MEM_BASE\t0xfffffffffffffff0ULL\n#define\tPCIM_BAR_IO_RESERVED\t0x00000002\n#define\tPCIM_BAR_IO_BASE\t0xfffffffc\n#define\tPCIR_CIS\t0x28\n#define\tPCIM_CIS_ASI_MASK\t0x00000007\n#define\tPCIM_CIS_ASI_CONFIG\t0\n#define\tPCIM_CIS_ASI_BAR0\t1\n#define\tPCIM_CIS_ASI_BAR1\t2\n#define\tPCIM_CIS_ASI_BAR2\t3\n#define\tPCIM_CIS_ASI_BAR3\t4\n#define\tPCIM_CIS_ASI_BAR4\t5\n#define\tPCIM_CIS_ASI_BAR5\t6\n#define\tPCIM_CIS_ASI_ROM\t7\n#define\tPCIM_CIS_ADDR_MASK\t0x0ffffff8\n#define\tPCIM_CIS_ROM_MASK\t0xf0000000\n#define\tPCIM_CIS_CONFIG_MASK\t0xff\n#define\tPCIR_SUBVEND_0\t0x2c\n#define\tPCIR_SUBDEV_0\t0x2e\n#define\tPCIR_BIOS\t0x30\n#define\tPCIM_BIOS_ENABLE\t0x01\n#define\tPCIM_BIOS_ADDR_MASK\t0xfffff800\n#define\tPCIR_CAP_PTR\t0x34\n#define\tPCIR_INTLINE\t0x3c\n#define\tPCIR_INTPIN\t0x3d\n#define\tPCIR_MINGNT\t0x3e\n#define\tPCIR_MAXLAT\t0x3f\n\n/* config registers for header type 1 (PCI-to-PCI bridge) devices */\n\n#define\tPCIR_MAX_BAR_1\t1\n#define\tPCIR_SECSTAT_1\t0x1e\n\n#define\tPCIR_PRIBUS_1\t0x18\n#define\tPCIR_SECBUS_1\t0x19\n#define\tPCIR_SUBBUS_1\t0x1a\n#define\tPCIR_SECLAT_1\t0x1b\n\n#define\tPCIR_IOBASEL_1\t0x1c\n#define\tPCIR_IOLIMITL_1\t0x1d\n#define\tPCIR_IOBASEH_1\t0x30\n#define\tPCIR_IOLIMITH_1\t0x32\n#define\tPCIM_BRIO_16\t\t0x0\n#define\tPCIM_BRIO_32\t\t0x1\n#define\tPCIM_BRIO_MASK\t\t0xf\n\n#define\tPCIR_MEMBASE_1\t0x20\n#define\tPCIR_MEMLIMIT_1\t0x22\n\n#define\tPCIR_PMBASEL_1\t0x24\n#define\tPCIR_PMLIMITL_1\t0x26\n#define\tPCIR_PMBASEH_1\t0x28\n#define\tPCIR_PMLIMITH_1\t0x2c\n#define\tPCIM_BRPM_32\t\t0x0\n#define\tPCIM_BRPM_64\t\t0x1\n#define\tPCIM_BRPM_MASK\t\t0xf\n\n#define\tPCIR_BIOS_1\t0x38\n#define\tPCIR_BRIDGECTL_1 0x3e\n\n/* config registers for header type 2 (CardBus) devices */\n\n#define\tPCIR_MAX_BAR_2\t0\n#define\tPCIR_CAP_PTR_2\t0x14\n#define\tPCIR_SECSTAT_2\t0x16\n\n#define\tPCIR_PRIBUS_2\t0x18\n#define\tPCIR_SECBUS_2\t0x19\n#define\tPCIR_SUBBUS_2\t0x1a\n#define\tPCIR_SECLAT_2\t0x1b\n\n#define\tPCIR_MEMBASE0_2\t0x1c\n#define\tPCIR_MEMLIMIT0_2 0x20\n#define\tPCIR_MEMBASE1_2\t0x24\n#define\tPCIR_MEMLIMIT1_2 0x28\n#define\tPCIR_IOBASE0_2\t0x2c\n#define\tPCIR_IOLIMIT0_2\t0x30\n#define\tPCIR_IOBASE1_2\t0x34\n#define\tPCIR_IOLIMIT1_2\t0x38\n\n#define\tPCIR_BRIDGECTL_2 0x3e\n\n#define\tPCIR_SUBVEND_2\t0x40\n#define\tPCIR_SUBDEV_2\t0x42\n\n#define\tPCIR_PCCARDIF_2\t0x44\n\n/* PCI device class, subclass and programming interface definitions */\n\n#define\tPCIC_OLD\t0x00\n#define\tPCIS_OLD_NONVGA\t\t0x00\n#define\tPCIS_OLD_VGA\t\t0x01\n\n#define\tPCIC_STORAGE\t0x01\n#define\tPCIS_STORAGE_SCSI\t0x00\n#define\tPCIS_STORAGE_IDE\t0x01\n#define\tPCIP_STORAGE_IDE_MODEPRIM\t0x01\n#define\tPCIP_STORAGE_IDE_PROGINDPRIM\t0x02\n#define\tPCIP_STORAGE_IDE_MODESEC\t0x04\n#define\tPCIP_STORAGE_IDE_PROGINDSEC\t0x08\n#define\tPCIP_STORAGE_IDE_MASTERDEV\t0x80\n#define\tPCIS_STORAGE_FLOPPY\t0x02\n#define\tPCIS_STORAGE_IPI\t0x03\n#define\tPCIS_STORAGE_RAID\t0x04\n#define\tPCIS_STORAGE_ATA_ADMA\t0x05\n#define\tPCIS_STORAGE_SATA\t0x06\n#define\tPCIP_STORAGE_SATA_AHCI_1_0\t0x01\n#define\tPCIS_STORAGE_SAS\t0x07\n#define\tPCIS_STORAGE_NVM\t0x08\n#define\tPCIP_STORAGE_NVM_NVMHCI_1_0\t0x01\n#define\tPCIP_STORAGE_NVM_ENTERPRISE_NVMHCI_1_0\t0x02\n#define\tPCIS_STORAGE_OTHER\t0x80\n\n#define\tPCIC_NETWORK\t0x02\n#define\tPCIS_NETWORK_ETHERNET\t0x00\n#define\tPCIS_NETWORK_TOKENRING\t0x01\n#define\tPCIS_NETWORK_FDDI\t0x02\n#define\tPCIS_NETWORK_ATM\t0x03\n#define\tPCIS_NETWORK_ISDN\t0x04\n#define\tPCIS_NETWORK_WORLDFIP\t0x05\n#define\tPCIS_NETWORK_PICMG\t0x06\n#define\tPCIS_NETWORK_OTHER\t0x80\n\n#define\tPCIC_DISPLAY\t0x03\n#define\tPCIS_DISPLAY_VGA\t0x00\n#define\tPCIS_DISPLAY_XGA\t0x01\n#define\tPCIS_DISPLAY_3D\t\t0x02\n#define\tPCIS_DISPLAY_OTHER\t0x80\n\n#define\tPCIC_MULTIMEDIA\t0x04\n#define\tPCIS_MULTIMEDIA_VIDEO\t0x00\n#define\tPCIS_MULTIMEDIA_AUDIO\t0x01\n#define\tPCIS_MULTIMEDIA_TELE\t0x02\n#define\tPCIS_MULTIMEDIA_HDA\t0x03\n#define\tPCIS_MULTIMEDIA_OTHER\t0x80\n\n#define\tPCIC_MEMORY\t0x05\n#define\tPCIS_MEMORY_RAM\t\t0x00\n#define\tPCIS_MEMORY_FLASH\t0x01\n#define\tPCIS_MEMORY_OTHER\t0x80\n\n#define\tPCIC_BRIDGE\t0x06\n#define\tPCIS_BRIDGE_HOST\t0x00\n#define\tPCIS_BRIDGE_ISA\t\t0x01\n#define\tPCIS_BRIDGE_EISA\t0x02\n#define\tPCIS_BRIDGE_MCA\t\t0x03\n#define\tPCIS_BRIDGE_PCI\t\t0x04\n#define\tPCIP_BRIDGE_PCI_SUBTRACTIVE\t0x01\n#define\tPCIS_BRIDGE_PCMCIA\t0x05\n#define\tPCIS_BRIDGE_NUBUS\t0x06\n#define\tPCIS_BRIDGE_CARDBUS\t0x07\n#define\tPCIS_BRIDGE_RACEWAY\t0x08\n#define\tPCIS_BRIDGE_PCI_TRANSPARENT 0x09\n#define\tPCIS_BRIDGE_INFINIBAND\t0x0a\n#define\tPCIS_BRIDGE_OTHER\t0x80\n\n#define\tPCIC_SIMPLECOMM\t0x07\n#define\tPCIS_SIMPLECOMM_UART\t0x00\n#define\tPCIP_SIMPLECOMM_UART_8250\t0x00\n#define\tPCIP_SIMPLECOMM_UART_16450A\t0x01\n#define\tPCIP_SIMPLECOMM_UART_16550A\t0x02\n#define\tPCIP_SIMPLECOMM_UART_16650A\t0x03\n#define\tPCIP_SIMPLECOMM_UART_16750A\t0x04\n#define\tPCIP_SIMPLECOMM_UART_16850A\t0x05\n#define\tPCIP_SIMPLECOMM_UART_16950A\t0x06\n#define\tPCIS_SIMPLECOMM_PAR\t0x01\n#define\tPCIS_SIMPLECOMM_MULSER\t0x02\n#define\tPCIS_SIMPLECOMM_MODEM\t0x03\n#define\tPCIS_SIMPLECOMM_GPIB\t0x04\n#define\tPCIS_SIMPLECOMM_SMART_CARD 0x05\n#define\tPCIS_SIMPLECOMM_OTHER\t0x80\n\n#define\tPCIC_BASEPERIPH\t0x08\n#define\tPCIS_BASEPERIPH_PIC\t0x00\n#define\tPCIP_BASEPERIPH_PIC_8259A\t0x00\n#define\tPCIP_BASEPERIPH_PIC_ISA\t\t0x01\n#define\tPCIP_BASEPERIPH_PIC_EISA\t0x02\n#define\tPCIP_BASEPERIPH_PIC_IO_APIC\t0x10\n#define\tPCIP_BASEPERIPH_PIC_IOX_APIC\t0x20\n#define\tPCIS_BASEPERIPH_DMA\t0x01\n#define\tPCIS_BASEPERIPH_TIMER\t0x02\n#define\tPCIS_BASEPERIPH_RTC\t0x03\n#define\tPCIS_BASEPERIPH_PCIHOT\t0x04\n#define\tPCIS_BASEPERIPH_SDHC\t0x05\n#define\tPCIS_BASEPERIPH_IOMMU\t0x06\n#define\tPCIS_BASEPERIPH_OTHER\t0x80\n\n#define\tPCIC_INPUTDEV\t0x09\n#define\tPCIS_INPUTDEV_KEYBOARD\t0x00\n#define\tPCIS_INPUTDEV_DIGITIZER\t0x01\n#define\tPCIS_INPUTDEV_MOUSE\t0x02\n#define\tPCIS_INPUTDEV_SCANNER\t0x03\n#define\tPCIS_INPUTDEV_GAMEPORT\t0x04\n#define\tPCIS_INPUTDEV_OTHER\t0x80\n\n#define\tPCIC_DOCKING\t0x0a\n#define\tPCIS_DOCKING_GENERIC\t0x00\n#define\tPCIS_DOCKING_OTHER\t0x80\n\n#define\tPCIC_PROCESSOR\t0x0b\n#define\tPCIS_PROCESSOR_386\t0x00\n#define\tPCIS_PROCESSOR_486\t0x01\n#define\tPCIS_PROCESSOR_PENTIUM\t0x02\n#define\tPCIS_PROCESSOR_ALPHA\t0x10\n#define\tPCIS_PROCESSOR_POWERPC\t0x20\n#define\tPCIS_PROCESSOR_MIPS\t0x30\n#define\tPCIS_PROCESSOR_COPROC\t0x40\n\n#define\tPCIC_SERIALBUS\t0x0c\n#define\tPCIS_SERIALBUS_FW\t0x00\n#define\tPCIS_SERIALBUS_ACCESS\t0x01\n#define\tPCIS_SERIALBUS_SSA\t0x02\n#define\tPCIS_SERIALBUS_USB\t0x03\n#define\tPCIP_SERIALBUS_USB_UHCI\t\t0x00\n#define\tPCIP_SERIALBUS_USB_OHCI\t\t0x10\n#define\tPCIP_SERIALBUS_USB_EHCI\t\t0x20\n#define\tPCIP_SERIALBUS_USB_XHCI\t\t0x30\n#define\tPCIP_SERIALBUS_USB_DEVICE\t0xfe\n#define\tPCIS_SERIALBUS_FC\t0x04\n#define\tPCIS_SERIALBUS_SMBUS\t0x05\n#define\tPCIS_SERIALBUS_INFINIBAND 0x06\n#define\tPCIS_SERIALBUS_IPMI\t0x07\n#define\tPCIP_SERIALBUS_IPMI_SMIC\t0x00\n#define\tPCIP_SERIALBUS_IPMI_KCS\t\t0x01\n#define\tPCIP_SERIALBUS_IPMI_BT\t\t0x02\n#define\tPCIS_SERIALBUS_SERCOS\t0x08\n#define\tPCIS_SERIALBUS_CANBUS\t0x09\n\n#define\tPCIC_WIRELESS\t0x0d\n#define\tPCIS_WIRELESS_IRDA\t0x00\n#define\tPCIS_WIRELESS_IR\t0x01\n#define\tPCIS_WIRELESS_RF\t0x10\n#define\tPCIS_WIRELESS_BLUETOOTH\t0x11\n#define\tPCIS_WIRELESS_BROADBAND\t0x12\n#define\tPCIS_WIRELESS_80211A\t0x20\n#define\tPCIS_WIRELESS_80211B\t0x21\n#define\tPCIS_WIRELESS_OTHER\t0x80\n\n#define\tPCIC_INTELLIIO\t0x0e\n#define\tPCIS_INTELLIIO_I2O\t0x00\n\n#define\tPCIC_SATCOM\t0x0f\n#define\tPCIS_SATCOM_TV\t\t0x01\n#define\tPCIS_SATCOM_AUDIO\t0x02\n#define\tPCIS_SATCOM_VOICE\t0x03\n#define\tPCIS_SATCOM_DATA\t0x04\n\n#define\tPCIC_CRYPTO\t0x10\n#define\tPCIS_CRYPTO_NETCOMP\t0x00\n#define\tPCIS_CRYPTO_ENTERTAIN\t0x10\n#define\tPCIS_CRYPTO_OTHER\t0x80\n\n#define\tPCIC_DASP\t0x11\n#define\tPCIS_DASP_DPIO\t\t0x00\n#define\tPCIS_DASP_PERFCNTRS\t0x01\n#define\tPCIS_DASP_COMM_SYNC\t0x10\n#define\tPCIS_DASP_MGMT_CARD\t0x20\n#define\tPCIS_DASP_OTHER\t\t0x80\n\n#define\tPCIC_OTHER\t0xff\n\n/* Bridge Control Values. */\n#define\tPCIB_BCR_PERR_ENABLE\t\t0x0001\n#define\tPCIB_BCR_SERR_ENABLE\t\t0x0002\n#define\tPCIB_BCR_ISA_ENABLE\t\t0x0004\n#define\tPCIB_BCR_VGA_ENABLE\t\t0x0008\n#define\tPCIB_BCR_MASTER_ABORT_MODE\t0x0020\n#define\tPCIB_BCR_SECBUS_RESET\t\t0x0040\n#define\tPCIB_BCR_SECBUS_BACKTOBACK\t0x0080\n#define\tPCIB_BCR_PRI_DISCARD_TIMEOUT\t0x0100\n#define\tPCIB_BCR_SEC_DISCARD_TIMEOUT\t0x0200\n#define\tPCIB_BCR_DISCARD_TIMER_STATUS\t0x0400\n#define\tPCIB_BCR_DISCARD_TIMER_SERREN\t0x0800\n\n/* PCI power manangement */\n#define\tPCIR_POWER_CAP\t\t0x2\n#define\tPCIM_PCAP_SPEC\t\t\t0x0007\n#define\tPCIM_PCAP_PMEREQCLK\t\t0x0008\n#define\tPCIM_PCAP_DEVSPECINIT\t\t0x0020\n#define\tPCIM_PCAP_AUXPWR_0\t\t0x0000\n#define\tPCIM_PCAP_AUXPWR_55\t\t0x0040\n#define\tPCIM_PCAP_AUXPWR_100\t\t0x0080\n#define\tPCIM_PCAP_AUXPWR_160\t\t0x00c0\n#define\tPCIM_PCAP_AUXPWR_220\t\t0x0100\n#define\tPCIM_PCAP_AUXPWR_270\t\t0x0140\n#define\tPCIM_PCAP_AUXPWR_320\t\t0x0180\n#define\tPCIM_PCAP_AUXPWR_375\t\t0x01c0\n#define\tPCIM_PCAP_AUXPWRMASK\t\t0x01c0\n#define\tPCIM_PCAP_D1SUPP\t\t0x0200\n#define\tPCIM_PCAP_D2SUPP\t\t0x0400\n#define\tPCIM_PCAP_D0PME\t\t\t0x0800\n#define\tPCIM_PCAP_D1PME\t\t\t0x1000\n#define\tPCIM_PCAP_D2PME\t\t\t0x2000\n#define\tPCIM_PCAP_D3PME_HOT\t\t0x4000\n#define\tPCIM_PCAP_D3PME_COLD\t\t0x8000\n\n#define\tPCIR_POWER_STATUS\t0x4\n#define\tPCIM_PSTAT_D0\t\t\t0x0000\n#define\tPCIM_PSTAT_D1\t\t\t0x0001\n#define\tPCIM_PSTAT_D2\t\t\t0x0002\n#define\tPCIM_PSTAT_D3\t\t\t0x0003\n#define\tPCIM_PSTAT_DMASK\t\t0x0003\n#define\tPCIM_PSTAT_NOSOFTRESET\t\t0x0008\n#define\tPCIM_PSTAT_PMEENABLE\t\t0x0100\n#define\tPCIM_PSTAT_D0POWER\t\t0x0000\n#define\tPCIM_PSTAT_D1POWER\t\t0x0200\n#define\tPCIM_PSTAT_D2POWER\t\t0x0400\n#define\tPCIM_PSTAT_D3POWER\t\t0x0600\n#define\tPCIM_PSTAT_D0HEAT\t\t0x0800\n#define\tPCIM_PSTAT_D1HEAT\t\t0x0a00\n#define\tPCIM_PSTAT_D2HEAT\t\t0x0c00\n#define\tPCIM_PSTAT_D3HEAT\t\t0x0e00\n#define\tPCIM_PSTAT_DATASELMASK\t\t0x1e00\n#define\tPCIM_PSTAT_DATAUNKN\t\t0x0000\n#define\tPCIM_PSTAT_DATADIV10\t\t0x2000\n#define\tPCIM_PSTAT_DATADIV100\t\t0x4000\n#define\tPCIM_PSTAT_DATADIV1000\t\t0x6000\n#define\tPCIM_PSTAT_DATADIVMASK\t\t0x6000\n#define\tPCIM_PSTAT_PME\t\t\t0x8000\n\n#define\tPCIR_POWER_BSE\t\t0x6\n#define\tPCIM_PMCSR_BSE_D3B3\t\t0x00\n#define\tPCIM_PMCSR_BSE_D3B2\t\t0x40\n#define\tPCIM_PMCSR_BSE_BPCCE\t\t0x80\n\n#define\tPCIR_POWER_DATA\t\t0x7\n\n/* VPD capability registers */\n#define\tPCIR_VPD_ADDR\t\t0x2\n#define\tPCIR_VPD_DATA\t\t0x4\n\n/* PCI Message Signalled Interrupts (MSI) */\n#define\tPCIR_MSI_CTRL\t\t0x2\n#define\tPCIM_MSICTRL_VECTOR\t\t0x0100\n#define\tPCIM_MSICTRL_64BIT\t\t0x0080\n#define\tPCIM_MSICTRL_MME_MASK\t\t0x0070\n#define\tPCIM_MSICTRL_MME_1\t\t0x0000\n#define\tPCIM_MSICTRL_MME_2\t\t0x0010\n#define\tPCIM_MSICTRL_MME_4\t\t0x0020\n#define\tPCIM_MSICTRL_MME_8\t\t0x0030\n#define\tPCIM_MSICTRL_MME_16\t\t0x0040\n#define\tPCIM_MSICTRL_MME_32\t\t0x0050\n#define\tPCIM_MSICTRL_MMC_MASK\t\t0x000E\n#define\tPCIM_MSICTRL_MMC_1\t\t0x0000\n#define\tPCIM_MSICTRL_MMC_2\t\t0x0002\n#define\tPCIM_MSICTRL_MMC_4\t\t0x0004\n#define\tPCIM_MSICTRL_MMC_8\t\t0x0006\n#define\tPCIM_MSICTRL_MMC_16\t\t0x0008\n#define\tPCIM_MSICTRL_MMC_32\t\t0x000A\n#define\tPCIM_MSICTRL_MSI_ENABLE\t\t0x0001\n#define\tPCIR_MSI_ADDR\t\t0x4\n#define\tPCIR_MSI_ADDR_HIGH\t0x8\n#define\tPCIR_MSI_DATA\t\t0x8\n#define\tPCIR_MSI_DATA_64BIT\t0xc\n#define\tPCIR_MSI_MASK\t\t0x10\n#define\tPCIR_MSI_PENDING\t0x14\n\n/* PCI-X definitions */\n\n/* For header type 0 devices */\n#define\tPCIXR_COMMAND\t\t0x2\n#define\tPCIXM_COMMAND_DPERR_E\t\t0x0001\t/* Data Parity Error Recovery */\n#define\tPCIXM_COMMAND_ERO\t\t0x0002\t/* Enable Relaxed Ordering */\n#define\tPCIXM_COMMAND_MAX_READ\t\t0x000c\t/* Maximum Burst Read Count */\n#define\tPCIXM_COMMAND_MAX_READ_512\t0x0000\n#define\tPCIXM_COMMAND_MAX_READ_1024\t0x0004\n#define\tPCIXM_COMMAND_MAX_READ_2048\t0x0008\n#define\tPCIXM_COMMAND_MAX_READ_4096\t0x000c\n#define\tPCIXM_COMMAND_MAX_SPLITS \t0x0070\t/* Maximum Split Transactions */\n#define\tPCIXM_COMMAND_MAX_SPLITS_1\t0x0000\n#define\tPCIXM_COMMAND_MAX_SPLITS_2\t0x0010\n#define\tPCIXM_COMMAND_MAX_SPLITS_3\t0x0020\n#define\tPCIXM_COMMAND_MAX_SPLITS_4\t0x0030\n#define\tPCIXM_COMMAND_MAX_SPLITS_8\t0x0040\n#define\tPCIXM_COMMAND_MAX_SPLITS_12\t0x0050\n#define\tPCIXM_COMMAND_MAX_SPLITS_16\t0x0060\n#define\tPCIXM_COMMAND_MAX_SPLITS_32\t0x0070\n#define\tPCIXM_COMMAND_VERSION\t\t0x3000\n#define\tPCIXR_STATUS\t\t0x4\n#define\tPCIXM_STATUS_DEVFN\t\t0x000000FF\n#define\tPCIXM_STATUS_BUS\t\t0x0000FF00\n#define\tPCIXM_STATUS_64BIT\t\t0x00010000\n#define\tPCIXM_STATUS_133CAP\t\t0x00020000\n#define\tPCIXM_STATUS_SC_DISCARDED\t0x00040000\n#define\tPCIXM_STATUS_UNEXP_SC\t\t0x00080000\n#define\tPCIXM_STATUS_COMPLEX_DEV\t0x00100000\n#define\tPCIXM_STATUS_MAX_READ\t\t0x00600000\n#define\tPCIXM_STATUS_MAX_READ_512\t0x00000000\n#define\tPCIXM_STATUS_MAX_READ_1024\t0x00200000\n#define\tPCIXM_STATUS_MAX_READ_2048\t0x00400000\n#define\tPCIXM_STATUS_MAX_READ_4096\t0x00600000\n#define\tPCIXM_STATUS_MAX_SPLITS\t\t0x03800000\n#define\tPCIXM_STATUS_MAX_SPLITS_1\t0x00000000\n#define\tPCIXM_STATUS_MAX_SPLITS_2\t0x00800000\n#define\tPCIXM_STATUS_MAX_SPLITS_3\t0x01000000\n#define\tPCIXM_STATUS_MAX_SPLITS_4\t0x01800000\n#define\tPCIXM_STATUS_MAX_SPLITS_8\t0x02000000\n#define\tPCIXM_STATUS_MAX_SPLITS_12\t0x02800000\n#define\tPCIXM_STATUS_MAX_SPLITS_16\t0x03000000\n#define\tPCIXM_STATUS_MAX_SPLITS_32\t0x03800000\n#define\tPCIXM_STATUS_MAX_CUM_READ\t0x1C000000\n#define\tPCIXM_STATUS_RCVD_SC_ERR\t0x20000000\n#define\tPCIXM_STATUS_266CAP\t\t0x40000000\n#define\tPCIXM_STATUS_533CAP\t\t0x80000000\n\n/* For header type 1 devices (PCI-X bridges) */\n#define\tPCIXR_SEC_STATUS\t0x2\n#define\tPCIXM_SEC_STATUS_64BIT\t\t0x0001\n#define\tPCIXM_SEC_STATUS_133CAP\t\t0x0002\n#define\tPCIXM_SEC_STATUS_SC_DISC\t0x0004\n#define\tPCIXM_SEC_STATUS_UNEXP_SC\t0x0008\n#define\tPCIXM_SEC_STATUS_SC_OVERRUN\t0x0010\n#define\tPCIXM_SEC_STATUS_SR_DELAYED\t0x0020\n#define\tPCIXM_SEC_STATUS_BUS_MODE\t0x03c0\n#define\tPCIXM_SEC_STATUS_VERSION\t0x3000\n#define\tPCIXM_SEC_STATUS_266CAP\t\t0x4000\n#define\tPCIXM_SEC_STATUS_533CAP\t\t0x8000\n#define\tPCIXR_BRIDGE_STATUS\t0x4\n#define\tPCIXM_BRIDGE_STATUS_DEVFN\t0x000000FF\n#define\tPCIXM_BRIDGE_STATUS_BUS\t\t0x0000FF00\n#define\tPCIXM_BRIDGE_STATUS_64BIT\t0x00010000\n#define\tPCIXM_BRIDGE_STATUS_133CAP\t0x00020000\n#define\tPCIXM_BRIDGE_STATUS_SC_DISCARDED 0x00040000\n#define\tPCIXM_BRIDGE_STATUS_UNEXP_SC\t0x00080000\n#define\tPCIXM_BRIDGE_STATUS_SC_OVERRUN\t0x00100000\n#define\tPCIXM_BRIDGE_STATUS_SR_DELAYED\t0x00200000\n#define\tPCIXM_BRIDGE_STATUS_DEVID_MSGCAP 0x20000000\n#define\tPCIXM_BRIDGE_STATUS_266CAP\t0x40000000\n#define\tPCIXM_BRIDGE_STATUS_533CAP\t0x80000000\n\n/* HT (HyperTransport) Capability definitions */\n#define\tPCIR_HT_COMMAND\t\t0x2\n#define\tPCIM_HTCMD_CAP_MASK\t\t0xf800\t/* Capability type. */\n#define\tPCIM_HTCAP_SLAVE\t\t0x0000\t/* 000xx */\n#define\tPCIM_HTCAP_HOST\t\t\t0x2000\t/* 001xx */\n#define\tPCIM_HTCAP_SWITCH\t\t0x4000\t/* 01000 */\n#define\tPCIM_HTCAP_INTERRUPT\t\t0x8000\t/* 10000 */\n#define\tPCIM_HTCAP_REVISION_ID\t\t0x8800\t/* 10001 */\n#define\tPCIM_HTCAP_UNITID_CLUMPING\t0x9000\t/* 10010 */\n#define\tPCIM_HTCAP_EXT_CONFIG_SPACE\t0x9800\t/* 10011 */\n#define\tPCIM_HTCAP_ADDRESS_MAPPING\t0xa000\t/* 10100 */\n#define\tPCIM_HTCAP_MSI_MAPPING\t\t0xa800\t/* 10101 */\n#define\tPCIM_HTCAP_DIRECT_ROUTE\t\t0xb000\t/* 10110 */\n#define\tPCIM_HTCAP_VCSET\t\t0xb800\t/* 10111 */\n#define\tPCIM_HTCAP_RETRY_MODE\t\t0xc000\t/* 11000 */\n#define\tPCIM_HTCAP_X86_ENCODING\t\t0xc800\t/* 11001 */\n#define\tPCIM_HTCAP_GEN3\t\t\t0xd000\t/* 11010 */\n#define\tPCIM_HTCAP_FLE\t\t\t0xd800\t/* 11011 */\n#define\tPCIM_HTCAP_PM\t\t\t0xe000\t/* 11100 */\n#define\tPCIM_HTCAP_HIGH_NODE_COUNT\t0xe800\t/* 11101 */\n\n/* HT MSI Mapping Capability definitions. */\n#define\tPCIM_HTCMD_MSI_ENABLE\t\t0x0001\n#define\tPCIM_HTCMD_MSI_FIXED\t\t0x0002\n#define\tPCIR_HTMSI_ADDRESS_LO\t0x4\n#define\tPCIR_HTMSI_ADDRESS_HI\t0x8\n\n/* PCI Vendor capability definitions */\n#define\tPCIR_VENDOR_LENGTH\t0x2\n#define\tPCIR_VENDOR_DATA\t0x3\n\n/* PCI EHCI Debug Port definitions */\n#define\tPCIR_DEBUG_PORT\t\t0x2\n#define\tPCIM_DEBUG_PORT_OFFSET\t\t0x1FFF\n#define\tPCIM_DEBUG_PORT_BAR\t\t0xe000\n\n/* PCI-PCI Bridge Subvendor definitions */\n#define\tPCIR_SUBVENDCAP_ID\t0x4\n\n/* PCI Express definitions */\n#define\tPCIER_FLAGS\t\t0x2\n#define\tPCIEM_FLAGS_VERSION\t\t0x000F\n#define\tPCIEM_FLAGS_TYPE\t\t0x00F0\n#define\tPCIEM_TYPE_ENDPOINT\t\t0x0000\n#define\tPCIEM_TYPE_LEGACY_ENDPOINT\t0x0010\n#define\tPCIEM_TYPE_ROOT_PORT\t\t0x0040\n#define\tPCIEM_TYPE_UPSTREAM_PORT\t0x0050\n#define\tPCIEM_TYPE_DOWNSTREAM_PORT\t0x0060\n#define\tPCIEM_TYPE_PCI_BRIDGE\t\t0x0070\n#define\tPCIEM_TYPE_PCIE_BRIDGE\t\t0x0080\n#define\tPCIEM_TYPE_ROOT_INT_EP\t\t0x0090\n#define\tPCIEM_TYPE_ROOT_EC\t\t0x00a0\n#define\tPCIEM_FLAGS_SLOT\t\t0x0100\n#define\tPCIEM_FLAGS_IRQ\t\t\t0x3e00\n#define\tPCIER_DEVICE_CAP\t0x4\n#define\tPCIEM_CAP_MAX_PAYLOAD\t\t0x00000007\n#define\tPCIEM_CAP_PHANTHOM_FUNCS\t0x00000018\n#define\tPCIEM_CAP_EXT_TAG_FIELD\t\t0x00000020\n#define\tPCIEM_CAP_L0S_LATENCY\t\t0x000001c0\n#define\tPCIEM_CAP_L1_LATENCY\t\t0x00000e00\n#define\tPCIEM_CAP_ROLE_ERR_RPT\t\t0x00008000\n#define\tPCIEM_CAP_SLOT_PWR_LIM_VAL\t0x03fc0000\n#define\tPCIEM_CAP_SLOT_PWR_LIM_SCALE\t0x0c000000\n#define\tPCIEM_CAP_FLR\t\t\t0x10000000\n#define\tPCIER_DEVICE_CTL\t0x8\n#define\tPCIEM_CTL_COR_ENABLE\t\t0x0001\n#define\tPCIEM_CTL_NFER_ENABLE\t\t0x0002\n#define\tPCIEM_CTL_FER_ENABLE\t\t0x0004\n#define\tPCIEM_CTL_URR_ENABLE\t\t0x0008\n#define\tPCIEM_CTL_RELAXED_ORD_ENABLE\t0x0010\n#define\tPCIEM_CTL_MAX_PAYLOAD\t\t0x00e0\n#define\tPCIEM_CTL_EXT_TAG_FIELD\t\t0x0100\n#define\tPCIEM_CTL_PHANTHOM_FUNCS\t0x0200\n#define\tPCIEM_CTL_AUX_POWER_PM\t\t0x0400\n#define\tPCIEM_CTL_NOSNOOP_ENABLE\t0x0800\n#define\tPCIEM_CTL_MAX_READ_REQUEST\t0x7000\n#define\tPCIEM_CTL_BRDG_CFG_RETRY\t0x8000\t/* PCI-E - PCI/PCI-X bridges */\n#define\tPCIEM_CTL_INITIATE_FLR\t\t0x8000\t/* FLR capable endpoints */\n#define\tPCIER_DEVICE_STA\t0xa\n#define\tPCIEM_STA_CORRECTABLE_ERROR\t0x0001\n#define\tPCIEM_STA_NON_FATAL_ERROR\t0x0002\n#define\tPCIEM_STA_FATAL_ERROR\t\t0x0004\n#define\tPCIEM_STA_UNSUPPORTED_REQ\t0x0008\n#define\tPCIEM_STA_AUX_POWER\t\t0x0010\n#define\tPCIEM_STA_TRANSACTION_PND\t0x0020\n#define\tPCIER_LINK_CAP\t\t0xc\n#define\tPCIEM_LINK_CAP_MAX_SPEED\t0x0000000f\n#define\tPCIEM_LINK_CAP_MAX_WIDTH\t0x000003f0\n#define\tPCIEM_LINK_CAP_ASPM\t\t0x00000c00\n#define\tPCIEM_LINK_CAP_L0S_EXIT\t\t0x00007000\n#define\tPCIEM_LINK_CAP_L1_EXIT\t\t0x00038000\n#define\tPCIEM_LINK_CAP_CLOCK_PM\t\t0x00040000\n#define\tPCIEM_LINK_CAP_SURPRISE_DOWN\t0x00080000\n#define\tPCIEM_LINK_CAP_DL_ACTIVE\t0x00100000\n#define\tPCIEM_LINK_CAP_LINK_BW_NOTIFY\t0x00200000\n#define\tPCIEM_LINK_CAP_ASPM_COMPLIANCE\t0x00400000\n#define\tPCIEM_LINK_CAP_PORT\t\t0xff000000\n#define\tPCIER_LINK_CTL\t\t0x10\n#define\tPCIEM_LINK_CTL_ASPMC_DIS\t0x0000\n#define\tPCIEM_LINK_CTL_ASPMC_L0S\t0x0001\n#define\tPCIEM_LINK_CTL_ASPMC_L1\t\t0x0002\n#define\tPCIEM_LINK_CTL_ASPMC\t\t0x0003\n#define\tPCIEM_LINK_CTL_RCB\t\t0x0008\n#define\tPCIEM_LINK_CTL_LINK_DIS\t\t0x0010\n#define\tPCIEM_LINK_CTL_RETRAIN_LINK\t0x0020\n#define\tPCIEM_LINK_CTL_COMMON_CLOCK\t0x0040\n#define\tPCIEM_LINK_CTL_EXTENDED_SYNC\t0x0080\n#define\tPCIEM_LINK_CTL_ECPM\t\t0x0100\n#define\tPCIEM_LINK_CTL_HAWD\t\t0x0200\n#define\tPCIEM_LINK_CTL_LBMIE\t\t0x0400\n#define\tPCIEM_LINK_CTL_LABIE\t\t0x0800\n#define\tPCIER_LINK_STA\t\t0x12\n#define\tPCIEM_LINK_STA_SPEED\t\t0x000f\n#define\tPCIEM_LINK_STA_WIDTH\t\t0x03f0\n#define\tPCIEM_LINK_STA_TRAINING_ERROR\t0x0400\n#define\tPCIEM_LINK_STA_TRAINING\t\t0x0800\n#define\tPCIEM_LINK_STA_SLOT_CLOCK\t0x1000\n#define\tPCIEM_LINK_STA_DL_ACTIVE\t0x2000\n#define\tPCIEM_LINK_STA_LINK_BW_MGMT\t0x4000\n#define\tPCIEM_LINK_STA_LINK_AUTO_BW\t0x8000\n#define\tPCIER_SLOT_CAP\t\t0x14\n#define\tPCIEM_SLOT_CAP_APB\t\t0x00000001\n#define\tPCIEM_SLOT_CAP_PCP\t\t0x00000002\n#define\tPCIEM_SLOT_CAP_MRLSP\t\t0x00000004\n#define\tPCIEM_SLOT_CAP_AIP\t\t0x00000008\n#define\tPCIEM_SLOT_CAP_PIP\t\t0x00000010\n#define\tPCIEM_SLOT_CAP_HPS\t\t0x00000020\n#define\tPCIEM_SLOT_CAP_HPC\t\t0x00000040\n#define\tPCIEM_SLOT_CAP_SPLV\t\t0x00007f80\n#define\tPCIEM_SLOT_CAP_SPLS\t\t0x00018000\n#define\tPCIEM_SLOT_CAP_EIP\t\t0x00020000\n#define\tPCIEM_SLOT_CAP_NCCS\t\t0x00040000\n#define\tPCIEM_SLOT_CAP_PSN\t\t0xfff80000\n#define\tPCIER_SLOT_CTL\t\t0x18\n#define\tPCIEM_SLOT_CTL_ABPE\t\t0x0001\n#define\tPCIEM_SLOT_CTL_PFDE\t\t0x0002\n#define\tPCIEM_SLOT_CTL_MRLSCE\t\t0x0004\n#define\tPCIEM_SLOT_CTL_PDCE\t\t0x0008\n#define\tPCIEM_SLOT_CTL_CCIE\t\t0x0010\n#define\tPCIEM_SLOT_CTL_HPIE\t\t0x0020\n#define\tPCIEM_SLOT_CTL_AIC\t\t0x00c0\n#define\tPCIEM_SLOT_CTL_PIC\t\t0x0300\n#define\tPCIEM_SLOT_CTL_PCC\t\t0x0400\n#define\tPCIEM_SLOT_CTL_EIC\t\t0x0800\n#define\tPCIEM_SLOT_CTL_DLLSCE\t\t0x1000\n#define\tPCIER_SLOT_STA\t\t0x1a\n#define\tPCIEM_SLOT_STA_ABP\t\t0x0001\n#define\tPCIEM_SLOT_STA_PFD\t\t0x0002\n#define\tPCIEM_SLOT_STA_MRLSC\t\t0x0004\n#define\tPCIEM_SLOT_STA_PDC\t\t0x0008\n#define\tPCIEM_SLOT_STA_CC\t\t0x0010\n#define\tPCIEM_SLOT_STA_MRLSS\t\t0x0020\n#define\tPCIEM_SLOT_STA_PDS\t\t0x0040\n#define\tPCIEM_SLOT_STA_EIS\t\t0x0080\n#define\tPCIEM_SLOT_STA_DLLSC\t\t0x0100\n#define\tPCIER_ROOT_CTL\t\t0x1c\n#define\tPCIEM_ROOT_CTL_SERR_CORR\t0x0001\n#define\tPCIEM_ROOT_CTL_SERR_NONFATAL\t0x0002\n#define\tPCIEM_ROOT_CTL_SERR_FATAL\t0x0004\n#define\tPCIEM_ROOT_CTL_PME\t\t0x0008\n#define\tPCIEM_ROOT_CTL_CRS_VIS\t\t0x0010\n#define\tPCIER_ROOT_CAP\t\t0x1e\n#define\tPCIEM_ROOT_CAP_CRS_VIS\t\t0x0001\n#define\tPCIER_ROOT_STA\t\t0x20\n#define\tPCIEM_ROOT_STA_PME_REQID_MASK\t0x0000ffff\n#define\tPCIEM_ROOT_STA_PME_STATUS\t0x00010000\n#define\tPCIEM_ROOT_STA_PME_PEND\t\t0x00020000\n#define\tPCIER_DEVICE_CAP2\t0x24\n#define\tPCIEM_CAP2_ARI\t\t0x20\n#define\tPCIER_DEVICE_CTL2\t0x28\n#define\tPCIEM_CTL2_COMP_TIMEOUT_VAL\t0x000f\n#define\tPCIEM_CTL2_COMP_TIMEOUT_DIS\t0x0010\n#define\tPCIEM_CTL2_ARI\t\t\t0x0020\n#define\tPCIEM_CTL2_ATOMIC_REQ_ENABLE\t0x0040\n#define\tPCIEM_CTL2_ATOMIC_EGR_BLOCK\t0x0080\n#define\tPCIEM_CTL2_ID_ORDERED_REQ_EN\t0x0100\n#define\tPCIEM_CTL2_ID_ORDERED_CMP_EN\t0x0200\n#define\tPCIEM_CTL2_LTR_ENABLE\t\t0x0400\n#define\tPCIEM_CTL2_OBFF\t\t\t0x6000\n#define\tPCIEM_OBFF_DISABLE\t\t0x0000\n#define\tPCIEM_OBFF_MSGA_ENABLE\t\t0x2000\n#define\tPCIEM_OBFF_MSGB_ENABLE\t\t0x4000\n#define\tPCIEM_OBFF_WAKE_ENABLE\t\t0x6000\n#define\tPCIEM_CTL2_END2END_TLP\t\t0x8000\n#define\tPCIER_DEVICE_STA2\t0x2a\n#define\tPCIER_LINK_CAP2\t\t0x2c\n#define\tPCIER_LINK_CTL2\t\t0x30\n#define\tPCIER_LINK_STA2\t\t0x32\n#define\tPCIER_SLOT_CAP2\t\t0x34\n#define\tPCIER_SLOT_CTL2\t\t0x38\n#define\tPCIER_SLOT_STA2\t\t0x3a\n\n/* MSI-X definitions */\n#define\tPCIR_MSIX_CTRL\t\t0x2\n#define\tPCIM_MSIXCTRL_MSIX_ENABLE\t0x8000\n#define\tPCIM_MSIXCTRL_FUNCTION_MASK\t0x4000\n#define\tPCIM_MSIXCTRL_TABLE_SIZE\t0x07FF\n#define\tPCIR_MSIX_TABLE\t\t0x4\n#define\tPCIR_MSIX_PBA\t\t0x8\n#define\tPCIM_MSIX_BIR_MASK\t\t0x7\n#define\tPCIM_MSIX_BIR_BAR_10\t\t0\n#define\tPCIM_MSIX_BIR_BAR_14\t\t1\n#define\tPCIM_MSIX_BIR_BAR_18\t\t2\n#define\tPCIM_MSIX_BIR_BAR_1C\t\t3\n#define\tPCIM_MSIX_BIR_BAR_20\t\t4\n#define\tPCIM_MSIX_BIR_BAR_24\t\t5\n#define\tPCIM_MSIX_VCTRL_MASK\t\t0x1\n\n/* PCI Advanced Features definitions */\n#define\tPCIR_PCIAF_CAP\t\t0x3\n#define\tPCIM_PCIAFCAP_TP\t0x01\n#define\tPCIM_PCIAFCAP_FLR\t0x02\n#define\tPCIR_PCIAF_CTRL\t\t0x4\n#define\tPCIR_PCIAFCTRL_FLR\t0x01\n#define\tPCIR_PCIAF_STATUS\t0x5\n#define\tPCIR_PCIAFSTATUS_TP\t0x01\n\n/* Advanced Error Reporting */\n#define\tPCIR_AER_UC_STATUS\t0x04\n#define\tPCIM_AER_UC_TRAINING_ERROR\t0x00000001\n#define\tPCIM_AER_UC_DL_PROTOCOL_ERROR\t0x00000010\n#define\tPCIM_AER_UC_SURPRISE_LINK_DOWN\t0x00000020\n#define\tPCIM_AER_UC_POISONED_TLP\t0x00001000\n#define\tPCIM_AER_UC_FC_PROTOCOL_ERROR\t0x00002000\n#define\tPCIM_AER_UC_COMPLETION_TIMEOUT\t0x00004000\n#define\tPCIM_AER_UC_COMPLETER_ABORT\t0x00008000\n#define\tPCIM_AER_UC_UNEXPECTED_COMPLETION 0x00010000\n#define\tPCIM_AER_UC_RECEIVER_OVERFLOW\t0x00020000\n#define\tPCIM_AER_UC_MALFORMED_TLP\t0x00040000\n#define\tPCIM_AER_UC_ECRC_ERROR\t\t0x00080000\n#define\tPCIM_AER_UC_UNSUPPORTED_REQUEST\t0x00100000\n#define\tPCIM_AER_UC_ACS_VIOLATION\t0x00200000\n#define\tPCIM_AER_UC_INTERNAL_ERROR\t0x00400000\n#define\tPCIM_AER_UC_MC_BLOCKED_TLP\t0x00800000\n#define\tPCIM_AER_UC_ATOMIC_EGRESS_BLK\t0x01000000\n#define\tPCIM_AER_UC_TLP_PREFIX_BLOCKED\t0x02000000\n#define\tPCIR_AER_UC_MASK\t0x08\t/* Shares bits with UC_STATUS */\n#define\tPCIR_AER_UC_SEVERITY\t0x0c\t/* Shares bits with UC_STATUS */\n#define\tPCIR_AER_COR_STATUS\t0x10\n#define\tPCIM_AER_COR_RECEIVER_ERROR\t0x00000001\n#define\tPCIM_AER_COR_BAD_TLP\t\t0x00000040\n#define\tPCIM_AER_COR_BAD_DLLP\t\t0x00000080\n#define\tPCIM_AER_COR_REPLAY_ROLLOVER\t0x00000100\n#define\tPCIM_AER_COR_REPLAY_TIMEOUT\t0x00001000\n#define\tPCIM_AER_COR_ADVISORY_NF_ERROR\t0x00002000\n#define\tPCIM_AER_COR_INTERNAL_ERROR\t0x00004000\n#define\tPCIM_AER_COR_HEADER_LOG_OVFLOW\t0x00008000\n#define\tPCIR_AER_COR_MASK\t0x14\t/* Shares bits with COR_STATUS */\n#define\tPCIR_AER_CAP_CONTROL\t0x18\n#define\tPCIM_AER_FIRST_ERROR_PTR\t0x0000001f\n#define\tPCIM_AER_ECRC_GEN_CAPABLE\t0x00000020\n#define\tPCIM_AER_ECRC_GEN_ENABLE\t0x00000040\n#define\tPCIM_AER_ECRC_CHECK_CAPABLE\t0x00000080\n#define\tPCIM_AER_ECRC_CHECK_ENABLE\t0x00000100\n#define\tPCIM_AER_MULT_HDR_CAPABLE\t0x00000200\n#define\tPCIM_AER_MULT_HDR_ENABLE\t0x00000400\n#define\tPCIM_AER_TLP_PREFIX_LOG_PRESENT\t0x00000800\n#define\tPCIR_AER_HEADER_LOG\t0x1c\n#define\tPCIR_AER_ROOTERR_CMD\t0x2c\t/* Only for root complex ports */\n#define\tPCIM_AER_ROOTERR_COR_ENABLE\t0x00000001\n#define\tPCIM_AER_ROOTERR_NF_ENABLE\t0x00000002\n#define\tPCIM_AER_ROOTERR_F_ENABLE\t0x00000004\n#define\tPCIR_AER_ROOTERR_STATUS\t0x30\t/* Only for root complex ports */\n#define\tPCIM_AER_ROOTERR_COR_ERR\t0x00000001\n#define\tPCIM_AER_ROOTERR_MULTI_COR_ERR\t0x00000002\n#define\tPCIM_AER_ROOTERR_UC_ERR\t\t0x00000004\n#define\tPCIM_AER_ROOTERR_MULTI_UC_ERR\t0x00000008\n#define\tPCIM_AER_ROOTERR_FIRST_UC_FATAL\t0x00000010\n#define\tPCIM_AER_ROOTERR_NF_ERR\t\t0x00000020\n#define\tPCIM_AER_ROOTERR_F_ERR\t\t0x00000040\n#define\tPCIM_AER_ROOTERR_INT_MESSAGE\t0xf8000000\n#define\tPCIR_AER_COR_SOURCE_ID\t0x34\t/* Only for root complex ports */\n#define\tPCIR_AER_ERR_SOURCE_ID\t0x36\t/* Only for root complex ports */\n#define\tPCIR_AER_TLP_PREFIX_LOG\t0x38\t/* Only for TLP prefix functions */\n\n/* Virtual Channel definitions */\n#define\tPCIR_VC_CAP1\t\t0x04\n#define\tPCIM_VC_CAP1_EXT_COUNT\t\t0x00000007\n#define\tPCIM_VC_CAP1_LOWPRI_EXT_COUNT\t0x00000070\n#define\tPCIR_VC_CAP2\t\t0x08\n#define\tPCIR_VC_CONTROL\t\t0x0C\n#define\tPCIR_VC_STATUS\t\t0x0E\n#define\tPCIR_VC_RESOURCE_CAP(n)\t(0x10 + (n) * 0x0C)\n#define\tPCIR_VC_RESOURCE_CTL(n)\t(0x14 + (n) * 0x0C)\n#define\tPCIR_VC_RESOURCE_STA(n)\t(0x18 + (n) * 0x0C)\n\n/* Serial Number definitions */\n#define\tPCIR_SERIAL_LOW\t\t0x04\n#define\tPCIR_SERIAL_HIGH\t0x08\n\n/* SR-IOV definitions */\n#define\tPCIR_SRIOV_CTL\t\t0x08\n#define\tPCIM_SRIOV_VF_EN\t0x01\n#define\tPCIM_SRIOV_VF_MSE\t0x08\t/* Memory space enable. */\n#define\tPCIM_SRIOV_ARI_EN\t0x10\n#define\tPCIR_SRIOV_TOTAL_VFS\t0x0E\n#define\tPCIR_SRIOV_NUM_VFS\t0x10\n#define\tPCIR_SRIOV_VF_OFF\t0x14\n#define\tPCIR_SRIOV_VF_STRIDE\t0x16\n#define\tPCIR_SRIOV_VF_DID\t0x1A\n#define\tPCIR_SRIOV_PAGE_CAP\t0x1C\n#define\tPCIR_SRIOV_PAGE_SIZE\t0x20\n\n#define\tPCI_SRIOV_BASE_PAGE_SHIFT\t12\n\n#define\tPCIR_SRIOV_BARS\t\t0x24\n#define\tPCIR_SRIOV_BAR(x)\t(PCIR_SRIOV_BARS + (x) * 4)\n"
  },
  {
    "path": "include/xhyve/support/psl.h",
    "content": "/*-\n * Copyright (c) 1990 The Regents of the University of California.\n * All rights reserved.\n *\n * This code is derived from software contributed to Berkeley by\n * William Jolitz.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tfrom: @(#)psl.h\t5.2 (Berkeley) 1/18/91\n * $FreeBSD$\n */\n\n#pragma once\n\n/*\n * 386 processor status longword.\n */\n#define\tPSL_C\t\t0x00000001\t/* carry bit */\n#define\tPSL_PF\t\t0x00000004\t/* parity bit */\n#define\tPSL_AF\t\t0x00000010\t/* bcd carry bit */\n#define\tPSL_Z\t\t0x00000040\t/* zero bit */\n#define\tPSL_N\t\t0x00000080\t/* negative bit */\n#define\tPSL_T\t\t0x00000100\t/* trace enable bit */\n#define\tPSL_I\t\t0x00000200\t/* interrupt enable bit */\n#define\tPSL_D\t\t0x00000400\t/* string instruction direction bit */\n#define\tPSL_V\t\t0x00000800\t/* overflow bit */\n#define\tPSL_IOPL\t0x00003000\t/* i/o privilege level */\n#define\tPSL_NT\t\t0x00004000\t/* nested task bit */\n#define\tPSL_RF\t\t0x00010000\t/* resume flag bit */\n#define\tPSL_VM\t\t0x00020000\t/* virtual 8086 mode bit */\n#define\tPSL_AC\t\t0x00040000\t/* alignment checking */\n#define\tPSL_VIF\t\t0x00080000\t/* virtual interrupt enable */\n#define\tPSL_VIP\t\t0x00100000\t/* virtual interrupt pending */\n#define\tPSL_ID\t\t0x00200000\t/* identification bit */\n\n/*\n * The i486 manual says that we are not supposed to change reserved flags,\n * but this is too much trouble since the reserved flags depend on the cpu\n * and setting them to their historical values works in practice.\n */\n#define\tPSL_RESERVED_DEFAULT\t0x00000002\n\n/*\n * Initial flags for kernel and user mode.  The kernel later inherits\n * PSL_I and some other flags from user mode.\n */\n#define\tPSL_KERNEL\tPSL_RESERVED_DEFAULT\n#define\tPSL_USER\t(PSL_RESERVED_DEFAULT | PSL_I)\n\n/*\n * Bits that can be changed in user mode on 486's.  We allow these bits\n * to be changed using ptrace(), sigreturn() and procfs.  Setting PS_NT\n * is undesirable but it may as well be allowed since users can inflict\n * it on the kernel directly.  Changes to PSL_AC are silently ignored on\n * 386's.\n *\n * Users are allowed to change the privileged flag PSL_RF.  The cpu sets PSL_RF\n * in tf_eflags for faults.  Debuggers should sometimes set it there too.\n * tf_eflags is kept in the signal context during signal handling and there is\n * no other place to remember it, so the PSL_RF bit may be corrupted by the\n * signal handler without us knowing.  Corruption of the PSL_RF bit at worst\n * causes one more or one less debugger trap, so allowing it is fairly\n * harmless.   \n */\n#define\tPSL_USERCHANGE (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_T \\\n\t\t\t| PSL_D | PSL_V | PSL_NT | PSL_RF | PSL_AC | PSL_ID)\n"
  },
  {
    "path": "include/xhyve/support/rtc.h",
    "content": "/*-\n * Copyright (c) 1990 The Regents of the University of California.\n * All rights reserved.\n *\n * This code is derived from software contributed to Berkeley by\n * William Jolitz.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tfrom: @(#)rtc.h\t7.1 (Berkeley) 5/12/91\n * $FreeBSD$\n */\n\n/*\n * MC146818 RTC Register locations\n */\n\n#pragma once\n\n#define RTC_SEC\t\t0x00\t/* seconds */\n#define RTC_SECALRM\t0x01\t/* seconds alarm */\n#define RTC_MIN\t\t0x02\t/* minutes */\n#define RTC_MINALRM\t0x03\t/* minutes alarm */\n#define RTC_HRS\t\t0x04\t/* hours */\n#define RTC_HRSALRM\t0x05\t/* hours alarm */\n#define RTC_WDAY\t0x06\t/* week day */\n#define RTC_DAY\t\t0x07\t/* day of month */\n#define RTC_MONTH\t0x08\t/* month of year */\n#define RTC_YEAR\t0x09\t/* month of year */\n\n#define RTC_STATUSA\t0x0a\t/* status register A */\n#define  RTCSA_TUP\t 0x80\t/* time update, don't look now */\n#define  RTCSA_RESET\t 0x70\t/* reset divider */\n#define  RTCSA_DIVIDER   0x20   /* divider correct for 32768 Hz */\n#define  RTCSA_8192      0x03\t/* 8192 Hz interrupt */\n#define  RTCSA_4096      0x04\n#define  RTCSA_2048      0x05\n#define  RTCSA_1024      0x06\t/* default for profiling */\n#define  RTCSA_PROF      RTCSA_1024\n#define  RTC_PROFRATE    1024\n#define  RTCSA_512       0x07\n#define  RTCSA_256       0x08\n#define  RTCSA_128       0x09\n#define  RTCSA_NOPROF\t RTCSA_128\n#define  RTC_NOPROFRATE  128\n#define  RTCSA_64        0x0a\n#define  RTCSA_32        0x0b\t/* 32 Hz interrupt */\n\n#define RTC_STATUSB\t0x0b\t/* status register B */\n#define\t RTCSB_DST\t 0x01\t/* USA Daylight Savings Time enable */\n#define\t RTCSB_24HR\t 0x02\t/* 0 = 12 hours, 1 = 24\thours */\n#define\t RTCSB_BCD\t 0x04\t/* 0 = BCD, 1 =\tBinary coded time */\n#define\t RTCSB_SQWE\t 0x08\t/* 1 = output sqare wave at SQW\tpin */\n#define\t RTCSB_UINTR\t 0x10\t/* 1 = enable update-ended interrupt */\n#define\t RTCSB_AINTR\t 0x20\t/* 1 = enable alarm interrupt */\n#define\t RTCSB_PINTR\t 0x40\t/* 1 = enable periodic clock interrupt */\n#define  RTCSB_HALT      0x80\t/* stop clock updates */\n\n#define RTC_INTR\t0x0c\t/* status register C (R) interrupt source */\n#define  RTCIR_UPDATE\t 0x10\t/* update intr */\n#define  RTCIR_ALARM\t 0x20\t/* alarm intr */\n#define  RTCIR_PERIOD\t 0x40\t/* periodic intr */\n#define  RTCIR_INT\t 0x80\t/* interrupt output signal */\n\n#define RTC_STATUSD\t0x0d\t/* status register D (R) Lost Power */\n#define  RTCSD_PWR\t 0x80\t/* clock power OK */\n\n#define RTC_DIAG\t0x0e\t/* status register E - bios diagnostic */\n#define RTCDG_BITS\t\"\\020\\010clock_battery\\007ROM_cksum\\006config_unit\\005memory_size\\004fixed_disk\\003invalid_time\"\n\n#define RTC_RESET\t0x0f\t/* status register F - reset code byte */\n#define\t RTCRS_RST\t 0x00\t\t/* normal reset */\n#define\t RTCRS_LOAD\t 0x04\t\t/* load system */\n\n#define RTC_FDISKETTE\t0x10\t/* diskette drive type in upper/lower nibble */\n#define\t RTCFDT_NONE\t 0\t\t/* none present */\n#define\t RTCFDT_360K\t 0x10\t\t/* 360K */\n#define\t RTCFDT_12M\t 0x20\t\t/* 1.2M */\n#define  RTCFDT_720K     0x30           /* 720K */\n#define\t RTCFDT_144M\t 0x40\t\t/* 1.44M */\n#define  RTCFDT_288M_1   0x50\t\t/* 2.88M, some BIOSes */\n#define\t RTCFDT_288M\t 0x60\t\t/* 2.88M */\n\n#define RTC_BASELO\t0x15\t/* low byte of basemem size */\n#define RTC_BASEHI\t0x16\t/* high byte of basemem size */\n#define RTC_EXTLO\t0x17\t/* low byte of extended mem size */\n#define RTC_EXTHI\t0x18\t/* low byte of extended mem size */\n\n#define\tRTC_CENTURY\t0x32\t/* current century */\n"
  },
  {
    "path": "include/xhyve/support/segments.h",
    "content": "/*-\n * Copyright (c) 1989, 1990 William F. Jolitz\n * Copyright (c) 1990 The Regents of the University of California.\n * All rights reserved.\n *\n * This code is derived from software contributed to Berkeley by\n * William Jolitz.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tfrom: @(#)segments.h\t7.1 (Berkeley) 5/9/91\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/misc.h>\n\n// /*\n//  * X86 Segmentation Data Structures and definitions\n//  */\n\n/* Selectors */\n#define SEL_RPL_MASK 3 /* requester priv level */\n#define ISPL(s) ((s) & 3) /* priority level of a selector */\n#define SEL_KPL 0 /* kernel priority level */\n#define SEL_UPL 3 /* user priority level */\n#define ISLDT(s) ((s) & SEL_LDT) /* is it local or global */\n#define SEL_LDT 4 /* local descriptor table */\n#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */\n#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */\n#define GSEL(s,r) (((s)<<3) | r) /* a global selector */\n\n/*\n * User segment descriptors (%cs, %ds etc for i386 apps. 64 bit wide)\n * For long-mode apps, %cs only has the conforming bit in sd_type, the sd_dpl,\n * sd_p, sd_l and sd_def32 which must be zero).  %ds only has sd_p.\n */\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\nstruct segment_descriptor {\n\tunsigned sd_lolimit:16;\t\t/* segment extent (lsb) */\n\tunsigned sd_lobase:24;\t\t/* segment base address (lsb) */\n\tunsigned sd_type:5;\t\t/* segment type */\n\tunsigned sd_dpl:2;\t\t/* segment descriptor priority level */\n\tunsigned sd_p:1;\t\t/* segment descriptor present */\n\tunsigned sd_hilimit:4;\t\t/* segment extent (msb) */\n\tunsigned sd_xx:2;\t\t/* unused */\n\tunsigned sd_def32:1;\t\t/* default 32 vs 16 bit size */\n\tunsigned sd_gran:1;\t\t/* limit granularity (byte/page units)*/\n\tunsigned sd_hibase:8;\t\t/* segment base address  (msb) */\n} __packed;\n#pragma clang diagnostic pop\n\nstruct user_segment_descriptor {\n\tuint64_t sd_lolimit:16; /* segment extent (lsb) */\n\tuint64_t sd_lobase:24; /* segment base address (lsb) */\n\tuint64_t sd_type:5; /* segment type */\n\tuint64_t sd_dpl:2; /* segment descriptor priority level */\n\tuint64_t sd_p:1; /* segment descriptor present */\n\tuint64_t sd_hilimit:4; /* segment extent (msb) */\n\tuint64_t sd_xx:1; /* unused */\n\tuint64_t sd_long:1; /* long mode (cs only) */\n\tuint64_t sd_def32:1; /* default 32 vs 16 bit size */\n\tuint64_t sd_gran:1; /* limit granularity (byte/page units)*/\n\tuint64_t sd_hibase:8; /* segment base address  (msb) */\n};\n\n#define USD_GETBASE(sd) (((sd)->sd_lobase) | (sd)->sd_hibase << 24)\n#define USD_SETBASE(sd, b) (sd)->sd_lobase = (b); \\\n\t(sd)->sd_hibase = ((b) >> 24);\n#define USD_GETLIMIT(sd) (((sd)->sd_lolimit) | (sd)->sd_hilimit << 16)\n#define USD_SETLIMIT(sd, l) (sd)->sd_lolimit = (l); \\\n\t(sd)->sd_hilimit = ((l) >> 16);\n\n// #ifdef __i386__\n// /*\n//  * Gate descriptors (e.g. indirect descriptors)\n//  */\n// struct gate_descriptor {\n// \tunsigned gd_looffset:16;\t/* gate offset (lsb) */\n// \tunsigned gd_selector:16;\t/* gate segment selector */\n// \tunsigned gd_stkcpy:5;\t\t/* number of stack wds to cpy */\n// \tunsigned gd_xx:3;\t\t/* unused */\n// \tunsigned gd_type:5;\t\t/* segment type */\n// \tunsigned gd_dpl:2;\t\t/* segment descriptor priority level */\n// \tunsigned gd_p:1;\t\t/* segment descriptor present */\n// \tunsigned gd_hioffset:16;\t/* gate offset (msb) */\n// } __packed;\n\n// /*\n//  * Generic descriptor\n//  */\n// union descriptor {\n// \tstruct segment_descriptor sd;\n// \tstruct gate_descriptor gd;\n// };\n// #else\n// /*\n//  * Gate descriptors (e.g. indirect descriptors, trap, interrupt etc. 128 bit)\n//  * Only interrupt and trap gates have gd_ist.\n//  */\n// struct gate_descriptor {\n// \tuint64_t gd_looffset:16;\t/* gate offset (lsb) */\n// \tuint64_t gd_selector:16;\t/* gate segment selector */\n// \tuint64_t gd_ist:3;\t\t/* IST table index */\n// \tuint64_t gd_xx:5;\t\t/* unused */\n// \tuint64_t gd_type:5;\t\t/* segment type */\n// \tuint64_t gd_dpl:2;\t\t/* segment descriptor priority level */\n// \tuint64_t gd_p:1;\t\t/* segment descriptor present */\n// \tuint64_t gd_hioffset:48;\t/* gate offset (msb) */\n// \tuint64_t sd_xx1:32;\n// } __packed;\n\n// /*\n//  * Generic descriptor\n//  */\n// union descriptor {\n// \tstruct user_segment_descriptor sd;\n// \tstruct gate_descriptor gd;\n// };\n// #endif\n\n\t/* system segments and gate types */\n#define SDT_SYSNULL 0 /* system null */\n#define SDT_SYS286TSS 1 /* system 286 TSS available */\n#define SDT_SYSLDT 2 /* system local descriptor table */\n#define SDT_SYS286BSY 3 /* system 286 TSS busy */\n#define SDT_SYS286CGT 4 /* system 286 call gate */\n#define SDT_SYSTASKGT 5 /* system task gate */\n#define SDT_SYS286IGT 6 /* system 286 interrupt gate */\n#define SDT_SYS286TGT 7 /* system 286 trap gate */\n#define SDT_SYSNULL2 8 /* system null again */\n#define SDT_SYS386TSS 9 /* system 386 TSS available */\n#define SDT_SYSTSS 9 /* system available 64 bit TSS */\n#define SDT_SYSNULL3 10 /* system null again */\n#define SDT_SYS386BSY 11 /* system 386 TSS busy */\n#define SDT_SYSBSY 11 /* system busy 64 bit TSS */\n#define SDT_SYS386CGT 12 /* system 386 call gate */\n#define SDT_SYSCGT 12 /* system 64 bit call gate */\n#define SDT_SYSNULL4 13 /* system null again */\n#define SDT_SYS386IGT 14 /* system 386 interrupt gate */\n#define SDT_SYSIGT 14 /* system 64 bit interrupt gate */\n#define SDT_SYS386TGT 15 /* system 386 trap gate */\n#define SDT_SYSTGT 15 /* system 64 bit trap gate */\n\n// \t/* memory segment types */\n// #define\tSDT_MEMRO\t16\t memory read only \n// #define\tSDT_MEMROA\t17\t/* memory read only accessed */\n#define SDT_MEMRW 18 /* memory read write */\n#define SDT_MEMRWA 19 /* memory read write accessed */\n// #define\tSDT_MEMROD\t20\t/* memory read only expand dwn limit */\n// #define\tSDT_MEMRODA\t21\t/* memory read only expand dwn limit accessed */\n// #define\tSDT_MEMRWD\t22\t/* memory read write expand dwn limit */\n// #define\tSDT_MEMRWDA\t23\t/* memory read write expand dwn limit accessed*/\n// #define\tSDT_MEME\t24\t/* memory execute only */\n// #define\tSDT_MEMEA\t25\t/* memory execute only accessed */\n#define SDT_MEMER 26 /* memory execute read */\n#define SDT_MEMERA 27 /* memory execute read accessed */\n// #define\tSDT_MEMEC\t28\t/* memory execute only conforming */\n// #define\tSDT_MEMEAC\t29\t/* memory execute only accessed conforming */\n// #define\tSDT_MEMERC\t30\t/* memory execute read conforming */\n// #define\tSDT_MEMERAC\t31\t/* memory execute read accessed conforming */\n\n// /*\n//  * Size of IDT table\n//  */\n// #define\tNIDT\t\t256\t/* 32 reserved, 0x80 syscall, most are h/w */\n// #define\tNRSVIDT\t\t32\t/* reserved entries for cpu exceptions */\n\n/*\n * Entries in the Interrupt Descriptor Table (IDT)\n */\n#define\tIDT_DE\t\t0\t/* #DE: Divide Error */\n#define\tIDT_DB\t\t1\t/* #DB: Debug */\n#define\tIDT_NMI\t\t2\t/* Nonmaskable External Interrupt */\n#define\tIDT_BP\t\t3\t/* #BP: Breakpoint */\n#define\tIDT_OF\t\t4\t/* #OF: Overflow */\n#define\tIDT_BR\t\t5\t/* #BR: Bound Range Exceeded */\n#define\tIDT_UD\t\t6\t/* #UD: Undefined/Invalid Opcode */\n#define\tIDT_NM\t\t7\t/* #NM: No Math Coprocessor */\n#define\tIDT_DF\t\t8\t/* #DF: Double Fault */\n#define\tIDT_FPUGP\t9\t/* Coprocessor Segment Overrun */\n#define\tIDT_TS\t\t10\t/* #TS: Invalid TSS */\n#define\tIDT_NP\t\t11\t/* #NP: Segment Not Present */\n#define\tIDT_SS\t\t12\t/* #SS: Stack Segment Fault */\n#define\tIDT_GP\t\t13\t/* #GP: General Protection Fault */\n#define\tIDT_PF\t\t14\t/* #PF: Page Fault */\n#define\tIDT_MF\t\t16\t/* #MF: FPU Floating-Point Error */\n#define\tIDT_AC\t\t17\t/* #AC: Alignment Check */\n#define\tIDT_MC\t\t18\t/* #MC: Machine Check */\n#define\tIDT_XF\t\t19\t/* #XF: SIMD Floating-Point Exception */\n#define\tIDT_IO_INTS\tNRSVIDT\t/* Base of IDT entries for I/O interrupts. */\n#define\tIDT_SYSCALL\t0x80\t/* System Call Interrupt Vector */\n#define\tIDT_DTRACE_RET\t0x92\t/* DTrace pid provider Interrupt Vector */\n#define\tIDT_EVTCHN\t0x93\t/* Xen HVM Event Channel Interrupt Vector */\n\n// #if defined(__i386__)\n// /*\n//  * Entries in the Global Descriptor Table (GDT)\n//  * Note that each 4 entries share a single 32 byte L1 cache line.\n//  * Some of the fast syscall instructions require a specific order here.\n//  */\n// #define\tGNULL_SEL\t0\t/* Null Descriptor */\n// #define\tGPRIV_SEL\t1\t/* SMP Per-Processor Private Data */\n// #define\tGUFS_SEL\t2\t/* User %fs Descriptor (order critical: 1) */\n// #define\tGUGS_SEL\t3\t/* User %gs Descriptor (order critical: 2) */\n// #define\tGCODE_SEL\t4\t/* Kernel Code Descriptor (order critical: 1) */\n// #define\tGDATA_SEL\t5\t/* Kernel Data Descriptor (order critical: 2) */\n// #define\tGUCODE_SEL\t6\t/* User Code Descriptor (order critical: 3) */\n// #define\tGUDATA_SEL\t7\t/* User Data Descriptor (order critical: 4) */\n// #define\tGBIOSLOWMEM_SEL\t8\t/* BIOS low memory access (must be entry 8) */\n// #define\tGPROC0_SEL\t9\t/* Task state process slot zero and up */\n// #define\tGLDT_SEL\t10\t/* Default User LDT */\n// #define\tGUSERLDT_SEL\t11\t/* User LDT */\n// #define\tGPANIC_SEL\t12\t/* Task state to consider panic from */\n// #define\tGBIOSCODE32_SEL\t13\t/* BIOS interface (32bit Code) */\n// #define\tGBIOSCODE16_SEL\t14\t/* BIOS interface (16bit Code) */\n// #define\tGBIOSDATA_SEL\t15\t/* BIOS interface (Data) */\n// #define\tGBIOSUTIL_SEL\t16\t/* BIOS interface (Utility) */\n// #define\tGBIOSARGS_SEL\t17\t/* BIOS interface (Arguments) */\n// #define\tGNDIS_SEL\t18\t/* For the NDIS layer */\n// #define\tNGDT\t\t19\n\n// /*\n//  * Entries in the Local Descriptor Table (LDT)\n//  */\n// #define\tLSYS5CALLS_SEL\t0\t/* forced by intel BCS */\n// #define\tLSYS5SIGR_SEL\t1\n// #define\tL43BSDCALLS_SEL\t2\t/* notyet */\n// #define\tLUCODE_SEL\t3\n// #define\tLSOL26CALLS_SEL\t4\t/* Solaris >= 2.6 system call gate */\n// #define\tLUDATA_SEL\t5\n// /* separate stack, es,fs,gs sels ? */\n// /* #define\tLPOSIXCALLS_SEL\t5*/\t/* notyet */\n// #define\tLBSDICALLS_SEL\t16\t/* BSDI system call gate */\n// #define\tNLDT\t\t(LBSDICALLS_SEL + 1)\n\n// #else /* !__i386__ */\n// /*\n//  * Entries in the Global Descriptor Table (GDT)\n//  */\n// #define\tGNULL_SEL\t0\t/* Null Descriptor */\n// #define\tGNULL2_SEL\t1\t/* Null Descriptor */\n// #define\tGUFS32_SEL\t2\t/* User 32 bit %fs Descriptor */\n// #define\tGUGS32_SEL\t3\t/* User 32 bit %gs Descriptor */\n// #define\tGCODE_SEL\t4\t/* Kernel Code Descriptor */\n// #define\tGDATA_SEL\t5\t/* Kernel Data Descriptor */\n// #define\tGUCODE32_SEL\t6\t/* User 32 bit code Descriptor */\n// #define\tGUDATA_SEL\t7\t/* User 32/64 bit Data Descriptor */\n// #define\tGUCODE_SEL\t8\t/* User 64 bit Code Descriptor */\n// #define\tGPROC0_SEL\t9\t/* TSS for entering kernel etc */\n// /* slot 10 is second half of GPROC0_SEL */\n// #define\tGUSERLDT_SEL\t11\t/* LDT */\n// /* slot 12 is second half of GUSERLDT_SEL */\n// #define\tNGDT \t\t13\n// #endif /* __i386__ */\n"
  },
  {
    "path": "include/xhyve/support/specialreg.h",
    "content": "/*-\n * Copyright (c) 1991 The Regents of the University of California.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *\tfrom: @(#)specialreg.h\t7.1 (Berkeley) 5/9/91\n * $FreeBSD$\n */\n\n#pragma once\n\n/*\n * Bits in 386 special registers:\n */\n#define\tCR0_PE\t0x00000001\t/* Protected mode Enable */\n#define\tCR0_MP\t0x00000002\t/* \"Math\" (fpu) Present */\n#define\tCR0_EM\t0x00000004\t/* EMulate FPU instructions. (trap ESC only) */\n#define\tCR0_TS\t0x00000008\t/* Task Switched (if MP, trap ESC and WAIT) */\n#define\tCR0_PG\t0x80000000\t/* PaGing enable */\n\n/*\n * Bits in 486 special registers:\n */\n#define\tCR0_ET\t0x00000010\t/* Extension type */\n#define\tCR0_NE\t0x00000020\t/* Numeric Error enable (EX16 vs IRQ13) */\n#define\tCR0_WP\t0x00010000\t/* Write Protect (honor page protect in\n\t\t\t\t\t\t\t   all modes) */\n#define\tCR0_AM\t0x00040000\t/* Alignment Mask (set to enable AC flag) */\n#define\tCR0_NW  0x20000000\t/* Not Write-through */\n#define\tCR0_CD  0x40000000\t/* Cache Disable */\n\n#define\tCR3_PCID_SAVE 0x8000000000000000\n#define\tCR3_PCID_MASK 0xfff\n\n/*\n * Bits in PPro special registers\n */\n#define\tCR4_VME\t0x00000001\t/* Virtual 8086 mode extensions */\n#define\tCR4_PVI\t0x00000002\t/* Protected-mode virtual interrupts */\n#define\tCR4_TSD\t0x00000004\t/* Time stamp disable */\n#define\tCR4_DE\t0x00000008\t/* Debugging extensions */\n#define\tCR4_PSE\t0x00000010\t/* Page size extensions */\n#define\tCR4_PAE\t0x00000020\t/* Physical address extension */\n#define\tCR4_MCE\t0x00000040\t/* Machine check enable */\n#define\tCR4_PGE\t0x00000080\t/* Page global enable */\n#define\tCR4_PCE\t0x00000100\t/* Performance monitoring counter enable */\n#define\tCR4_FXSR 0x00000200\t/* Fast FPU save/restore used by OS */\n#define\tCR4_XMM\t0x00000400\t/* enable SIMD/MMX2 to use except 16 */\n#define\tCR4_VMXE 0x00002000\t/* enable VMX operation (Intel-specific) */\n#define\tCR4_FSGSBASE 0x00010000\t/* Enable FS/GS BASE accessing instructions */\n#define\tCR4_PCIDE 0x00020000\t/* Enable Context ID */\n#define\tCR4_XSAVE 0x00040000\t/* XSETBV/XGETBV */\n#define\tCR4_SMEP 0x00100000\t/* Supervisor-Mode Execution Prevention */\n\n/*\n * Bits in AMD64 special registers.  EFER is 64 bits wide.\n */\n#define\tEFER_SCE 0x000000001\t/* System Call Extensions (R/W) */\n#define\tEFER_LME 0x000000100\t/* Long mode enable (R/W) */\n#define\tEFER_LMA 0x000000400\t/* Long mode active (R) */\n#define\tEFER_NXE 0x000000800\t/* PTE No-Execute bit enable (R/W) */\n#define\tEFER_SVM 0x000001000\t/* SVM enable bit for AMD, reserved for Intel */\n#define\tEFER_LMSLE 0x000002000\t/* Long Mode Segment Limit Enable */\n#define\tEFER_FFXSR 0x000004000\t/* Fast FXSAVE/FSRSTOR */\n#define\tEFER_TCE   0x000008000\t/* Translation Cache Extension */\n\n/*\n * Intel Extended Features registers\n */\n#define\tXCR0\t0\t\t/* XFEATURE_ENABLED_MASK register */\n\n#define\tXFEATURE_ENABLED_X87\t\t0x00000001\n#define\tXFEATURE_ENABLED_SSE\t\t0x00000002\n#define\tXFEATURE_ENABLED_YMM_HI128\t0x00000004\n#define\tXFEATURE_ENABLED_AVX\t\tXFEATURE_ENABLED_YMM_HI128\n#define\tXFEATURE_ENABLED_BNDREGS\t0x00000008\n#define\tXFEATURE_ENABLED_BNDCSR\t\t0x00000010\n#define\tXFEATURE_ENABLED_OPMASK\t\t0x00000020\n#define\tXFEATURE_ENABLED_ZMM_HI256\t0x00000040\n#define\tXFEATURE_ENABLED_HI16_ZMM\t0x00000080\n\n#define\tXFEATURE_AVX\t\t\t\t\t\\\n    (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE | XFEATURE_ENABLED_AVX)\n#define\tXFEATURE_AVX512\t\t\t\t\t\t\\\n    (XFEATURE_ENABLED_OPMASK | XFEATURE_ENABLED_ZMM_HI256 |\t\\\n    XFEATURE_ENABLED_HI16_ZMM)\n#define\tXFEATURE_MPX\t\t\t\t\t\\\n    (XFEATURE_ENABLED_BNDREGS | XFEATURE_ENABLED_BNDCSR)\n\n/*\n * CPUID instruction features register\n */\n#define\tCPUID_FPU\t0x00000001\n#define\tCPUID_VME\t0x00000002\n#define\tCPUID_DE\t0x00000004\n#define\tCPUID_PSE\t0x00000008\n#define\tCPUID_TSC\t0x00000010\n#define\tCPUID_MSR\t0x00000020\n#define\tCPUID_PAE\t0x00000040\n#define\tCPUID_MCE\t0x00000080\n#define\tCPUID_CX8\t0x00000100\n#define\tCPUID_APIC\t0x00000200\n#define\tCPUID_B10\t0x00000400\n#define\tCPUID_SEP\t0x00000800\n#define\tCPUID_MTRR\t0x00001000\n#define\tCPUID_PGE\t0x00002000\n#define\tCPUID_MCA\t0x00004000\n#define\tCPUID_CMOV\t0x00008000\n#define\tCPUID_PAT\t0x00010000\n#define\tCPUID_PSE36\t0x00020000\n#define\tCPUID_PSN\t0x00040000\n#define\tCPUID_CLFSH\t0x00080000\n#define\tCPUID_B20\t0x00100000\n#define\tCPUID_DS\t0x00200000\n#define\tCPUID_ACPI\t0x00400000\n#define\tCPUID_MMX\t0x00800000\n#define\tCPUID_FXSR\t0x01000000\n#define\tCPUID_SSE\t0x02000000\n#define\tCPUID_XMM\t0x02000000\n#define\tCPUID_SSE2\t0x04000000\n#define\tCPUID_SS\t0x08000000\n#define\tCPUID_HTT\t0x10000000\n#define\tCPUID_TM\t0x20000000\n#define\tCPUID_IA64\t0x40000000\n#define\tCPUID_PBE\t0x80000000\n\n#define\tCPUID2_SSE3\t0x00000001\n#define\tCPUID2_PCLMULQDQ 0x00000002\n#define\tCPUID2_DTES64\t0x00000004\n#define\tCPUID2_MON\t0x00000008\n#define\tCPUID2_DS_CPL\t0x00000010\n#define\tCPUID2_VMX\t0x00000020\n#define\tCPUID2_SMX\t0x00000040\n#define\tCPUID2_EST\t0x00000080\n#define\tCPUID2_TM2\t0x00000100\n#define\tCPUID2_SSSE3\t0x00000200\n#define\tCPUID2_CNXTID\t0x00000400\n#define\tCPUID2_SDBG\t0x00000800\n#define\tCPUID2_FMA\t0x00001000\n#define\tCPUID2_CX16\t0x00002000\n#define\tCPUID2_XTPR\t0x00004000\n#define\tCPUID2_PDCM\t0x00008000\n#define\tCPUID2_PCID\t0x00020000\n#define\tCPUID2_DCA\t0x00040000\n#define\tCPUID2_SSE41\t0x00080000\n#define\tCPUID2_SSE42\t0x00100000\n#define\tCPUID2_X2APIC\t0x00200000\n#define\tCPUID2_MOVBE\t0x00400000\n#define\tCPUID2_POPCNT\t0x00800000\n#define\tCPUID2_TSCDLT\t0x01000000\n#define\tCPUID2_AESNI\t0x02000000\n#define\tCPUID2_XSAVE\t0x04000000\n#define\tCPUID2_OSXSAVE\t0x08000000\n#define\tCPUID2_AVX\t0x10000000\n#define\tCPUID2_F16C\t0x20000000\n#define\tCPUID2_RDRAND\t0x40000000\n#define\tCPUID2_HV\t0x80000000\n\n/*\n * Important bits in the Thermal and Power Management flags\n * CPUID.6 EAX and ECX.\n */\n#define\tCPUTPM1_SENSOR\t0x00000001\n#define\tCPUTPM1_TURBO\t0x00000002\n#define\tCPUTPM1_ARAT\t0x00000004\n#define\tCPUTPM2_EFFREQ\t0x00000001\n\n/*\n * Important bits in the AMD extended cpuid flags\n */\n#define\tAMDID_SYSCALL\t0x00000800\n#define\tAMDID_MP\t0x00080000\n#define\tAMDID_NX\t0x00100000\n#define\tAMDID_EXT_MMX\t0x00400000\n#define\tAMDID_FFXSR\t0x02000000\n#define\tAMDID_PAGE1GB\t0x04000000\n#define\tAMDID_RDTSCP\t0x08000000\n#define\tAMDID_LM\t0x20000000\n#define\tAMDID_EXT_3DNOW\t0x40000000\n#define\tAMDID_3DNOW\t0x80000000\n\n#define\tAMDID2_LAHF\t0x00000001\n#define\tAMDID2_CMP\t0x00000002\n#define\tAMDID2_SVM\t0x00000004\n#define\tAMDID2_EXT_APIC\t0x00000008\n#define\tAMDID2_CR8\t0x00000010\n#define\tAMDID2_ABM\t0x00000020\n#define\tAMDID2_SSE4A\t0x00000040\n#define\tAMDID2_MAS\t0x00000080\n#define\tAMDID2_PREFETCH\t0x00000100\n#define\tAMDID2_OSVW\t0x00000200\n#define\tAMDID2_IBS\t0x00000400\n#define\tAMDID2_XOP\t0x00000800\n#define\tAMDID2_SKINIT\t0x00001000\n#define\tAMDID2_WDT\t0x00002000\n#define\tAMDID2_LWP\t0x00008000\n#define\tAMDID2_FMA4\t0x00010000\n#define\tAMDID2_TCE\t0x00020000\n#define\tAMDID2_NODE_ID\t0x00080000\n#define\tAMDID2_TBM\t0x00200000\n#define\tAMDID2_TOPOLOGY\t0x00400000\n#define\tAMDID2_PCXC\t0x00800000\n#define\tAMDID2_PNXC\t0x01000000\n#define\tAMDID2_DBE\t0x04000000\n#define\tAMDID2_PTSC\t0x08000000\n#define\tAMDID2_PTSCEL2I\t0x10000000\n\n/*\n * CPUID instruction 1 eax info\n */\n#define\tCPUID_STEPPING\t\t0x0000000f\n#define\tCPUID_MODEL\t\t0x000000f0\n#define\tCPUID_FAMILY\t\t0x00000f00\n#define\tCPUID_EXT_MODEL\t\t0x000f0000\n#define\tCPUID_EXT_FAMILY\t0x0ff00000\n// #ifdef __i386__\n// #define\tCPUID_TO_MODEL(id) \\\n//     ((((id) & CPUID_MODEL) >> 4) | \\\n//     ((((id) & CPUID_FAMILY) >= 0x600) ? \\\n//     (((id) & CPUID_EXT_MODEL) >> 12) : 0))\n// #define\tCPUID_TO_FAMILY(id) \\\n//     ((((id) & CPUID_FAMILY) >> 8) + \\\n//     ((((id) & CPUID_FAMILY) == 0xf00) ? \\\n//     (((id) & CPUID_EXT_FAMILY) >> 20) : 0))\n// #else\n// #define\tCPUID_TO_MODEL(id) \\\n//     ((((id) & CPUID_MODEL) >> 4) | \\\n//     (((id) & CPUID_EXT_MODEL) >> 12))\n// #define\tCPUID_TO_FAMILY(id) \\\n//     ((((id) & CPUID_FAMILY) >> 8) + \\\n//     (((id) & CPUID_EXT_FAMILY) >> 20))\n// #endif\n\n/*\n * CPUID instruction 1 ebx info\n */\n#define\tCPUID_BRAND_INDEX\t0x000000ff\n#define\tCPUID_CLFUSH_SIZE\t0x0000ff00\n#define\tCPUID_HTT_CORES\t\t0x00ff0000\n#define\tCPUID_LOCAL_APIC_ID\t0xff000000\n\n/*\n * CPUID instruction 5 info\n */\n#define\tCPUID5_MON_MIN_SIZE\t0x0000ffff\t/* eax */\n#define\tCPUID5_MON_MAX_SIZE\t0x0000ffff\t/* ebx */\n#define\tCPUID5_MON_MWAIT_EXT\t0x00000001\t/* ecx */\n#define\tCPUID5_MWAIT_INTRBREAK\t0x00000002\t/* ecx */\n\n/*\n * MWAIT cpu power states.  Lower 4 bits are sub-states.\n */\n#define\tMWAIT_C0\t0xf0\n#define\tMWAIT_C1\t0x00\n#define\tMWAIT_C2\t0x10\n#define\tMWAIT_C3\t0x20\n#define\tMWAIT_C4\t0x30\n\n/*\n * MWAIT extensions.\n */\n/* Interrupt breaks MWAIT even when masked. */\n#define\tMWAIT_INTRBREAK\t\t0x00000001\n\n/*\n * CPUID instruction 6 ecx info\n */\n#define\tCPUID_PERF_STAT\t\t0x00000001\n#define\tCPUID_PERF_BIAS\t\t0x00000008\n\n/* \n * CPUID instruction 0xb ebx info.\n */\n#define\tCPUID_TYPE_INVAL\t0\n#define\tCPUID_TYPE_SMT\t\t1\n#define\tCPUID_TYPE_CORE\t\t2\n\n/*\n * CPUID instruction 0xd Processor Extended State Enumeration Sub-leaf 1\n */\n#define\tCPUID_EXTSTATE_XSAVEOPT\t0x00000001\n#define\tCPUID_EXTSTATE_XSAVEC\t0x00000002\n#define\tCPUID_EXTSTATE_XINUSE\t0x00000004\n#define\tCPUID_EXTSTATE_XSAVES\t0x00000008\n\n/*\n * AMD extended function 8000_0007h edx info\n */\n#define\tAMDPM_TS\t\t0x00000001\n#define\tAMDPM_FID\t\t0x00000002\n#define\tAMDPM_VID\t\t0x00000004\n#define\tAMDPM_TTP\t\t0x00000008\n#define\tAMDPM_TM\t\t0x00000010\n#define\tAMDPM_STC\t\t0x00000020\n#define\tAMDPM_100MHZ_STEPS\t0x00000040\n#define\tAMDPM_HW_PSTATE\t\t0x00000080\n#define\tAMDPM_TSC_INVARIANT\t0x00000100\n#define\tAMDPM_CPB\t\t0x00000200\n\n/*\n * AMD extended function 8000_0008h ecx info\n */\n#define\tAMDID_CMP_CORES\t\t0x000000ff\n#define\tAMDID_COREID_SIZE\t0x0000f000\n#define\tAMDID_COREID_SIZE_SHIFT\t12\n\n/*\n * CPUID instruction 7 Structured Extended Features, leaf 0 ebx info\n */\n#define\tCPUID_STDEXT_FSGSBASE\t0x00000001\n#define\tCPUID_STDEXT_TSC_ADJUST\t0x00000002\n#define\tCPUID_STDEXT_BMI1\t0x00000008\n#define\tCPUID_STDEXT_HLE\t0x00000010\n#define\tCPUID_STDEXT_AVX2\t0x00000020\n#define\tCPUID_STDEXT_SMEP\t0x00000080\n#define\tCPUID_STDEXT_BMI2\t0x00000100\n#define\tCPUID_STDEXT_ERMS\t0x00000200\n#define\tCPUID_STDEXT_INVPCID\t0x00000400\n#define\tCPUID_STDEXT_RTM\t0x00000800\n#define\tCPUID_STDEXT_MPX\t0x00004000\n#define\tCPUID_STDEXT_AVX512F\t0x00010000\n#define\tCPUID_STDEXT_RDSEED\t0x00040000\n#define\tCPUID_STDEXT_ADX\t0x00080000\n#define\tCPUID_STDEXT_SMAP\t0x00100000\n#define\tCPUID_STDEXT_CLFLUSHOPT\t0x00800000\n#define\tCPUID_STDEXT_PROCTRACE\t0x02000000\n#define\tCPUID_STDEXT_AVX512PF\t0x04000000\n#define\tCPUID_STDEXT_AVX512ER\t0x08000000\n#define\tCPUID_STDEXT_AVX512CD\t0x10000000\n#define\tCPUID_STDEXT_SHA\t0x20000000\n\n/*\n * CPUID manufacturers identifiers\n */\n#define\tAMD_VENDOR_ID\t\t\"AuthenticAMD\"\n#define\tCENTAUR_VENDOR_ID\t\"CentaurHauls\"\n#define\tCYRIX_VENDOR_ID\t\t\"CyrixInstead\"\n#define\tINTEL_VENDOR_ID\t\t\"GenuineIntel\"\n#define\tNEXGEN_VENDOR_ID\t\"NexGenDriven\"\n#define\tNSC_VENDOR_ID\t\t\"Geode by NSC\"\n#define\tRISE_VENDOR_ID\t\t\"RiseRiseRise\"\n#define\tSIS_VENDOR_ID\t\t\"SiS SiS SiS \"\n#define\tTRANSMETA_VENDOR_ID\t\"GenuineTMx86\"\n#define\tUMC_VENDOR_ID\t\t\"UMC UMC UMC \"\n\n/*\n * Model-specific registers for the i386 family\n */\n#define\tMSR_P5_MC_ADDR\t\t0x000\n#define\tMSR_P5_MC_TYPE\t\t0x001\n#define\tMSR_TSC\t\t\t0x010\n#define\tMSR_P5_CESR\t\t0x011\n#define\tMSR_P5_CTR0\t\t0x012\n#define\tMSR_P5_CTR1\t\t0x013\n#define\tMSR_IA32_PLATFORM_ID\t0x017\n#define\tMSR_APICBASE\t\t0x01b\n#define\tMSR_EBL_CR_POWERON\t0x02a\n#define\tMSR_TEST_CTL\t\t0x033\n#define\tMSR_IA32_FEATURE_CONTROL 0x03a\n#define\tMSR_BIOS_UPDT_TRIG\t0x079\n#define\tMSR_BBL_CR_D0\t\t0x088\n#define\tMSR_BBL_CR_D1\t\t0x089\n#define\tMSR_BBL_CR_D2\t\t0x08a\n#define\tMSR_BIOS_SIGN\t\t0x08b\n#define\tMSR_PERFCTR0\t\t0x0c1\n#define\tMSR_PERFCTR1\t\t0x0c2\n#define\tMSR_PLATFORM_INFO\t0x0ce\n#define\tMSR_MPERF\t\t0x0e7\n#define\tMSR_APERF\t\t0x0e8\n#define\tMSR_IA32_EXT_CONFIG\t0x0ee\t/* Undocumented. Core Solo/Duo only */\n#define\tMSR_MTRRcap\t\t0x0fe\n#define\tMSR_BBL_CR_ADDR\t\t0x116\n#define\tMSR_BBL_CR_DECC\t\t0x118\n#define\tMSR_BBL_CR_CTL\t\t0x119\n#define\tMSR_BBL_CR_TRIG\t\t0x11a\n#define\tMSR_BBL_CR_BUSY\t\t0x11b\n#define\tMSR_BBL_CR_CTL3\t\t0x11e\n#define\tMSR_SYSENTER_CS_MSR\t0x174\n#define\tMSR_SYSENTER_ESP_MSR\t0x175\n#define\tMSR_SYSENTER_EIP_MSR\t0x176\n#define\tMSR_MCG_CAP\t\t0x179\n#define\tMSR_MCG_STATUS\t\t0x17a\n#define\tMSR_MCG_CTL\t\t0x17b\n#define\tMSR_EVNTSEL0\t\t0x186\n#define\tMSR_EVNTSEL1\t\t0x187\n#define\tMSR_THERM_CONTROL\t0x19a\n#define\tMSR_THERM_INTERRUPT\t0x19b\n#define\tMSR_THERM_STATUS\t0x19c\n#define\tMSR_IA32_MISC_ENABLE\t0x1a0\n#define\tMSR_IA32_TEMPERATURE_TARGET\t0x1a2\n#define\tMSR_TURBO_RATIO_LIMIT\t0x1ad\n#define\tMSR_TURBO_RATIO_LIMIT1\t0x1ae\n#define\tMSR_DEBUGCTLMSR\t\t0x1d9\n#define\tMSR_LASTBRANCHFROMIP\t0x1db\n#define\tMSR_LASTBRANCHTOIP\t0x1dc\n#define\tMSR_LASTINTFROMIP\t0x1dd\n#define\tMSR_LASTINTTOIP\t\t0x1de\n#define\tMSR_ROB_CR_BKUPTMPDR6\t0x1e0\n#define\tMSR_MTRRVarBase\t\t0x200\n#define\tMSR_MTRR64kBase\t\t0x250\n#define\tMSR_MTRR16kBase\t\t0x258\n#define\tMSR_MTRR4kBase\t\t0x268\n#define\tMSR_PAT\t\t\t0x277\n#define\tMSR_MC0_CTL2\t\t0x280\n#define\tMSR_MTRRdefType\t\t0x2ff\n#define\tMSR_MC0_CTL\t\t0x400\n#define\tMSR_MC0_STATUS\t\t0x401\n#define\tMSR_MC0_ADDR\t\t0x402\n#define\tMSR_MC0_MISC\t\t0x403\n#define\tMSR_MC1_CTL\t\t0x404\n#define\tMSR_MC1_STATUS\t\t0x405\n#define\tMSR_MC1_ADDR\t\t0x406\n#define\tMSR_MC1_MISC\t\t0x407\n#define\tMSR_MC2_CTL\t\t0x408\n#define\tMSR_MC2_STATUS\t\t0x409\n#define\tMSR_MC2_ADDR\t\t0x40a\n#define\tMSR_MC2_MISC\t\t0x40b\n#define\tMSR_MC3_CTL\t\t0x40c\n#define\tMSR_MC3_STATUS\t\t0x40d\n#define\tMSR_MC3_ADDR\t\t0x40e\n#define\tMSR_MC3_MISC\t\t0x40f\n#define\tMSR_MC4_CTL\t\t0x410\n#define\tMSR_MC4_STATUS\t\t0x411\n#define\tMSR_MC4_ADDR\t\t0x412\n#define\tMSR_MC4_MISC\t\t0x413\n#define\tMSR_RAPL_POWER_UNIT\t0x606\n#define\tMSR_PKG_ENERGY_STATUS\t0x611\n#define\tMSR_DRAM_ENERGY_STATUS\t0x619\n#define\tMSR_PP0_ENERGY_STATUS\t0x639\n#define\tMSR_PP1_ENERGY_STATUS\t0x641\n\n/*\n * VMX MSRs\n */\n#define\tMSR_VMX_BASIC\t\t0x480\n#define\tMSR_VMX_PINBASED_CTLS\t0x481\n#define\tMSR_VMX_PROCBASED_CTLS\t0x482\n#define\tMSR_VMX_EXIT_CTLS\t0x483\n#define\tMSR_VMX_ENTRY_CTLS\t0x484\n#define\tMSR_VMX_CR0_FIXED0\t0x486\n#define\tMSR_VMX_CR0_FIXED1\t0x487\n#define\tMSR_VMX_CR4_FIXED0\t0x488\n#define\tMSR_VMX_CR4_FIXED1\t0x489\n#define\tMSR_VMX_PROCBASED_CTLS2\t0x48b\n#define\tMSR_VMX_EPT_VPID_CAP\t0x48c\n#define\tMSR_VMX_TRUE_PINBASED_CTLS\t0x48d\n#define\tMSR_VMX_TRUE_PROCBASED_CTLS\t0x48e\n#define\tMSR_VMX_TRUE_EXIT_CTLS\t0x48f\n#define\tMSR_VMX_TRUE_ENTRY_CTLS\t0x490\n\n/*\n * X2APIC MSRs\n */\n#define\tMSR_APIC_000\t\t0x800\n#define\tMSR_APIC_ID\t\t0x802\n#define\tMSR_APIC_VERSION\t0x803\n#define\tMSR_APIC_TPR\t\t0x808\n#define\tMSR_APIC_EOI\t\t0x80b\n#define\tMSR_APIC_LDR\t\t0x80d\n#define\tMSR_APIC_SVR\t\t0x80f\n#define\tMSR_APIC_ISR0\t\t0x810\n#define\tMSR_APIC_ISR1\t\t0x811\n#define\tMSR_APIC_ISR2\t\t0x812\n#define\tMSR_APIC_ISR3\t\t0x813\n#define\tMSR_APIC_ISR4\t\t0x814\n#define\tMSR_APIC_ISR5\t\t0x815\n#define\tMSR_APIC_ISR6\t\t0x816\n#define\tMSR_APIC_ISR7\t\t0x817\n#define\tMSR_APIC_TMR0\t\t0x818\n#define\tMSR_APIC_IRR0\t\t0x820\n#define\tMSR_APIC_ESR\t\t0x828\n#define\tMSR_APIC_LVT_CMCI\t0x82F\n#define\tMSR_APIC_ICR\t\t0x830\n#define\tMSR_APIC_LVT_TIMER\t0x832\n#define\tMSR_APIC_LVT_THERMAL\t0x833\n#define\tMSR_APIC_LVT_PCINT\t0x834\n#define\tMSR_APIC_LVT_LINT0\t0x835\n#define\tMSR_APIC_LVT_LINT1\t0x836\n#define\tMSR_APIC_LVT_ERROR\t0x837\n#define\tMSR_APIC_ICR_TIMER\t0x838\n#define\tMSR_APIC_CCR_TIMER\t0x839\n#define\tMSR_APIC_DCR_TIMER\t0x83e\n#define\tMSR_APIC_SELF_IPI\t0x83f\n\n#define\tMSR_IA32_XSS\t\t0xda0\n\n#define MSR_IA32_TSC_AUX\t0xc0000103\n\n/*\n * Constants related to MSR's.\n */\n#define\tAPICBASE_RESERVED\t0x000002ff\n#define\tAPICBASE_BSP\t\t0x00000100\n#define\tAPICBASE_X2APIC\t\t0x00000400\n#define\tAPICBASE_ENABLED\t0x00000800\n#define\tAPICBASE_ADDRESS\t0xfffff000\n\n/* MSR_IA32_FEATURE_CONTROL related */\n#define\tIA32_FEATURE_CONTROL_LOCK\t0x01\t/* lock bit */\n#define\tIA32_FEATURE_CONTROL_SMX_EN\t0x02\t/* enable VMX inside SMX */\n#define\tIA32_FEATURE_CONTROL_VMX_EN\t0x04\t/* enable VMX outside SMX */\n\n/*\n * PAT modes.\n */\n#define\tPAT_UNCACHEABLE\t\t0x00\n#define\tPAT_WRITE_COMBINING\t0x01\n#define\tPAT_WRITE_THROUGH\t0x04\n#define\tPAT_WRITE_PROTECTED\t0x05\n#define\tPAT_WRITE_BACK\t\t0x06\n#define\tPAT_UNCACHED\t\t0x07\n#define\tPAT_VALUE(i, m)\t\t((long long)(m) << (8 * (i)))\n#define\tPAT_MASK(i)\t\tPAT_VALUE(i, 0xff)\n\n/*\n * Constants related to MTRRs\n */\n#define\tMTRR_UNCACHEABLE\t0x00\n#define\tMTRR_WRITE_COMBINING\t0x01\n#define\tMTRR_WRITE_THROUGH\t0x04\n#define\tMTRR_WRITE_PROTECTED\t0x05\n#define\tMTRR_WRITE_BACK\t\t0x06\n#define\tMTRR_N64K\t\t8\t/* numbers of fixed-size entries */\n#define\tMTRR_N16K\t\t16\n#define\tMTRR_N4K\t\t64\n#define\tMTRR_CAP_WC\t\t0x0000000000000400\n#define\tMTRR_CAP_FIXED\t\t0x0000000000000100\n#define\tMTRR_CAP_VCNT\t\t0x00000000000000ff\n#define\tMTRR_DEF_ENABLE\t\t0x0000000000000800\n#define\tMTRR_DEF_FIXED_ENABLE\t0x0000000000000400\n#define\tMTRR_DEF_TYPE\t\t0x00000000000000ff\n#define\tMTRR_PHYSBASE_PHYSBASE\t0x000ffffffffff000\n#define\tMTRR_PHYSBASE_TYPE\t0x00000000000000ff\n#define\tMTRR_PHYSMASK_PHYSMASK\t0x000ffffffffff000\n#define\tMTRR_PHYSMASK_VALID\t0x0000000000000800\n\n/*\n * Cyrix configuration registers, accessible as IO ports.\n */\n#define\tCCR0\t\t\t0xc0\t/* Configuration control register 0 */\n#define\tCCR0_NC0\t\t0x01\t/* First 64K of each 1M memory region is\n\t\t\t\t\t\t\t\t   non-cacheable */\n#define\tCCR0_NC1\t\t0x02\t/* 640K-1M region is non-cacheable */\n#define\tCCR0_A20M\t\t0x04\t/* Enables A20M# input pin */\n#define\tCCR0_KEN\t\t0x08\t/* Enables KEN# input pin */\n#define\tCCR0_FLUSH\t\t0x10\t/* Enables FLUSH# input pin */\n#define\tCCR0_BARB\t\t0x20\t/* Flushes internal cache when entering hold\n\t\t\t\t\t\t\t\t   state */\n#define\tCCR0_CO\t\t\t0x40\t/* Cache org: 1=direct mapped, 0=2x set\n\t\t\t\t\t\t\t\t   assoc */\n#define\tCCR0_SUSPEND\t0x80\t/* Enables SUSP# and SUSPA# pins */\n\n#define\tCCR1\t\t\t0xc1\t/* Configuration control register 1 */\n#define\tCCR1_RPL\t\t0x01\t/* Enables RPLSET and RPLVAL# pins */\n#define\tCCR1_SMI\t\t0x02\t/* Enables SMM pins */\n#define\tCCR1_SMAC\t\t0x04\t/* System management memory access */\n#define\tCCR1_MMAC\t\t0x08\t/* Main memory access */\n#define\tCCR1_NO_LOCK\t0x10\t/* Negate LOCK# */\n#define\tCCR1_SM3\t\t0x80\t/* SMM address space address region 3 */\n\n#define\tCCR2\t\t\t0xc2\n#define\tCCR2_WB\t\t\t0x02\t/* Enables WB cache interface pins */\n#define\tCCR2_SADS\t\t0x02\t/* Slow ADS */\n#define\tCCR2_LOCK_NW\t0x04\t/* LOCK NW Bit */\n#define\tCCR2_SUSP_HLT\t0x08\t/* Suspend on HALT */\n#define\tCCR2_WT1\t\t0x10\t/* WT region 1 */\n#define\tCCR2_WPR1\t\t0x10\t/* Write-protect region 1 */\n#define\tCCR2_BARB\t\t0x20\t/* Flushes write-back cache when entering\n\t\t\t\t\t\t\t\t   hold state. */\n#define\tCCR2_BWRT\t\t0x40\t/* Enables burst write cycles */\n#define\tCCR2_USE_SUSP\t0x80\t/* Enables suspend pins */\n\n#define\tCCR3\t\t\t0xc3\n#define\tCCR3_SMILOCK\t0x01\t/* SMM register lock */\n#define\tCCR3_NMI\t\t0x02\t/* Enables NMI during SMM */\n#define\tCCR3_LINBRST\t0x04\t/* Linear address burst cycles */\n#define\tCCR3_SMMMODE\t0x08\t/* SMM Mode */\n#define\tCCR3_MAPEN0\t\t0x10\t/* Enables Map0 */\n#define\tCCR3_MAPEN1\t\t0x20\t/* Enables Map1 */\n#define\tCCR3_MAPEN2\t\t0x40\t/* Enables Map2 */\n#define\tCCR3_MAPEN3\t\t0x80\t/* Enables Map3 */\n\n#define\tCCR4\t\t\t0xe8\n#define\tCCR4_IOMASK\t\t0x07\n#define\tCCR4_MEM\t\t0x08\t/* Enables momory bypassing */\n#define\tCCR4_DTE\t\t0x10\t/* Enables directory table entry cache */\n#define\tCCR4_FASTFPE\t0x20\t/* Fast FPU exception */\n#define\tCCR4_CPUID\t\t0x80\t/* Enables CPUID instruction */\n\n#define\tCCR5\t\t\t0xe9\n#define\tCCR5_WT_ALLOC\t0x01\t/* Write-through allocate */\n#define\tCCR5_SLOP\t\t0x02\t/* LOOP instruction slowed down */\n#define\tCCR5_LBR1\t\t0x10\t/* Local bus region 1 */\n#define\tCCR5_ARREN\t\t0x20\t/* Enables ARR region */\n\n#define\tCCR6\t\t\t0xea\n\n#define\tCCR7\t\t\t0xeb\n\n/* Performance Control Register (5x86 only). */\n#define\tPCR0\t\t\t0x20\n#define\tPCR0_RSTK\t\t0x01\t/* Enables return stack */\n#define\tPCR0_BTB\t\t0x02\t/* Enables branch target buffer */\n#define\tPCR0_LOOP\t\t0x04\t/* Enables loop */\n#define\tPCR0_AIS\t\t0x08\t/* Enables all instrcutions stalled to\n\t\t\t\t\t\t\t\t   serialize pipe. */\n#define\tPCR0_MLR\t\t0x10\t/* Enables reordering of misaligned loads */\n#define\tPCR0_BTBRT\t\t0x40\t/* Enables BTB test register. */\n#define\tPCR0_LSSER\t\t0x80\t/* Disable reorder */\n\n/* Device Identification Registers */\n#define\tDIR0\t\t\t0xfe\n#define\tDIR1\t\t\t0xff\n\n/*\n * Machine Check register constants.\n */\n#define\tMCG_CAP_COUNT\t\t0x000000ff\n#define\tMCG_CAP_CTL_P\t\t0x00000100\n#define\tMCG_CAP_EXT_P\t\t0x00000200\n#define\tMCG_CAP_CMCI_P\t\t0x00000400\n#define\tMCG_CAP_TES_P\t\t0x00000800\n#define\tMCG_CAP_EXT_CNT\t\t0x00ff0000\n#define\tMCG_CAP_SER_P\t\t0x01000000\n#define\tMCG_STATUS_RIPV\t\t0x00000001\n#define\tMCG_STATUS_EIPV\t\t0x00000002\n#define\tMCG_STATUS_MCIP\t\t0x00000004\n#define\tMCG_CTL_ENABLE\t\t0xffffffffffffffff\n#define\tMCG_CTL_DISABLE\t\t0x0000000000000000\n#define\tMSR_MC_CTL(x)\t\t(MSR_MC0_CTL + (x) * 4)\n#define\tMSR_MC_STATUS(x)\t(MSR_MC0_STATUS + (x) * 4)\n#define\tMSR_MC_ADDR(x)\t\t(MSR_MC0_ADDR + (x) * 4)\n#define\tMSR_MC_MISC(x)\t\t(MSR_MC0_MISC + (x) * 4)\n#define\tMSR_MC_CTL2(x)\t\t(MSR_MC0_CTL2 + (x))\t/* If MCG_CAP_CMCI_P */\n#define\tMC_STATUS_MCA_ERROR\t0x000000000000ffff\n#define\tMC_STATUS_MODEL_ERROR\t0x00000000ffff0000\n#define\tMC_STATUS_OTHER_INFO\t0x01ffffff00000000\n#define\tMC_STATUS_COR_COUNT\t0x001fffc000000000\t/* If MCG_CAP_CMCI_P */\n#define\tMC_STATUS_TES_STATUS\t0x0060000000000000\t/* If MCG_CAP_TES_P */\n#define\tMC_STATUS_AR\t\t0x0080000000000000\t/* If MCG_CAP_TES_P */\n#define\tMC_STATUS_S\t\t0x0100000000000000\t/* If MCG_CAP_TES_P */\n#define\tMC_STATUS_PCC\t\t0x0200000000000000\n#define\tMC_STATUS_ADDRV\t\t0x0400000000000000\n#define\tMC_STATUS_MISCV\t\t0x0800000000000000\n#define\tMC_STATUS_EN\t\t0x1000000000000000\n#define\tMC_STATUS_UC\t\t0x2000000000000000\n#define\tMC_STATUS_OVER\t\t0x4000000000000000\n#define\tMC_STATUS_VAL\t\t0x8000000000000000\n#define\tMC_MISC_RA_LSB\t\t0x000000000000003f\t/* If MCG_CAP_SER_P */\n#define\tMC_MISC_ADDRESS_MODE\t0x00000000000001c0\t/* If MCG_CAP_SER_P */\n#define\tMC_CTL2_THRESHOLD\t0x0000000000007fff\n#define\tMC_CTL2_CMCI_EN\t\t0x0000000040000000\n\n/*\n * The following four 3-byte registers control the non-cacheable regions.\n * These registers must be written as three separate bytes.\n *\n * NCRx+0: A31-A24 of starting address\n * NCRx+1: A23-A16 of starting address\n * NCRx+2: A15-A12 of starting address | NCR_SIZE_xx.\n *\n * The non-cacheable region's starting address must be aligned to the\n * size indicated by the NCR_SIZE_xx field.\n */\n#define\tNCR1\t0xc4\n#define\tNCR2\t0xc7\n#define\tNCR3\t0xca\n#define\tNCR4\t0xcd\n\n#define\tNCR_SIZE_0K\t0\n#define\tNCR_SIZE_4K\t1\n#define\tNCR_SIZE_8K\t2\n#define\tNCR_SIZE_16K\t3\n#define\tNCR_SIZE_32K\t4\n#define\tNCR_SIZE_64K\t5\n#define\tNCR_SIZE_128K\t6\n#define\tNCR_SIZE_256K\t7\n#define\tNCR_SIZE_512K\t8\n#define\tNCR_SIZE_1M\t9\n#define\tNCR_SIZE_2M\t10\n#define\tNCR_SIZE_4M\t11\n#define\tNCR_SIZE_8M\t12\n#define\tNCR_SIZE_16M\t13\n#define\tNCR_SIZE_32M\t14\n#define\tNCR_SIZE_4G\t15\n\n/*\n * The address region registers are used to specify the location and\n * size for the eight address regions.\n *\n * ARRx + 0: A31-A24 of start address\n * ARRx + 1: A23-A16 of start address\n * ARRx + 2: A15-A12 of start address | ARR_SIZE_xx\n */\n#define\tARR0\t0xc4\n#define\tARR1\t0xc7\n#define\tARR2\t0xca\n#define\tARR3\t0xcd\n#define\tARR4\t0xd0\n#define\tARR5\t0xd3\n#define\tARR6\t0xd6\n#define\tARR7\t0xd9\n\n#define\tARR_SIZE_0K\t\t0\n#define\tARR_SIZE_4K\t\t1\n#define\tARR_SIZE_8K\t\t2\n#define\tARR_SIZE_16K\t3\n#define\tARR_SIZE_32K\t4\n#define\tARR_SIZE_64K\t5\n#define\tARR_SIZE_128K\t6\n#define\tARR_SIZE_256K\t7\n#define\tARR_SIZE_512K\t8\n#define\tARR_SIZE_1M\t\t9\n#define\tARR_SIZE_2M\t\t10\n#define\tARR_SIZE_4M\t\t11\n#define\tARR_SIZE_8M\t\t12\n#define\tARR_SIZE_16M\t13\n#define\tARR_SIZE_32M\t14\n#define\tARR_SIZE_4G\t\t15\n\n/*\n * The region control registers specify the attributes associated with\n * the ARRx addres regions.\n */\n#define\tRCR0\t0xdc\n#define\tRCR1\t0xdd\n#define\tRCR2\t0xde\n#define\tRCR3\t0xdf\n#define\tRCR4\t0xe0\n#define\tRCR5\t0xe1\n#define\tRCR6\t0xe2\n#define\tRCR7\t0xe3\n\n#define\tRCR_RCD\t0x01\t/* Disables caching for ARRx (x = 0-6). */\n#define\tRCR_RCE\t0x01\t/* Enables caching for ARR7. */\n#define\tRCR_WWO\t0x02\t/* Weak write ordering. */\n#define\tRCR_WL\t0x04\t/* Weak locking. */\n#define\tRCR_WG\t0x08\t/* Write gathering. */\n#define\tRCR_WT\t0x10\t/* Write-through. */\n#define\tRCR_NLB\t0x20\t/* LBA# pin is not asserted. */\n\n/* AMD Write Allocate Top-Of-Memory and Control Register */\n#define\tAMD_WT_ALLOC_TME\t0x40000\t/* top-of-memory enable */\n#define\tAMD_WT_ALLOC_PRE\t0x20000\t/* programmable range enable */\n#define\tAMD_WT_ALLOC_FRE\t0x10000\t/* fixed (A0000-FFFFF) range enable */\n\n/* AMD64 MSR's */\n#define\tMSR_EFER\t0xc0000080\t/* extended features */\n#define\tMSR_STAR\t0xc0000081\t/* legacy mode SYSCALL target/cs/ss */\n#define\tMSR_LSTAR\t0xc0000082\t/* long mode SYSCALL target rip */\n#define\tMSR_CSTAR\t0xc0000083\t/* compat mode SYSCALL target rip */\n#define\tMSR_SF_MASK\t0xc0000084\t/* syscall flags mask */\n#define\tMSR_FSBASE\t0xc0000100\t/* base address of the %fs \"segment\" */\n#define\tMSR_GSBASE\t0xc0000101\t/* base address of the %gs \"segment\" */\n#define\tMSR_KGSBASE\t0xc0000102\t/* base address of the kernel %gs */\n#define\tMSR_PERFEVSEL0\t0xc0010000\n#define\tMSR_PERFEVSEL1\t0xc0010001\n#define\tMSR_PERFEVSEL2\t0xc0010002\n#define\tMSR_PERFEVSEL3\t0xc0010003\n#define\tMSR_K7_PERFCTR0\t0xc0010004\n#define\tMSR_K7_PERFCTR1\t0xc0010005\n#define\tMSR_K7_PERFCTR2\t0xc0010006\n#define\tMSR_K7_PERFCTR3\t0xc0010007\n#define\tMSR_SYSCFG\t0xc0010010\n#define\tMSR_HWCR\t0xc0010015\n#define\tMSR_IORRBASE0\t0xc0010016\n#define\tMSR_IORRMASK0\t0xc0010017\n#define\tMSR_IORRBASE1\t0xc0010018\n#define\tMSR_IORRMASK1\t0xc0010019\n#define\tMSR_TOP_MEM\t0xc001001a\t/* boundary for ram below 4G */\n#define\tMSR_TOP_MEM2\t0xc001001d\t/* boundary for ram above 4G */\n#define\tMSR_NB_CFG1\t0xc001001f\t/* NB configuration 1 */\n#define\tMSR_P_STATE_LIMIT 0xc0010061\t/* P-state Current Limit Register */\n#define\tMSR_P_STATE_CONTROL 0xc0010062\t/* P-state Control Register */\n#define\tMSR_P_STATE_STATUS 0xc0010063\t/* P-state Status Register */\n#define\tMSR_P_STATE_CONFIG(n) (0xc0010064 + (n)) /* P-state Config */\n#define\tMSR_SMM_ADDR\t0xc0010112\t/* SMM TSEG base address */\n#define\tMSR_SMM_MASK\t0xc0010113\t/* SMM TSEG address mask */\n#define\tMSR_IC_CFG\t0xc0011021\t/* Instruction Cache Configuration */\n#define\tMSR_K8_UCODE_UPDATE\t0xc0010020\t/* update microcode */\n#define\tMSR_MC0_CTL_MASK\t0xc0010044\n#define\tMSR_VM_CR\t\t0xc0010114 /* SVM: feature control */\n#define\tMSR_VM_HSAVE_PA\t\t0xc0010117 /* SVM: host save area address */\n\n/* MSR_VM_CR related */\n#define\tVM_CR_SVMDIS\t\t0x10\t/* SVM: disabled by BIOS */\n\n/* VIA ACE crypto featureset: for via_feature_rng */\n#define\tVIA_HAS_RNG\t\t1\t/* cpu has RNG */\n\n/* VIA ACE crypto featureset: for via_feature_xcrypt */\n#define\tVIA_HAS_AES\t\t1\t/* cpu has AES */\n#define\tVIA_HAS_SHA\t\t2\t/* cpu has SHA1 & SHA256 */\n#define\tVIA_HAS_MM\t\t4\t/* cpu has RSA instructions */\n#define\tVIA_HAS_AESCTR\t\t8\t/* cpu has AES-CTR instructions */\n\n/* Centaur Extended Feature flags */\n#define\tVIA_CPUID_HAS_RNG\t0x000004\n#define\tVIA_CPUID_DO_RNG\t0x000008\n#define\tVIA_CPUID_HAS_ACE\t0x000040\n#define\tVIA_CPUID_DO_ACE\t0x000080\n#define\tVIA_CPUID_HAS_ACE2\t0x000100\n#define\tVIA_CPUID_DO_ACE2\t0x000200\n#define\tVIA_CPUID_HAS_PHE\t0x000400\n#define\tVIA_CPUID_DO_PHE\t0x000800\n#define\tVIA_CPUID_HAS_PMM\t0x001000\n#define\tVIA_CPUID_DO_PMM\t0x002000\n\n/* VIA ACE xcrypt-* instruction context control options */\n#define\tVIA_CRYPT_CWLO_ROUND_M\t\t0x0000000f\n#define\tVIA_CRYPT_CWLO_ALG_M\t\t0x00000070\n#define\tVIA_CRYPT_CWLO_ALG_AES\t\t0x00000000\n#define\tVIA_CRYPT_CWLO_KEYGEN_M\t\t0x00000080\n#define\tVIA_CRYPT_CWLO_KEYGEN_HW\t0x00000000\n#define\tVIA_CRYPT_CWLO_KEYGEN_SW\t0x00000080\n#define\tVIA_CRYPT_CWLO_NORMAL\t\t0x00000000\n#define\tVIA_CRYPT_CWLO_INTERMEDIATE\t0x00000100\n#define\tVIA_CRYPT_CWLO_ENCRYPT\t\t0x00000000\n#define\tVIA_CRYPT_CWLO_DECRYPT\t\t0x00000200\n#define\tVIA_CRYPT_CWLO_KEY128\t\t0x0000000a\t/* 128bit, 10 rds */\n#define\tVIA_CRYPT_CWLO_KEY192\t\t0x0000040c\t/* 192bit, 12 rds */\n#define\tVIA_CRYPT_CWLO_KEY256\t\t0x0000080e\t/* 256bit, 15 rds */\n"
  },
  {
    "path": "include/xhyve/support/timerreg.h",
    "content": "/*-\n * Copyright (C) 2005 TAKAHASHI Yoshihiro. All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * The outputs of the three timers are connected as follows:\n *\n *\t timer 0 -> irq 0\n *\t timer 1 -> dma chan 0 (for dram refresh)\n * \t timer 2 -> speaker (via keyboard controller)\n *\n * Timer 0 is used to call hardclock.\n * Timer 2 is used to generate console beeps.\n */\n\n#pragma once\n\n#include <xhyve/support/i8253reg.h>\n\n#define\tIO_TIMER1\t0x40\t\t/* 8253 Timer #1 */\n#define\tTIMER_CNTR0\t(IO_TIMER1 + TIMER_REG_CNTR0)\n#define\tTIMER_CNTR1\t(IO_TIMER1 + TIMER_REG_CNTR1)\n#define\tTIMER_CNTR2\t(IO_TIMER1 + TIMER_REG_CNTR2)\n#define\tTIMER_MODE\t(IO_TIMER1 + TIMER_REG_MODE)\n"
  },
  {
    "path": "include/xhyve/support/tree.h",
    "content": "/*\t$NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $\t*/\n/*\t$OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $\t*/\n/* $FreeBSD: src/sys/sys/tree.h,v 1.7 2007/12/28 07:03:26 jasone Exp $ */\n\n/*-\n * Copyright 2002 Niels Provos <provos@citi.umich.edu>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#pragma once\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\n/*\n * This file defines data structures for different types of trees:\n * splay trees and red-black trees.\n *\n * A splay tree is a self-organizing data structure.  Every operation\n * on the tree causes a splay to happen.  The splay moves the requested\n * node to the root of the tree and partly rebalances it.\n *\n * This has the benefit that request locality causes faster lookups as\n * the requested nodes move to the top of the tree.  On the other hand,\n * every lookup causes memory writes.\n *\n * The Balance Theorem bounds the total access time for m operations\n * and n inserts on an initially empty tree as O((m + n)lg n).  The\n * amortized cost for a sequence of m accesses to a splay tree is O(lg n);\n *\n * A red-black tree is a binary search tree with the node color as an\n * extra attribute.  It fulfills a set of conditions:\n *\t- every search path from the root to a leaf consists of the\n *\t  same number of black nodes,\n *\t- each red node (except for the root) has a black parent,\n *\t- each leaf node is black.\n *\n * Every operation on a red-black tree is bounded as O(lg n).\n * The maximum height of a red-black tree is 2lg (n+1).\n */\n\n#define SPLAY_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *sph_root; /* root of the tree */\t\t\t\\\n}\n\n#define SPLAY_INITIALIZER(root)\t\t\t\t\t\t\\\n\t{ NULL }\n\n#define SPLAY_INIT(root) do {\t\t\t\t\t\t\\\n\t(root)->sph_root = NULL;\t\t\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define SPLAY_ENTRY(type)\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *spe_left; /* left element */\t\t\t\\\n\tstruct type *spe_right; /* right element */\t\t\t\\\n}\n\n#define SPLAY_LEFT(elm, field)\t\t(elm)->field.spe_left\n#define SPLAY_RIGHT(elm, field)\t\t(elm)->field.spe_right\n#define SPLAY_ROOT(head)\t\t(head)->sph_root\n#define SPLAY_EMPTY(head)\t\t(SPLAY_ROOT(head) == NULL)\n\n/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */\n#define SPLAY_ROTATE_RIGHT(head, tmp, field) do {\t\t\t\\\n\tSPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field);\t\\\n\tSPLAY_RIGHT(tmp, field) = (head)->sph_root;\t\t\t\\\n\t(head)->sph_root = tmp;\t\t\t\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define SPLAY_ROTATE_LEFT(head, tmp, field) do {\t\t\t\\\n\tSPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field);\t\\\n\tSPLAY_LEFT(tmp, field) = (head)->sph_root;\t\t\t\\\n\t(head)->sph_root = tmp;\t\t\t\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define SPLAY_LINKLEFT(head, tmp, field) do {\t\t\t\t\\\n\tSPLAY_LEFT(tmp, field) = (head)->sph_root;\t\t\t\\\n\ttmp = (head)->sph_root;\t\t\t\t\t\t\\\n\t(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define SPLAY_LINKRIGHT(head, tmp, field) do {\t\t\t\t\\\n\tSPLAY_RIGHT(tmp, field) = (head)->sph_root;\t\t\t\\\n\ttmp = (head)->sph_root;\t\t\t\t\t\t\\\n\t(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define SPLAY_ASSEMBLE(head, node, left, right, field) do {\t\t\\\n\tSPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field);\t\\\n\tSPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\\\n\tSPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field);\t\\\n\tSPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field);\t\\\n} while (/*CONSTCOND*/ 0)\n\n/* Generates prototypes and inline functions */\n\n#define SPLAY_PROTOTYPE(name, type, field, cmp)\t\t\t\t\\\nvoid name##_SPLAY(struct name *, struct type *);\t\t\t\\\nvoid name##_SPLAY_MINMAX(struct name *, int);\t\t\t\t\\\nstruct type *name##_SPLAY_INSERT(struct name *, struct type *);\t\t\\\nstruct type *name##_SPLAY_REMOVE(struct name *, struct type *);\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* Finds the node with the same key as elm */\t\t\t\t\\\nstatic __inline struct type *\t\t\t\t\t\t\\\nname##_SPLAY_FIND(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tif (SPLAY_EMPTY(head))\t\t\t\t\t\t\\\n\t\treturn(NULL);\t\t\t\t\t\t\\\n\tname##_SPLAY(head, elm);\t\t\t\t\t\\\n\tif ((cmp)(elm, (head)->sph_root) == 0)\t\t\t\t\\\n\t\treturn (head->sph_root);\t\t\t\t\\\n\treturn (NULL);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nstatic __inline struct type *\t\t\t\t\t\t\\\nname##_SPLAY_NEXT(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tname##_SPLAY(head, elm);\t\t\t\t\t\\\n\tif (SPLAY_RIGHT(elm, field) != NULL) {\t\t\t\t\\\n\t\telm = SPLAY_RIGHT(elm, field);\t\t\t\t\\\n\t\twhile (SPLAY_LEFT(elm, field) != NULL) {\t\t\\\n\t\t\telm = SPLAY_LEFT(elm, field);\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t} else\t\t\t\t\t\t\t\t\\\n\t\telm = NULL;\t\t\t\t\t\t\\\n\treturn (elm);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nstatic __inline struct type *\t\t\t\t\t\t\\\nname##_SPLAY_MIN_MAX(struct name *head, int val)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tname##_SPLAY_MINMAX(head, val);\t\t\t\t\t\\\n        return (SPLAY_ROOT(head));\t\t\t\t\t\\\n}\n\n/* Main splay operation.\n * Moves node close to the key of elm to top\n */\n#define SPLAY_GENERATE(name, type, field, cmp)\t\t\t\t\\\nstruct type *\t\t\t\t\t\t\t\t\\\nname##_SPLAY_INSERT(struct name *head, struct type *elm)\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n    if (SPLAY_EMPTY(head)) {\t\t\t\t\t\t\\\n\t    SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL;\t\\\n    } else {\t\t\t\t\t\t\t\t\\\n\t    int __comp;\t\t\t\t\t\t\t\\\n\t    name##_SPLAY(head, elm);\t\t\t\t\t\\\n\t    __comp = (cmp)(elm, (head)->sph_root);\t\t\t\\\n\t    if(__comp < 0) {\t\t\t\t\t\t\\\n\t\t    SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\\\n\t\t    SPLAY_RIGHT(elm, field) = (head)->sph_root;\t\t\\\n\t\t    SPLAY_LEFT((head)->sph_root, field) = NULL;\t\t\\\n\t    } else if (__comp > 0) {\t\t\t\t\t\\\n\t\t    SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\\\n\t\t    SPLAY_LEFT(elm, field) = (head)->sph_root;\t\t\\\n\t\t    SPLAY_RIGHT((head)->sph_root, field) = NULL;\t\\\n\t    } else\t\t\t\t\t\t\t\\\n\t\t    return ((head)->sph_root);\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\t\\\n    (head)->sph_root = (elm);\t\t\t\t\t\t\\\n    return (NULL);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nstruct type *\t\t\t\t\t\t\t\t\\\nname##_SPLAY_REMOVE(struct name *head, struct type *elm)\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *__tmp;\t\t\t\t\t\t\\\n\tif (SPLAY_EMPTY(head))\t\t\t\t\t\t\\\n\t\treturn (NULL);\t\t\t\t\t\t\\\n\tname##_SPLAY(head, elm);\t\t\t\t\t\\\n\tif ((cmp)(elm, (head)->sph_root) == 0) {\t\t\t\\\n\t\tif (SPLAY_LEFT((head)->sph_root, field) == NULL) {\t\\\n\t\t\t(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\\\n\t\t} else {\t\t\t\t\t\t\\\n\t\t\t__tmp = SPLAY_RIGHT((head)->sph_root, field);\t\\\n\t\t\t(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\\\n\t\t\tname##_SPLAY(head, elm);\t\t\t\\\n\t\t\tSPLAY_RIGHT((head)->sph_root, field) = __tmp;\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t\treturn (elm);\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\treturn (NULL);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nvoid\t\t\t\t\t\t\t\t\t\\\nname##_SPLAY(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type __node, *__left, *__right, *__tmp;\t\t\t\\\n\tint __comp;\t\t\t\t\t\t\t\\\n\\\n\tSPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\\\n\t__left = __right = &__node;\t\t\t\t\t\\\n\\\n\twhile ((__comp = (cmp)(elm, (head)->sph_root)) != 0) {\t\t\\\n\t\tif (__comp < 0) {\t\t\t\t\t\\\n\t\t\t__tmp = SPLAY_LEFT((head)->sph_root, field);\t\\\n\t\t\tif (__tmp == NULL)\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\\\n\t\t\tif ((cmp)(elm, __tmp) < 0){\t\t\t\\\n\t\t\t\tSPLAY_ROTATE_RIGHT(head, __tmp, field);\t\\\n\t\t\t\tif (SPLAY_LEFT((head)->sph_root, field) == NULL)\\\n\t\t\t\t\tbreak;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tSPLAY_LINKLEFT(head, __right, field);\t\t\\\n\t\t} else if (__comp > 0) {\t\t\t\t\\\n\t\t\t__tmp = SPLAY_RIGHT((head)->sph_root, field);\t\\\n\t\t\tif (__tmp == NULL)\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\\\n\t\t\tif ((cmp)(elm, __tmp) > 0){\t\t\t\\\n\t\t\t\tSPLAY_ROTATE_LEFT(head, __tmp, field);\t\\\n\t\t\t\tif (SPLAY_RIGHT((head)->sph_root, field) == NULL)\\\n\t\t\t\t\tbreak;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tSPLAY_LINKRIGHT(head, __left, field);\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tSPLAY_ASSEMBLE(head, &__node, __left, __right, field);\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* Splay with either the minimum or the maximum element\t\t\t\\\n * Used to find minimum or maximum element in tree.\t\t\t\\\n */\t\t\t\t\t\t\t\t\t\\\nvoid name##_SPLAY_MINMAX(struct name *head, int __comp) \\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type __node, *__left, *__right, *__tmp;\t\t\t\\\n\\\n\tSPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\\\n\t__left = __right = &__node;\t\t\t\t\t\\\n\\\n\twhile (1) {\t\t\t\t\t\t\t\\\n\t\tif (__comp < 0) {\t\t\t\t\t\\\n\t\t\t__tmp = SPLAY_LEFT((head)->sph_root, field);\t\\\n\t\t\tif (__tmp == NULL)\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\\\n\t\t\tif (__comp < 0){\t\t\t\t\\\n\t\t\t\tSPLAY_ROTATE_RIGHT(head, __tmp, field);\t\\\n\t\t\t\tif (SPLAY_LEFT((head)->sph_root, field) == NULL)\\\n\t\t\t\t\tbreak;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tSPLAY_LINKLEFT(head, __right, field);\t\t\\\n\t\t} else if (__comp > 0) {\t\t\t\t\\\n\t\t\t__tmp = SPLAY_RIGHT((head)->sph_root, field);\t\\\n\t\t\tif (__tmp == NULL)\t\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\\\n\t\t\tif (__comp > 0) {\t\t\t\t\\\n\t\t\t\tSPLAY_ROTATE_LEFT(head, __tmp, field);\t\\\n\t\t\t\tif (SPLAY_RIGHT((head)->sph_root, field) == NULL)\\\n\t\t\t\t\tbreak;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tSPLAY_LINKRIGHT(head, __left, field);\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tSPLAY_ASSEMBLE(head, &__node, __left, __right, field);\t\t\\\n}\n\n#define SPLAY_NEGINF\t-1\n#define SPLAY_INF\t1\n\n#define SPLAY_INSERT(name, x, y)\tname##_SPLAY_INSERT(x, y)\n#define SPLAY_REMOVE(name, x, y)\tname##_SPLAY_REMOVE(x, y)\n#define SPLAY_FIND(name, x, y)\t\tname##_SPLAY_FIND(x, y)\n#define SPLAY_NEXT(name, x, y)\t\tname##_SPLAY_NEXT(x, y)\n#define SPLAY_MIN(name, x)\t\t(SPLAY_EMPTY(x) ? NULL\t\\\n\t\t\t\t\t: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))\n#define SPLAY_MAX(name, x)\t\t(SPLAY_EMPTY(x) ? NULL\t\\\n\t\t\t\t\t: name##_SPLAY_MIN_MAX(x, SPLAY_INF))\n\n#define SPLAY_FOREACH(x, name, head)\t\t\t\t\t\\\n\tfor ((x) = SPLAY_MIN(name, head);\t\t\t\t\\\n\t     (x) != NULL;\t\t\t\t\t\t\\\n\t     (x) = SPLAY_NEXT(name, head, x))\n\n/* Macros that define a red-black tree */\n#define RB_HEAD(name, type)\t\t\t\t\t\t\\\nstruct name {\t\t\t\t\t\t\t\t\\\n\tstruct type *rbh_root; /* root of the tree */\t\t\t\\\n}\n\n#define RB_INITIALIZER(root)\t\t\t\t\t\t\\\n\t{ NULL }\n\n#define RB_INIT(root) do {\t\t\t\t\t\t\\\n\t(root)->rbh_root = NULL;\t\t\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n/*\n * Undef for Linux\n */\n#undef\tRB_BLACK\n#undef\tRB_RED\n#undef\tRB_ROOT\n\n#define RB_BLACK\t0\n#define RB_RED\t\t1\n#define RB_ENTRY(type)\t\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\tstruct type *rbe_left;\t\t/* left element */\t\t\\\n\tstruct type *rbe_right;\t\t/* right element */\t\t\\\n\tstruct type *rbe_parent;\t/* parent element */\t\t\\\n\tint rbe_color;\t\t\t/* node color */\t\t\\\n}\n\n#define RB_LEFT(elm, field)\t\t(elm)->field.rbe_left\n#define RB_RIGHT(elm, field)\t\t(elm)->field.rbe_right\n#define RB_PARENT(elm, field)\t\t(elm)->field.rbe_parent\n#define RB_COLOR(elm, field)\t\t(elm)->field.rbe_color\n#define RB_ROOT(head)\t\t\t(head)->rbh_root\n#define RB_EMPTY(head)\t\t\t(RB_ROOT(head) == NULL)\n\n#define RB_SET(elm, parent, field) do {\t\t\t\t\t\\\n\tRB_PARENT(elm, field) = parent;\t\t\t\t\t\\\n\tRB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL;\t\t\\\n\tRB_COLOR(elm, field) = RB_RED;\t\t\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define RB_SET_BLACKRED(black, red, field) do {\t\t\t\t\\\n\tRB_COLOR(black, field) = RB_BLACK;\t\t\t\t\\\n\tRB_COLOR(red, field) = RB_RED;\t\t\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#ifndef RB_AUGMENT\n#define RB_AUGMENT(x)\tdo {} while (0)\n#endif\n\n#define RB_ROTATE_LEFT(head, elm, tmp, field) do {\t\t\t\\\n\t(tmp) = RB_RIGHT(elm, field);\t\t\t\t\t\\\n\tif ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) {\t\\\n\t\tRB_PARENT(RB_LEFT(tmp, field), field) = (elm);\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tRB_AUGMENT(elm);\t\t\t\t\t\t\\\n\tif ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) {\t\\\n\t\tif ((elm) == RB_LEFT(RB_PARENT(elm, field), field))\t\\\n\t\t\tRB_LEFT(RB_PARENT(elm, field), field) = (tmp);\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\tRB_RIGHT(RB_PARENT(elm, field), field) = (tmp);\t\\\n\t} else\t\t\t\t\t\t\t\t\\\n\t\t(head)->rbh_root = (tmp);\t\t\t\t\\\n\tRB_LEFT(tmp, field) = (elm);\t\t\t\t\t\\\n\tRB_PARENT(elm, field) = (tmp);\t\t\t\t\t\\\n\tRB_AUGMENT(tmp);\t\t\t\t\t\t\\\n\tif ((RB_PARENT(tmp, field)))\t\t\t\t\t\\\n\t\tRB_AUGMENT(RB_PARENT(tmp, field));\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n#define RB_ROTATE_RIGHT(head, elm, tmp, field) do {\t\t\t\\\n\t(tmp) = RB_LEFT(elm, field);\t\t\t\t\t\\\n\tif ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) {\t\\\n\t\tRB_PARENT(RB_RIGHT(tmp, field), field) = (elm);\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tRB_AUGMENT(elm);\t\t\t\t\t\t\\\n\tif ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) {\t\\\n\t\tif ((elm) == RB_LEFT(RB_PARENT(elm, field), field))\t\\\n\t\t\tRB_LEFT(RB_PARENT(elm, field), field) = (tmp);\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\tRB_RIGHT(RB_PARENT(elm, field), field) = (tmp);\t\\\n\t} else\t\t\t\t\t\t\t\t\\\n\t\t(head)->rbh_root = (tmp);\t\t\t\t\\\n\tRB_RIGHT(tmp, field) = (elm);\t\t\t\t\t\\\n\tRB_PARENT(elm, field) = (tmp);\t\t\t\t\t\\\n\tRB_AUGMENT(tmp);\t\t\t\t\t\t\\\n\tif ((RB_PARENT(tmp, field)))\t\t\t\t\t\\\n\t\tRB_AUGMENT(RB_PARENT(tmp, field));\t\t\t\\\n} while (/*CONSTCOND*/ 0)\n\n/* Generates prototypes and inline functions */\n#define\tRB_PROTOTYPE(name, type, field, cmp) \\\n\tRB_PROTOTYPE_INTERNAL(name, type, field, cmp,)\n#define\tRB_PROTOTYPE_STATIC(name, type, field, cmp) \\\n\tRB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)\n#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \\\nattr void name##_RB_INSERT_COLOR(struct name *, struct type *); \\\nattr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *); \\\nattr struct type *name##_RB_REMOVE(struct name *, struct type *); \\\nattr struct type *name##_RB_INSERT(struct name *, struct type *); \\\nattr struct type *name##_RB_FIND(struct name *, struct type *); \\\nattr struct type *name##_RB_NFIND(struct name *, struct type *); \\\nattr struct type *name##_RB_NEXT(struct type *); \\\nattr struct type *name##_RB_PREV(struct type *); \\\nattr struct type *name##_RB_MINMAX(struct name *, int) \\\n\n/* Main rb operation.\n * Moves node close to the key of elm to top\n */\n#define\tRB_GENERATE(name, type, field, cmp)\t\t\t\t\\\n\tRB_GENERATE_INTERNAL(name, type, field, cmp,)\n#define\tRB_GENERATE_STATIC(name, type, field, cmp)\t\t\t\\\n\tRB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)\n#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr)\t\t\\\nattr void\t\t\t\t\t\t\t\t\\\nname##_RB_INSERT_COLOR(struct name *head, struct type *elm)\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *parent, *gparent, *tmp;\t\t\t\t\\\n\twhile ((parent = RB_PARENT(elm, field)) != NULL &&\t\t\\\n\t    RB_COLOR(parent, field) == RB_RED) {\t\t\t\\\n\t\tgparent = RB_PARENT(parent, field);\t\t\t\\\n\t\tif (parent == RB_LEFT(gparent, field)) {\t\t\\\n\t\t\ttmp = RB_RIGHT(gparent, field);\t\t\t\\\n\t\t\tif (tmp && RB_COLOR(tmp, field) == RB_RED) {\t\\\n\t\t\t\tRB_COLOR(tmp, field) = RB_BLACK;\t\\\n\t\t\t\tRB_SET_BLACKRED(parent, gparent, field);\\\n\t\t\t\telm = gparent;\t\t\t\t\\\n\t\t\t\tcontinue;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tif (RB_RIGHT(parent, field) == elm) {\t\t\\\n\t\t\t\tRB_ROTATE_LEFT(head, parent, tmp, field);\\\n\t\t\t\ttmp = parent;\t\t\t\t\\\n\t\t\t\tparent = elm;\t\t\t\t\\\n\t\t\t\telm = tmp;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tRB_SET_BLACKRED(parent, gparent, field);\t\\\n\t\t\tRB_ROTATE_RIGHT(head, gparent, tmp, field);\t\\\n\t\t} else {\t\t\t\t\t\t\\\n\t\t\ttmp = RB_LEFT(gparent, field);\t\t\t\\\n\t\t\tif (tmp && RB_COLOR(tmp, field) == RB_RED) {\t\\\n\t\t\t\tRB_COLOR(tmp, field) = RB_BLACK;\t\\\n\t\t\t\tRB_SET_BLACKRED(parent, gparent, field);\\\n\t\t\t\telm = gparent;\t\t\t\t\\\n\t\t\t\tcontinue;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tif (RB_LEFT(parent, field) == elm) {\t\t\\\n\t\t\t\tRB_ROTATE_RIGHT(head, parent, tmp, field);\\\n\t\t\t\ttmp = parent;\t\t\t\t\\\n\t\t\t\tparent = elm;\t\t\t\t\\\n\t\t\t\telm = tmp;\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tRB_SET_BLACKRED(parent, gparent, field);\t\\\n\t\t\tRB_ROTATE_LEFT(head, gparent, tmp, field);\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tRB_COLOR(head->rbh_root, field) = RB_BLACK;\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nattr void\t\t\t\t\t\t\t\t\\\nname##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *tmp;\t\t\t\t\t\t\\\n\twhile ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) &&\t\\\n\t    elm != RB_ROOT(head)) {\t\t\t\t\t\\\n\t\tif (RB_LEFT(parent, field) == elm) {\t\t\t\\\n\t\t\ttmp = RB_RIGHT(parent, field);\t\t\t\\\n\t\t\tif (RB_COLOR(tmp, field) == RB_RED) {\t\t\\\n\t\t\t\tRB_SET_BLACKRED(tmp, parent, field);\t\\\n\t\t\t\tRB_ROTATE_LEFT(head, parent, tmp, field);\\\n\t\t\t\ttmp = RB_RIGHT(parent, field);\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tif ((RB_LEFT(tmp, field) == NULL ||\t\t\\\n\t\t\t    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\\\n\t\t\t    (RB_RIGHT(tmp, field) == NULL ||\t\t\\\n\t\t\t    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\\\n\t\t\t\tRB_COLOR(tmp, field) = RB_RED;\t\t\\\n\t\t\t\telm = parent;\t\t\t\t\\\n\t\t\t\tparent = RB_PARENT(elm, field);\t\t\\\n\t\t\t} else {\t\t\t\t\t\\\n\t\t\t\tif (RB_RIGHT(tmp, field) == NULL ||\t\\\n\t\t\t\t    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\\\n\t\t\t\t\tstruct type *oleft;\t\t\\\n\t\t\t\t\tif ((oleft = RB_LEFT(tmp, field)) \\\n\t\t\t\t\t    != NULL)\t\t\t\\\n\t\t\t\t\t\tRB_COLOR(oleft, field) = RB_BLACK;\\\n\t\t\t\t\tRB_COLOR(tmp, field) = RB_RED;\t\\\n\t\t\t\t\tRB_ROTATE_RIGHT(head, tmp, oleft, field);\\\n\t\t\t\t\ttmp = RB_RIGHT(parent, field);\t\\\n\t\t\t\t}\t\t\t\t\t\\\n\t\t\t\tRB_COLOR(tmp, field) = RB_COLOR(parent, field);\\\n\t\t\t\tRB_COLOR(parent, field) = RB_BLACK;\t\\\n\t\t\t\tif (RB_RIGHT(tmp, field))\t\t\\\n\t\t\t\t\tRB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\\\n\t\t\t\tRB_ROTATE_LEFT(head, parent, tmp, field);\\\n\t\t\t\telm = RB_ROOT(head);\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t} else {\t\t\t\t\t\t\\\n\t\t\ttmp = RB_LEFT(parent, field);\t\t\t\\\n\t\t\tif (RB_COLOR(tmp, field) == RB_RED) {\t\t\\\n\t\t\t\tRB_SET_BLACKRED(tmp, parent, field);\t\\\n\t\t\t\tRB_ROTATE_RIGHT(head, parent, tmp, field);\\\n\t\t\t\ttmp = RB_LEFT(parent, field);\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t\tif ((RB_LEFT(tmp, field) == NULL ||\t\t\\\n\t\t\t    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\\\n\t\t\t    (RB_RIGHT(tmp, field) == NULL ||\t\t\\\n\t\t\t    RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\\\n\t\t\t\tRB_COLOR(tmp, field) = RB_RED;\t\t\\\n\t\t\t\telm = parent;\t\t\t\t\\\n\t\t\t\tparent = RB_PARENT(elm, field);\t\t\\\n\t\t\t} else {\t\t\t\t\t\\\n\t\t\t\tif (RB_LEFT(tmp, field) == NULL ||\t\\\n\t\t\t\t    RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\\\n\t\t\t\t\tstruct type *oright;\t\t\\\n\t\t\t\t\tif ((oright = RB_RIGHT(tmp, field)) \\\n\t\t\t\t\t    != NULL)\t\t\t\\\n\t\t\t\t\t\tRB_COLOR(oright, field) = RB_BLACK;\\\n\t\t\t\t\tRB_COLOR(tmp, field) = RB_RED;\t\\\n\t\t\t\t\tRB_ROTATE_LEFT(head, tmp, oright, field);\\\n\t\t\t\t\ttmp = RB_LEFT(parent, field);\t\\\n\t\t\t\t}\t\t\t\t\t\\\n\t\t\t\tRB_COLOR(tmp, field) = RB_COLOR(parent, field);\\\n\t\t\t\tRB_COLOR(parent, field) = RB_BLACK;\t\\\n\t\t\t\tif (RB_LEFT(tmp, field))\t\t\\\n\t\t\t\t\tRB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\\\n\t\t\t\tRB_ROTATE_RIGHT(head, parent, tmp, field);\\\n\t\t\t\telm = RB_ROOT(head);\t\t\t\\\n\t\t\t\tbreak;\t\t\t\t\t\\\n\t\t\t}\t\t\t\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tif (elm)\t\t\t\t\t\t\t\\\n\t\tRB_COLOR(elm, field) = RB_BLACK;\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_REMOVE(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *child, *parent, *old = elm;\t\t\t\\\n\tint color;\t\t\t\t\t\t\t\\\n\tif (RB_LEFT(elm, field) == NULL)\t\t\t\t\\\n\t\tchild = RB_RIGHT(elm, field);\t\t\t\t\\\n\telse if (RB_RIGHT(elm, field) == NULL)\t\t\t\t\\\n\t\tchild = RB_LEFT(elm, field);\t\t\t\t\\\n\telse {\t\t\t\t\t\t\t\t\\\n\t\tstruct type *left;\t\t\t\t\t\\\n\t\telm = RB_RIGHT(elm, field);\t\t\t\t\\\n\t\twhile ((left = RB_LEFT(elm, field)) != NULL)\t\t\\\n\t\t\telm = left;\t\t\t\t\t\\\n\t\tchild = RB_RIGHT(elm, field);\t\t\t\t\\\n\t\tparent = RB_PARENT(elm, field);\t\t\t\t\\\n\t\tcolor = RB_COLOR(elm, field);\t\t\t\t\\\n\t\tif (child)\t\t\t\t\t\t\\\n\t\t\tRB_PARENT(child, field) = parent;\t\t\\\n\t\tif (parent) {\t\t\t\t\t\t\\\n\t\t\tif (RB_LEFT(parent, field) == elm)\t\t\\\n\t\t\t\tRB_LEFT(parent, field) = child;\t\t\\\n\t\t\telse\t\t\t\t\t\t\\\n\t\t\t\tRB_RIGHT(parent, field) = child;\t\\\n\t\t\tRB_AUGMENT(parent);\t\t\t\t\\\n\t\t} else\t\t\t\t\t\t\t\\\n\t\t\tRB_ROOT(head) = child;\t\t\t\t\\\n\t\tif (RB_PARENT(elm, field) == old)\t\t\t\\\n\t\t\tparent = elm;\t\t\t\t\t\\\n\t\t(elm)->field = (old)->field;\t\t\t\t\\\n\t\tif (RB_PARENT(old, field)) {\t\t\t\t\\\n\t\t\tif (RB_LEFT(RB_PARENT(old, field), field) == old)\\\n\t\t\t\tRB_LEFT(RB_PARENT(old, field), field) = elm;\\\n\t\t\telse\t\t\t\t\t\t\\\n\t\t\t\tRB_RIGHT(RB_PARENT(old, field), field) = elm;\\\n\t\t\tRB_AUGMENT(RB_PARENT(old, field));\t\t\\\n\t\t} else\t\t\t\t\t\t\t\\\n\t\t\tRB_ROOT(head) = elm;\t\t\t\t\\\n\t\tRB_PARENT(RB_LEFT(old, field), field) = elm;\t\t\\\n\t\tif (RB_RIGHT(old, field))\t\t\t\t\\\n\t\t\tRB_PARENT(RB_RIGHT(old, field), field) = elm;\t\\\n\t\tif (parent) {\t\t\t\t\t\t\\\n\t\t\tleft = parent;\t\t\t\t\t\\\n\t\t\tdo {\t\t\t\t\t\t\\\n\t\t\t\tRB_AUGMENT(left);\t\t\t\\\n\t\t\t} while ((left = RB_PARENT(left, field)) != NULL); \\\n\t\t}\t\t\t\t\t\t\t\\\n\t\tgoto color;\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tparent = RB_PARENT(elm, field);\t\t\t\t\t\\\n\tcolor = RB_COLOR(elm, field);\t\t\t\t\t\\\n\tif (child)\t\t\t\t\t\t\t\\\n\t\tRB_PARENT(child, field) = parent;\t\t\t\\\n\tif (parent) {\t\t\t\t\t\t\t\\\n\t\tif (RB_LEFT(parent, field) == elm)\t\t\t\\\n\t\t\tRB_LEFT(parent, field) = child;\t\t\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\tRB_RIGHT(parent, field) = child;\t\t\\\n\t\tRB_AUGMENT(parent);\t\t\t\t\t\\\n\t} else\t\t\t\t\t\t\t\t\\\n\t\tRB_ROOT(head) = child;\t\t\t\t\t\\\ncolor:\t\t\t\t\t\t\t\t\t\\\n\tif (color == RB_BLACK)\t\t\t\t\t\t\\\n\t\tname##_RB_REMOVE_COLOR(head, parent, child);\t\t\\\n\treturn (old);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* Inserts a node into the RB tree */\t\t\t\t\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_INSERT(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *tmp;\t\t\t\t\t\t\\\n\tstruct type *parent = NULL;\t\t\t\t\t\\\n\tint comp = 0;\t\t\t\t\t\t\t\\\n\ttmp = RB_ROOT(head);\t\t\t\t\t\t\\\n\twhile (tmp) {\t\t\t\t\t\t\t\\\n\t\tparent = tmp;\t\t\t\t\t\t\\\n\t\tcomp = (cmp)(elm, parent);\t\t\t\t\\\n\t\tif (comp < 0)\t\t\t\t\t\t\\\n\t\t\ttmp = RB_LEFT(tmp, field);\t\t\t\\\n\t\telse if (comp > 0)\t\t\t\t\t\\\n\t\t\ttmp = RB_RIGHT(tmp, field);\t\t\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\treturn (tmp);\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\tRB_SET(elm, parent, field);\t\t\t\t\t\\\n\tif (parent != NULL) {\t\t\t\t\t\t\\\n\t\tif (comp < 0)\t\t\t\t\t\t\\\n\t\t\tRB_LEFT(parent, field) = elm;\t\t\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\tRB_RIGHT(parent, field) = elm;\t\t\t\\\n\t\tRB_AUGMENT(parent);\t\t\t\t\t\\\n\t} else\t\t\t\t\t\t\t\t\\\n\t\tRB_ROOT(head) = elm;\t\t\t\t\t\\\n\tname##_RB_INSERT_COLOR(head, elm);\t\t\t\t\\\n\treturn (NULL);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* Finds the node with the same key as elm */\t\t\t\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_FIND(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *tmp = RB_ROOT(head);\t\t\t\t\\\n\tint comp;\t\t\t\t\t\t\t\\\n\twhile (tmp) {\t\t\t\t\t\t\t\\\n\t\tcomp = cmp(elm, tmp);\t\t\t\t\t\\\n\t\tif (comp < 0)\t\t\t\t\t\t\\\n\t\t\ttmp = RB_LEFT(tmp, field);\t\t\t\\\n\t\telse if (comp > 0)\t\t\t\t\t\\\n\t\t\ttmp = RB_RIGHT(tmp, field);\t\t\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\treturn (tmp);\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\treturn (NULL);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* Finds the first node greater than or equal to the search key */\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_NFIND(struct name *head, struct type *elm)\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *tmp = RB_ROOT(head);\t\t\t\t\\\n\tstruct type *res = NULL;\t\t\t\t\t\\\n\tint comp;\t\t\t\t\t\t\t\\\n\twhile (tmp) {\t\t\t\t\t\t\t\\\n\t\tcomp = cmp(elm, tmp);\t\t\t\t\t\\\n\t\tif (comp < 0) {\t\t\t\t\t\t\\\n\t\t\tres = tmp;\t\t\t\t\t\\\n\t\t\ttmp = RB_LEFT(tmp, field);\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t\telse if (comp > 0)\t\t\t\t\t\\\n\t\t\ttmp = RB_RIGHT(tmp, field);\t\t\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\treturn (tmp);\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\treturn (res);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* ARGSUSED */\t\t\t\t\t\t\t\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_NEXT(struct type *elm)\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tif (RB_RIGHT(elm, field)) {\t\t\t\t\t\\\n\t\telm = RB_RIGHT(elm, field);\t\t\t\t\\\n\t\twhile (RB_LEFT(elm, field))\t\t\t\t\\\n\t\t\telm = RB_LEFT(elm, field);\t\t\t\\\n\t} else {\t\t\t\t\t\t\t\\\n\t\tif (RB_PARENT(elm, field) &&\t\t\t\t\\\n\t\t    (elm == RB_LEFT(RB_PARENT(elm, field), field)))\t\\\n\t\t\telm = RB_PARENT(elm, field);\t\t\t\\\n\t\telse {\t\t\t\t\t\t\t\\\n\t\t\twhile (RB_PARENT(elm, field) &&\t\t\t\\\n\t\t\t    (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\\\n\t\t\t\telm = RB_PARENT(elm, field);\t\t\\\n\t\t\telm = RB_PARENT(elm, field);\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\treturn (elm);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n/* ARGSUSED */\t\t\t\t\t\t\t\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_PREV(struct type *elm)\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tif (RB_LEFT(elm, field)) {\t\t\t\t\t\\\n\t\telm = RB_LEFT(elm, field);\t\t\t\t\\\n\t\twhile (RB_RIGHT(elm, field))\t\t\t\t\\\n\t\t\telm = RB_RIGHT(elm, field);\t\t\t\\\n\t} else {\t\t\t\t\t\t\t\\\n\t\tif (RB_PARENT(elm, field) &&\t\t\t\t\\\n\t\t    (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\t\\\n\t\t\telm = RB_PARENT(elm, field);\t\t\t\\\n\t\telse {\t\t\t\t\t\t\t\\\n\t\t\twhile (RB_PARENT(elm, field) &&\t\t\t\\\n\t\t\t    (elm == RB_LEFT(RB_PARENT(elm, field), field)))\\\n\t\t\t\telm = RB_PARENT(elm, field);\t\t\\\n\t\t\telm = RB_PARENT(elm, field);\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\treturn (elm);\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\nattr struct type *\t\t\t\t\t\t\t\\\nname##_RB_MINMAX(struct name *head, int val)\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tstruct type *tmp = RB_ROOT(head);\t\t\t\t\\\n\tstruct type *parent = NULL;\t\t\t\t\t\\\n\twhile (tmp) {\t\t\t\t\t\t\t\\\n\t\tparent = tmp;\t\t\t\t\t\t\\\n\t\tif (val < 0)\t\t\t\t\t\t\\\n\t\t\ttmp = RB_LEFT(tmp, field);\t\t\t\\\n\t\telse\t\t\t\t\t\t\t\\\n\t\t\ttmp = RB_RIGHT(tmp, field);\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n\treturn (parent);\t\t\t\t\t\t\\\n}\n\n#define RB_NEGINF\t-1\n#define RB_INF\t1\n\n#define RB_INSERT(name, x, y)\tname##_RB_INSERT(x, y)\n#define RB_REMOVE(name, x, y)\tname##_RB_REMOVE(x, y)\n#define RB_FIND(name, x, y)\tname##_RB_FIND(x, y)\n#define RB_NFIND(name, x, y)\tname##_RB_NFIND(x, y)\n#define RB_NEXT(name, x, y)\tname##_RB_NEXT(y)\n#define RB_PREV(name, x, y)\tname##_RB_PREV(y)\n#define RB_MIN(name, x)\t\tname##_RB_MINMAX(x, RB_NEGINF)\n#define RB_MAX(name, x)\t\tname##_RB_MINMAX(x, RB_INF)\n\n#define RB_FOREACH(x, name, head)\t\t\t\t\t\\\n\tfor ((x) = RB_MIN(name, head);\t\t\t\t\t\\\n\t     (x) != NULL;\t\t\t\t\t\t\\\n\t     (x) = name##_RB_NEXT(x))\n\n#define RB_FOREACH_REVERSE(x, name, head)\t\t\t\t\\\n\tfor ((x) = RB_MAX(name, head);\t\t\t\t\t\\\n\t     (x) != NULL;\t\t\t\t\t\t\\\n\t     (x) = name##_RB_PREV(x))\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "include/xhyve/support/uuid.h",
    "content": "/*-\n * Copyright (c) 2002,2005 Marcel Moolenaar\n * Copyright (c) 2002 Hiten Mahesh Pandya\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\n#define\t_UUID_NODE_LEN 6\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct uuid {\n\tuint32_t time_low;\n\tuint16_t time_mid;\n\tuint16_t time_hi_and_version;\n\tuint8_t clock_seq_hi_and_reserved;\n\tuint8_t clock_seq_low;\n\tuint8_t node[_UUID_NODE_LEN];\n};\n#pragma clang diagnostic pop\n\ntypedef struct uuid uuid_internal_t;\n\n/*\n * This implementation mostly conforms to the DCE 1.1 specification.\n * See Also:\n *\tuuidgen(1), uuidgen(2), uuid(3)\n */\n\n/* Status codes returned by the functions. */\n#define\tuuid_s_ok\t\t\t0\n#define\tuuid_s_bad_version\t\t1\n#define\tuuid_s_invalid_string_uuid\t2\n#define\tuuid_s_no_memory\t\t3\n\n/*\n * uuid_create_nil() - create a nil UUID.\n * See also:\n *\thttp://www.opengroup.org/onlinepubs/009629399/uuid_create_nil.htm\n */\nstatic inline void\nuuid_create_nil(uuid_t *u, uint32_t *status)\n{\n\tif (status)\n\t\t*status = uuid_s_ok;\n\n\tbzero(u, sizeof(*u));\n}\n\nstatic inline void\nuuid_enc_le(void *buf, uuid_t *uuid)\n{\n\tuuid_internal_t *u = (uuid_internal_t *) ((void *) uuid);\n\tuint8_t *p = buf;\n\tint i;\n\n\tmemcpy(p, &u->time_low, 4);\n\tmemcpy(p, &u->time_mid, 2);\n\tmemcpy(p, &u->time_hi_and_version, 2);\n\tp[8] = u->clock_seq_hi_and_reserved;\n\tp[9] = u->clock_seq_low;\n\tfor (i = 0; i < _UUID_NODE_LEN; i++)\n\t\tp[10 + i] = u->node[i];\n}\n\n/*\n * uuid_from_string() - convert a string representation of an UUID into\n *\t\t\ta binary representation.\n * See also:\n *\thttp://www.opengroup.org/onlinepubs/009629399/uuid_from_string.htm\n *\n * NOTE: The sequence field is in big-endian, while the time fields are in\n *\t native byte order.\n */\nstatic inline void\nuuid_from_string(const char *s, uuid_t *uuid, uint32_t *status)\n{\n\tuuid_internal_t *u = (uuid_internal_t *) ((void *) uuid);\n\tint n;\n\n\t/* Short-circuit 2 special cases: NULL pointer and empty string. */\n\tif (s == NULL || *s == '\\0') {\n\t\tuuid_create_nil(((uuid_t *) u), status);\n\t\treturn;\n\t}\n\n\t/* Assume the worst. */\n\tif (status != NULL)\n\t\t*status = uuid_s_invalid_string_uuid;\n\n\t/* The UUID string representation has a fixed length. */\n\tif (strlen(s) != 36)\n\t\treturn;\n\n\t/*\n\t * We only work with \"new\" UUIDs. New UUIDs have the form:\n\t *\t01234567-89ab-cdef-0123-456789abcdef\n\t * The so called \"old\" UUIDs, which we don't support, have the form:\n\t *\t0123456789ab.cd.ef.01.23.45.67.89.ab\n\t */\n\tif (s[8] != '-')\n\t\treturn;\n\n\tn = sscanf(s,\n\t    \"%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx\",\n\t    &u->time_low, &u->time_mid, &u->time_hi_and_version,\n\t    &u->clock_seq_hi_and_reserved, &u->clock_seq_low, &u->node[0],\n\t    &u->node[1], &u->node[2], &u->node[3], &u->node[4], &u->node[5]);\n\n\t/* Make sure we have all conversions. */\n\tif (n != 11)\n\t\treturn;\n\n\t/* We have a successful scan. Check semantics... */\n\tn = u->clock_seq_hi_and_reserved;\n\tif ((n & 0x80) != 0x00 &&\t\t\t/* variant 0? */\n\t    (n & 0xc0) != 0x80 &&\t\t\t/* variant 1? */\n\t    (n & 0xe0) != 0xc0) {\t\t\t/* variant 2? */\n\t\tif (status != NULL)\n\t\t\t*status = uuid_s_bad_version;\n\t} else {\n\t\tif (status != NULL)\n\t\t\t*status = uuid_s_ok;\n\t}\n}\n"
  },
  {
    "path": "include/xhyve/uart_emul.h",
    "content": "/*-\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#define\tUART_IO_BAR_SIZE 8\n\nstruct uart_softc;\n\ntypedef void (*uart_intr_func_t)(void *arg);\nstruct uart_softc *uart_init(uart_intr_func_t intr_assert,\n\tuart_intr_func_t intr_deassert, void *arg);\n\nint uart_legacy_alloc(int unit, int *ioaddr, int *irq);\nuint8_t uart_read(struct uart_softc *sc, int offset);\nvoid uart_write(struct uart_softc *sc, int offset, uint8_t value);\nint uart_set_backend(struct uart_softc *sc, const char *backend, const char *devname);\n"
  },
  {
    "path": "include/xhyve/vga.h",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#ifndef _VGA_H_\n#define\t_VGA_H_\n\n#define\tVGA_IOPORT_START\t\t0x3c0\n#define\tVGA_IOPORT_END\t\t\t0x3df\n\n/* General registers */\n#define\tGEN_INPUT_STS0_PORT\t\t0x3c2\n#define\tGEN_FEATURE_CTRL_PORT\t\t0x3ca\n#define\tGEN_MISC_OUTPUT_PORT\t\t0x3cc\n#define\tGEN_INPUT_STS1_MONO_PORT\t0x3ba\n#define\tGEN_INPUT_STS1_COLOR_PORT\t0x3da\n#define\t GEN_IS1_VR\t\t\t0x08\t/* Vertical retrace */\n#define\t GEN_IS1_DE\t\t\t0x01\t/* Display enable not */\n\n/* Attribute controller registers. */\n#define\tATC_IDX_PORT\t\t\t0x3c0\n#define\tATC_DATA_PORT\t\t\t0x3c1\n\n#define\tATC_IDX_MASK\t\t\t0x1f\n#define\tATC_PALETTE0\t\t\t0\n#define\tATC_PALETTE15\t\t\t15\n#define\tATC_MODE_CONTROL\t\t16\n#define\t ATC_MC_IPS\t\t\t0x80\t/* Internal palette size */\n#define\t ATC_MC_GA\t\t\t0x01\t/* Graphics/alphanumeric */\n#define\tATC_OVERSCAN_COLOR\t\t17\n#define\tATC_COLOR_PLANE_ENABLE\t\t18\n#define\tATC_HORIZ_PIXEL_PANNING\t\t19\n#define\tATC_COLOR_SELECT\t\t20\n#define\t ATC_CS_C67\t\t\t0x0c\t/* Color select bits 6+7 */\n#define\t ATC_CS_C45\t\t\t0x03\t/* Color select bits 4+5 */\n\n/* Sequencer registers. */\n#define\tSEQ_IDX_PORT\t\t\t0x3c4\n#define\tSEQ_DATA_PORT\t\t\t0x3c5\n\n#define\tSEQ_RESET\t\t\t0\n#define\tSEQ_RESET_ASYNC\t\t\t0x1\n#define\tSEQ_RESET_SYNC\t\t\t0x2\n#define\tSEQ_CLOCKING_MODE\t\t1\n#define\t SEQ_CM_SO\t\t\t0x20\t/* Screen off */\n#define\t SEQ_CM_89\t\t\t0x01\t/* 8/9 dot clock */\n#define\tSEQ_MAP_MASK\t\t\t2\n#define\tSEQ_CHAR_MAP_SELECT\t\t3\n#define\t SEQ_CMS_SAH\t\t\t0x20\t/* Char map A bit 2 */\n#define\t SEQ_CMS_SAH_SHIFT\t\t5\n#define\t SEQ_CMS_SA\t\t\t0x0c\t/* Char map A bits 0+1 */\n#define\t SEQ_CMS_SA_SHIFT\t\t2\n#define\t SEQ_CMS_SBH\t\t\t0x10\t/* Char map B bit 2 */\n#define\t SEQ_CMS_SBH_SHIFT\t\t4\n#define\t SEQ_CMS_SB\t\t\t0x03\t/* Char map B bits 0+1 */\n#define\t SEQ_CMS_SB_SHIFT\t\t0\n#define\tSEQ_MEMORY_MODE\t\t\t4\n#define\t SEQ_MM_C4\t\t\t0x08\t/* Chain 4 */\n#define\t SEQ_MM_OE\t\t\t0x04\t/* Odd/even */\n#define\t SEQ_MM_EM\t\t\t0x02\t/* Extended memory */\n\n/* Graphics controller registers. */\n#define\tGC_IDX_PORT\t\t\t0x3ce\n#define\tGC_DATA_PORT\t\t\t0x3cf\n\n#define\tGC_SET_RESET\t\t\t0\n#define\tGC_ENABLE_SET_RESET\t\t1\n#define\tGC_COLOR_COMPARE\t\t2\n#define\tGC_DATA_ROTATE\t\t\t3\n#define\tGC_READ_MAP_SELECT\t\t4\n#define\tGC_MODE\t\t\t\t5\n#define\t GC_MODE_OE\t\t\t0x10\t/* Odd/even */\n#define\t GC_MODE_C4\t\t\t0x04\t/* Chain 4 */\n\n#define\tGC_MISCELLANEOUS\t\t6\n#define\t GC_MISC_GM\t\t\t0x01\t/* Graphics/alphanumeric */\n#define\t GC_MISC_MM\t\t\t0x0c\t/* memory map */\n#define\t GC_MISC_MM_SHIFT\t2\n#define\tGC_COLOR_DONT_CARE\t\t7\n#define\tGC_BIT_MASK\t\t\t8\n\n/* CRT controller registers. */\n#define\tCRTC_IDX_MONO_PORT\t\t0x3b4\n#define\tCRTC_DATA_MONO_PORT\t\t0x3b5\n#define\tCRTC_IDX_COLOR_PORT\t\t0x3d4\n#define\tCRTC_DATA_COLOR_PORT\t\t0x3d5\n\n#define\tCRTC_HORIZ_TOTAL\t\t0\n#define\tCRTC_HORIZ_DISP_END\t\t1\n#define\tCRTC_START_HORIZ_BLANK\t\t2\n#define\tCRTC_END_HORIZ_BLANK\t\t3\n#define\tCRTC_START_HORIZ_RETRACE\t4\n#define\tCRTC_END_HORIZ_RETRACE\t\t5\n#define\tCRTC_VERT_TOTAL\t\t\t6\n#define\tCRTC_OVERFLOW\t\t\t7\n#define\t CRTC_OF_VRS9\t\t\t0x80\t/* VRS bit 9 */\n#define\t CRTC_OF_VRS9_SHIFT\t\t7\n#define\t CRTC_OF_VDE9\t\t\t0x40\t/* VDE bit 9 */\n#define\t CRTC_OF_VDE9_SHIFT\t\t6\n#define\t CRTC_OF_VRS8\t\t\t0x04\t/* VRS bit 8 */\n#define\t CRTC_OF_VRS8_SHIFT\t\t2\n#define\t CRTC_OF_VDE8\t\t\t0x02\t/* VDE bit 8 */\n#define\t CRTC_OF_VDE8_SHIFT\t\t1\n#define\tCRTC_PRESET_ROW_SCAN\t\t8\n#define\tCRTC_MAX_SCAN_LINE\t\t9\n#define\t CRTC_MSL_MSL\t\t\t0x1f\n#define\tCRTC_CURSOR_START\t\t10\n#define\t CRTC_CS_CO\t\t\t0x20\t/* Cursor off */\n#define\t CRTC_CS_CS\t\t\t0x1f\t/* Cursor start */\n#define\tCRTC_CURSOR_END\t\t\t11\n#define\t CRTC_CE_CE\t\t\t0x1f\t/* Cursor end */\n#define\tCRTC_START_ADDR_HIGH\t\t12\n#define\tCRTC_START_ADDR_LOW\t\t13\n#define\tCRTC_CURSOR_LOC_HIGH\t\t14\n#define\tCRTC_CURSOR_LOC_LOW\t\t15\n#define\tCRTC_VERT_RETRACE_START\t\t16\n#define\tCRTC_VERT_RETRACE_END\t\t17\n#define\t CRTC_VRE_MASK\t\t\t0xf\n#define\tCRTC_VERT_DISP_END\t\t18\n#define\tCRTC_OFFSET\t\t\t19\n#define\tCRTC_UNDERLINE_LOC\t\t20\n#define\tCRTC_START_VERT_BLANK\t\t21\n#define\tCRTC_END_VERT_BLANK\t\t22\n#define\tCRTC_MODE_CONTROL\t\t23\n#define\t CRTC_MC_TE\t\t\t0x80\t/* Timing enable */\n#define\tCRTC_LINE_COMPARE\t\t24\n\n/* DAC registers */\n#define\tDAC_MASK\t\t\t0x3c6\n#define\tDAC_IDX_RD_PORT\t\t\t0x3c7\n#define\tDAC_IDX_WR_PORT\t\t\t0x3c8\n#define\tDAC_DATA_PORT\t\t\t0x3c9\n\nvoid    *vga_init(int io_only);\n\nvoid vga_render(struct bhyvegc *gc, void *arg);\n\n#endif /* _VGA_H_ */\n"
  },
  {
    "path": "include/xhyve/virtio.h",
    "content": "/*-\n * Copyright (c) 2013  Chris Torek <torek @ torek net>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <pthread.h>\n\n/*\n * These are derived from several virtio specifications.\n *\n * Some useful links:\n *    https://github.com/rustyrussell/virtio-spec\n *    http://people.redhat.com/pbonzini/virtio-spec.pdf\n */\n\n/*\n * A virtual device has zero or more \"virtual queues\" (virtqueue).\n * Each virtqueue uses at least two 4096-byte pages, laid out thus:\n *\n *      +-----------------------------------------------+\n *      |    \"desc\":  <N> descriptors, 16 bytes each    |\n *      |   -----------------------------------------   |\n *      |   \"avail\":   2 uint16; <N> uint16; 1 uint16   |\n *      |   -----------------------------------------   |\n *      |              pad to 4k boundary               |\n *      +-----------------------------------------------+\n *      |   \"used\": 2 x uint16; <N> elems; 1 uint16     |\n *      |   -----------------------------------------   |\n *      |              pad to 4k boundary               |\n *      +-----------------------------------------------+\n *\n * The number <N> that appears here is always a power of two and is\n * limited to no more than 32768 (as it must fit in a 16-bit field).\n * If <N> is sufficiently large, the above will occupy more than\n * two pages.  In any case, all pages must be physically contiguous\n * within the guest's physical address space.\n *\n * The <N> 16-byte \"desc\" descriptors consist of a 64-bit guest\n * physical address <addr>, a 32-bit length <len>, a 16-bit\n * <flags>, and a 16-bit <next> field (all in guest byte order).\n *\n * There are three flags that may be set :\n *\tNEXT    descriptor is chained, so use its \"next\" field\n *\tWRITE   descriptor is for host to write into guest RAM\n *\t\t(else host is to read from guest RAM)\n *\tINDIRECT   descriptor address field is (guest physical)\n *\t\taddress of a linear array of descriptors\n *\n * Unless INDIRECT is set, <len> is the number of bytes that may\n * be read/written from guest physical address <addr>.  If\n * INDIRECT is set, WRITE is ignored and <len> provides the length\n * of the indirect descriptors (and <len> must be a multiple of\n * 16).  Note that NEXT may still be set in the main descriptor\n * pointing to the indirect, and should be set in each indirect\n * descriptor that uses the next descriptor (these should generally\n * be numbered sequentially).  However, INDIRECT must not be set\n * in the indirect descriptors.  Upon reaching an indirect descriptor\n * without a NEXT bit, control returns to the direct descriptors.\n *\n * Except inside an indirect, each <next> value must be in the\n * range [0 .. N) (i.e., the half-open interval).  (Inside an\n * indirect, each <next> must be in the range [0 .. <len>/16).)\n *\n * The \"avail\" data structures reside in the same pages as the\n * \"desc\" structures since both together are used by the device to\n * pass information to the hypervisor's virtual driver.  These\n * begin with a 16-bit <flags> field and 16-bit index <idx>, then\n * have <N> 16-bit <ring> values, followed by one final 16-bit\n * field <used_event>.  The <N> <ring> entries are simply indices\n * indices into the descriptor ring (and thus must meet the same\n * constraints as each <next> value).  However, <idx> is counted\n * up from 0 (initially) and simply wraps around after 65535; it\n * is taken mod <N> to find the next available entry.\n *\n * The \"used\" ring occupies a separate page or pages, and contains\n * values written from the virtual driver back to the guest OS.\n * This begins with a 16-bit <flags> and 16-bit <idx>, then there\n * are <N> \"vring_used\" elements, followed by a 16-bit <avail_event>.\n * The <N> \"vring_used\" elements consist of a 32-bit <id> and a\n * 32-bit <len> (vu_tlen below).  The <id> is simply the index of\n * the head of a descriptor chain the guest made available\n * earlier, and the <len> is the number of bytes actually written,\n * e.g., in the case of a network driver that provided a large\n * receive buffer but received only a small amount of data.\n *\n * The two event fields, <used_event> and <avail_event>, in the\n * avail and used rings (respectively -- note the reversal!), are\n * always provided, but are used only if the virtual device\n * negotiates the VIRTIO_RING_F_EVENT_IDX feature during feature\n * negotiation.  Similarly, both rings provide a flag --\n * VRING_AVAIL_F_NO_INTERRUPT and VRING_USED_F_NO_NOTIFY -- in\n * their <flags> field, indicating that the guest does not need an\n * interrupt, or that the hypervisor driver does not need a\n * notify, when descriptors are added to the corresponding ring.\n * (These are provided only for interrupt optimization and need\n * not be implemented.)\n */\n#define VRING_ALIGN\t4096\n\n#define VRING_DESC_F_NEXT\t(1 << 0)\n#define VRING_DESC_F_WRITE\t(1 << 1)\n#define VRING_DESC_F_INDIRECT\t(1 << 2)\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\n\nstruct virtio_desc { /* AKA vring_desc */\n\tuint64_t vd_addr; /* guest physical address */\n\tuint32_t vd_len; /* length of scatter/gather seg */\n\tuint16_t vd_flags; /* VRING_F_DESC_* */\n\tuint16_t vd_next; /* next desc if F_NEXT */\n} __packed;\n\nstruct virtio_used { /* AKA vring_used_elem */\n\tuint32_t vu_idx; /* head of used descriptor chain */\n\tuint32_t vu_tlen; /* length written-to */\n} __packed;\n\n#define VRING_AVAIL_F_NO_INTERRUPT   1\n\nstruct vring_avail {\n\tuint16_t va_flags; /* VRING_AVAIL_F_* */\n\tuint16_t va_idx; /* counts to 65535, then cycles */\n\tuint16_t va_ring[]; /* size N, reported in QNUM value */\n/*\tuint16_t va_used_event; -- after N ring entries */\n} __packed;\n\n#define\tVRING_USED_F_NO_NOTIFY\t\t1\nstruct vring_used {\n\tuint16_t vu_flags; /* VRING_USED_F_* */\n\tuint16_t vu_idx; /* counts to 65535, then cycles */\n\tstruct virtio_used vu_ring[]; /* size N */\n/*\tuint16_t vu_avail_event; -- after N ring entries */\n} __packed;\n\n#pragma clang diagnostic pop\n\n/*\n * The address of any given virtual queue is determined by a single\n * Page Frame Number register.  The guest writes the PFN into the\n * PCI config space.  However, a device that has two or more\n * virtqueues can have a different PFN, and size, for each queue.\n * The number of queues is determinable via the PCI config space\n * VTCFG_R_QSEL register.  Writes to QSEL select the queue: 0 means\n * queue #0, 1 means queue#1, etc.  Once a queue is selected, the\n * remaining PFN and QNUM registers refer to that queue.\n *\n * QNUM is a read-only register containing a nonzero power of two\n * that indicates the (hypervisor's) queue size.  Or, if reading it\n * produces zero, the hypervisor does not have a corresponding\n * queue.  (The number of possible queues depends on the virtual\n * device.  The block device has just one; the network device\n * provides either two -- 0 = receive, 1 = transmit -- or three,\n * with 2 = control.)\n *\n * PFN is a read/write register giving the physical page address of\n * the virtqueue in guest memory (the guest must allocate enough space\n * based on the hypervisor's provided QNUM).\n *\n * QNOTIFY is effectively write-only: when the guest writes a queue\n * number to the register, the hypervisor should scan the specified\n * virtqueue. (Reading QNOTIFY currently always gets 0).\n */\n\n/*\n * PFN register shift amount\n */\n#define VRING_PFN               12\n\n/*\n * Virtio device types\n *\n * XXX Should really be merged with <dev/virtio/virtio.h> defines\n */\n#define\tVIRTIO_TYPE_NET\t\t1\n#define\tVIRTIO_TYPE_BLOCK\t2\n#define\tVIRTIO_TYPE_CONSOLE\t3\n#define\tVIRTIO_TYPE_ENTROPY\t4\n#define\tVIRTIO_TYPE_BALLOON\t5\n#define\tVIRTIO_TYPE_IOMEMORY\t6\n#define\tVIRTIO_TYPE_RPMSG\t7\n#define\tVIRTIO_TYPE_SCSI\t8\n#define\tVIRTIO_TYPE_9P\t\t9\n\n/* experimental IDs start at 65535 and work down */\n\n/*\n * PCI vendor/device IDs\n */\n#define\tVIRTIO_VENDOR\t\t0x1AF4\n#define\tVIRTIO_DEV_NET\t\t0x1000\n#define\tVIRTIO_DEV_BLOCK\t0x1001\n#define\tVIRTIO_DEV_RANDOM\t0x1005\n\n/*\n * PCI config space constants.\n *\n * If MSI-X is enabled, the ISR register is generally not used,\n * and the configuration vector and queue vector appear at offsets\n * 20 and 22 with the remaining configuration registers at 24.\n * If MSI-X is not enabled, those two registers disappear and\n * the remaining configuration registers start at offset 20.\n */\n#define VTCFG_R_HOSTCAP\t\t0\n#define VTCFG_R_GUESTCAP\t4\n#define VTCFG_R_PFN\t\t8\n#define VTCFG_R_QNUM\t\t12\n#define VTCFG_R_QSEL\t\t14\n#define VTCFG_R_QNOTIFY\t\t16\n#define VTCFG_R_STATUS\t\t18\n#define VTCFG_R_ISR\t\t19\n#define VTCFG_R_CFGVEC\t\t20\n#define VTCFG_R_QVEC\t\t22\n#define VTCFG_R_CFG0\t\t20\t/* No MSI-X */\n#define VTCFG_R_CFG1\t\t24\t/* With MSI-X */\n#define VTCFG_R_MSIX\t\t20\n\n/*\n * Bits in VTCFG_R_STATUS.  Guests need not actually set any of these,\n * but a guest writing 0 to this register means \"please reset\".\n */\n#define\tVTCFG_STATUS_ACK\t0x01\t/* guest OS has acknowledged dev */\n#define\tVTCFG_STATUS_DRIVER\t0x02\t/* guest OS driver is loaded */\n#define\tVTCFG_STATUS_DRIVER_OK\t0x04\t/* guest OS driver ready */\n#define\tVTCFG_STATUS_FAILED\t0x80\t/* guest has given up on this dev */\n\n/*\n * Bits in VTCFG_R_ISR.  These apply only if not using MSI-X.\n *\n * (We don't [yet?] ever use CONF_CHANGED.)\n */\n#define\tVTCFG_ISR_QUEUES\t0x01\t/* re-scan queues */\n#define\tVTCFG_ISR_CONF_CHANGED\t0x80\t/* configuration changed */\n\n#define VIRTIO_MSI_NO_VECTOR\t0xFFFF\n\n/*\n * Feature flags.\n * Note: bits 0 through 23 are reserved to each device type.\n */\n#define\tVIRTIO_F_NOTIFY_ON_EMPTY\t(1 << 24)\n#define\tVIRTIO_RING_F_INDIRECT_DESC\t(1 << 28)\n#define\tVIRTIO_RING_F_EVENT_IDX\t\t(1 << 29)\n\n/* From section 2.3, \"Virtqueue Configuration\", of the virtio specification */\nstatic inline size_t\nvring_size(u_int qsz)\n{\n\tsize_t size;\n\n\t/* constant 3 below = va_flags, va_idx, va_used_event */\n\tsize = sizeof(struct virtio_desc) * qsz + sizeof(uint16_t) * (3 + qsz);\n\tsize = roundup2(size, ((size_t) VRING_ALIGN));\n\n\t/* constant 3 below = vu_flags, vu_idx, vu_avail_event */\n\tsize += sizeof(uint16_t) * 3 + sizeof(struct virtio_used) * qsz;\n\tsize = roundup2(size, ((size_t) VRING_ALIGN));\n\n\treturn (size);\n}\n\nstruct pci_devinst;\nstruct vqueue_info;\n\n/*\n * A virtual device, with some number (possibly 0) of virtual\n * queues and some size (possibly 0) of configuration-space\n * registers private to the device.  The virtio_softc should come\n * at the front of each \"derived class\", so that a pointer to the\n * virtio_softc is also a pointer to the more specific, derived-\n * from-virtio driver's softc.\n *\n * Note: inside each hypervisor virtio driver, changes to these\n * data structures must be locked against other threads, if any.\n * Except for PCI config space register read/write, we assume each\n * driver does the required locking, but we need a pointer to the\n * lock (if there is one) for PCI config space read/write ops.\n *\n * When the guest reads or writes the device's config space, the\n * generic layer checks for operations on the special registers\n * described above.  If the offset of the register(s) being read\n * or written is past the CFG area (CFG0 or CFG1), the request is\n * passed on to the virtual device, after subtracting off the\n * generic-layer size.  (So, drivers can just use the offset as\n * an offset into \"struct config\", for instance.)\n *\n * (The virtio layer also makes sure that the read or write is to/\n * from a \"good\" config offset, hence vc_cfgsize, and on BAR #0.\n * However, the driver must verify the read or write size and offset\n * and that no one is writing a readonly register.)\n *\n * The BROKED flag (\"this thing done gone and broked\") is for future\n * use.\n */\n#define\tVIRTIO_USE_MSIX\t\t0x01\n#define\tVIRTIO_EVENT_IDX\t0x02\t/* use the event-index values */\n#define\tVIRTIO_BROKED\t\t0x08\t/* ??? */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct virtio_softc {\n\tstruct virtio_consts *vs_vc; /* constants (see below) */\n\tint vs_flags; /* VIRTIO_* flags from above */\n\tpthread_mutex_t *vs_mtx; /* POSIX mutex, if any */\n\tstruct pci_devinst *vs_pi; /* PCI device instance */\n\tuint32_t vs_negotiated_caps; /* negotiated capabilities */\n\tstruct vqueue_info *vs_queues; /* one per vc_nvq */\n\tint vs_curq; /* current queue */\n\tuint8_t vs_status; /* value from last status write */\n\tuint8_t vs_isr; /* ISR flags, if not MSI-X */\n\tuint16_t vs_msix_cfg_idx; /* MSI-X vector for config event */\n};\n\n#define\tVS_LOCK(vs) \\\ndo { \\\n\tif (vs->vs_mtx) \\\n\t\tpthread_mutex_lock(vs->vs_mtx); \\\n} while (0)\n\n#define\tVS_UNLOCK(vs) \\\ndo { \\\n\tif (vs->vs_mtx) \\\n\t\tpthread_mutex_unlock(vs->vs_mtx); \\\n} while (0)\n\nstruct virtio_consts {\n\t/* name of driver (for diagnostics) */\n\tconst char *vc_name;\n\t/* number of virtual queues */\n\tint vc_nvq;\n\t/* size of dev-specific config regs */\n\tsize_t vc_cfgsize;\n\t/* called on virtual device reset */\n\tvoid (*vc_reset)(void *);\n\t/* called on QNOTIFY if no VQ notify */\n\tvoid (*vc_qnotify)(void *, struct vqueue_info *);\n\t/* called to read config regs */\n\tint (*vc_cfgread)(void *, int, int, uint32_t *);\n\t/* called to write config regs */\n\tint (*vc_cfgwrite)(void *, int, int, uint32_t);\n\t/* called to apply negotiated features */\n\tvoid (*vc_apply_features)(void *, uint64_t);\n\t/* hypervisor-provided capabilities */\n\tuint64_t vc_hv_caps;\n};\n\n/*\n * Data structure allocated (statically) per virtual queue.\n *\n * Drivers may change vq_qsize after a reset.  When the guest OS\n * requests a device reset, the hypervisor first calls\n * vs->vs_vc->vc_reset(); then the data structure below is\n * reinitialized (for each virtqueue: vs->vs_vc->vc_nvq).\n *\n * The remaining fields should only be fussed-with by the generic\n * code.\n *\n * Note: the addresses of vq_desc, vq_avail, and vq_used are all\n * computable from each other, but it's a lot simpler if we just\n * keep a pointer to each one.  The event indices are similarly\n * (but more easily) computable, and this time we'll compute them:\n * they're just XX_ring[N].\n */\n#define\tVQ_ALLOC\t0x01\t/* set once we have a pfn */\n#define\tVQ_BROKED\t0x02\t/* ??? */\nstruct vqueue_info {\n\t/* size of this queue (a power of 2) */\n\tuint16_t vq_qsize;\n\t/* called instead of vc_notify, if not NULL */\n\tvoid (*vq_notify)(void *, struct vqueue_info *);\n\t/* backpointer to softc */\n\tstruct virtio_softc *vq_vs;\n\t/* we're the num'th queue in the softc */\n\tuint16_t vq_num;\n\t/* flags (see above) */\n\tuint16_t vq_flags;\n\t/* a recent value of vq_avail->va_idx */\n\tuint16_t vq_last_avail;\n\t/* saved vq_used->vu_idx; see vq_endchains */\n\tuint16_t vq_save_used;\n\t/* MSI-X index, or VIRTIO_MSI_NO_VECTOR */\n\tuint16_t vq_msix_idx;\n\t/* PFN of virt queue (not shifted!) */\n\tuint32_t vq_pfn;\n\t/* descriptor array */\n\tvolatile struct virtio_desc *vq_desc;\n\t/* the \"avail\" ring */\n\tvolatile struct vring_avail *vq_avail;\n\t/* the \"used\" ring */\n\tvolatile struct vring_used *vq_used;\n};\n\n#pragma clang diagnostic pop\n\n/* as noted above, these are sort of backwards, name-wise */\n#define VQ_AVAIL_EVENT_IDX(vq) \\\n\t(*(volatile uint16_t *)&(vq)->vq_used->vu_ring[(vq)->vq_qsize])\n#define VQ_USED_EVENT_IDX(vq) \\\n\t((vq)->vq_avail->va_ring[(vq)->vq_qsize])\n\n/*\n * Is this ring ready for I/O?\n */\nstatic inline int\nvq_ring_ready(struct vqueue_info *vq)\n{\n\treturn (vq->vq_flags & VQ_ALLOC);\n}\n\n/*\n * Are there \"available\" descriptors?  (This does not count\n * how many, just returns True if there are some.)\n */\nstatic inline int\nvq_has_descs(struct vqueue_info *vq)\n{\n\treturn (vq_ring_ready(vq) && vq->vq_last_avail !=\n\t    vq->vq_avail->va_idx);\n}\n\n/*\n * Deliver an interrupt to guest on the given virtual queue\n * (if possible, or a generic MSI interrupt if not using MSI-X).\n */\nstatic inline void\nvq_interrupt(struct virtio_softc *vs, struct vqueue_info *vq)\n{\n\tif (pci_msix_enabled(vs->vs_pi))\n\t\tpci_generate_msix(vs->vs_pi, vq->vq_msix_idx);\n\telse {\n\t\tVS_LOCK(vs);\n\t\tvs->vs_isr |= VTCFG_ISR_QUEUES;\n\t\tpci_generate_msi(vs->vs_pi, 0);\n\t\tpci_lintr_assert(vs->vs_pi);\n\t\tVS_UNLOCK(vs);\n\t}\n}\n\nstruct iovec;\nvoid vi_softc_linkup(struct virtio_softc *vs, struct virtio_consts *vc,\n\tvoid *dev_softc, struct pci_devinst *pi, struct vqueue_info *queues);\nint vi_intr_init(struct virtio_softc *vs, int barnum, int use_msix);\nvoid vi_reset_dev(struct virtio_softc *);\nvoid vi_set_io_bar(struct virtio_softc *, int);\nint vq_getchain(struct vqueue_info *vq, uint16_t *pidx, struct iovec *iov,\n\tint n_iov, uint16_t *flags);\nvoid vq_retchain(struct vqueue_info *vq);\nvoid vq_relchain(struct vqueue_info *vq, uint16_t idx, uint32_t iolen);\nvoid vq_endchains(struct vqueue_info *vq, int used_all_avail);\nuint64_t vi_pci_read(int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size);\nvoid vi_pci_write(int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset,\n\tint size, uint64_t value);\n"
  },
  {
    "path": "include/xhyve/vmm/intel/vmcs.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <Hypervisor/hv.h>\n#include <Hypervisor/hv_vmx.h>\n#include <xhyve/vmm/vmm.h>\n\nint\tvmcs_getreg(int vcpuid, int ident, uint64_t *rv);\nint\tvmcs_setreg(int vcpuid, int ident, uint64_t val);\nint\tvmcs_getdesc(int vcpuid, int ident, struct seg_desc *desc);\nint\tvmcs_setdesc(int vcpuid, int ident, struct seg_desc *desc);\n\nstatic __inline uint64_t\nvmcs_read(int vcpuid, uint32_t encoding)\n{\n\tuint64_t val;\n\n\thv_vmx_vcpu_read_vmcs(((hv_vcpuid_t) vcpuid), encoding, &val);\n\treturn (val);\n}\n\nstatic __inline void\nvmcs_write(int vcpuid, uint32_t encoding, uint64_t val)\n{\n\tif (encoding == 0x00004002) {\n\t\tif (val == 0x0000000000000004) {\n\t\t\tabort();\n\t\t}\n\t}\n\thv_vmx_vcpu_write_vmcs(((hv_vcpuid_t) vcpuid), encoding, val);\n}\n\n#define\tvmexit_instruction_length(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_EXIT_INSTRUCTION_LENGTH)\n#define\tvmcs_guest_rip(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_GUEST_RIP)\n#define\tvmcs_instruction_error(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_INSTRUCTION_ERROR)\n#define\tvmcs_exit_reason(vcpuid) \\\n\t(vmcs_read(vcpuid, VMCS_EXIT_REASON) & 0xffff)\n#define\tvmcs_exit_qualification(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_EXIT_QUALIFICATION)\n#define\tvmcs_guest_cr3(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_GUEST_CR3)\n#define\tvmcs_gpa(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_GUEST_PHYSICAL_ADDRESS)\n#define\tvmcs_gla(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_GUEST_LINEAR_ADDRESS)\n#define\tvmcs_idt_vectoring_info(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_IDT_VECTORING_INFO)\n#define\tvmcs_idt_vectoring_err(vcpuid) \\\n\tvmcs_read(vcpuid, VMCS_IDT_VECTORING_ERROR)\n\n#define\tVMCS_INITIAL\t\t\t0xffffffffffffffff\n\n#define\tVMCS_IDENT(encoding) ((int) (((unsigned) (encoding)) | 0x80000000))\n/*\n * VMCS field encodings from Appendix H, Intel Architecture Manual Vol3B.\n */\n#define\tVMCS_INVALID_ENCODING\t\t0xffffffff\n\n/* 16-bit control fields */\n#define\tVMCS_VPID\t\t\t0x00000000\n#define\tVMCS_PIR_VECTOR\t\t\t0x00000002\n\n/* 16-bit guest-state fields */\n#define\tVMCS_GUEST_ES_SELECTOR\t\t0x00000800\n#define\tVMCS_GUEST_CS_SELECTOR\t\t0x00000802\n#define\tVMCS_GUEST_SS_SELECTOR\t\t0x00000804\n#define\tVMCS_GUEST_DS_SELECTOR\t\t0x00000806\n#define\tVMCS_GUEST_FS_SELECTOR\t\t0x00000808\n#define\tVMCS_GUEST_GS_SELECTOR\t\t0x0000080A\n#define\tVMCS_GUEST_LDTR_SELECTOR\t0x0000080C\n#define\tVMCS_GUEST_TR_SELECTOR\t\t0x0000080E\n#define\tVMCS_GUEST_INTR_STATUS\t\t0x00000810\n\n/* 16-bit host-state fields */\n#define\tVMCS_HOST_ES_SELECTOR\t\t0x00000C00\n#define\tVMCS_HOST_CS_SELECTOR\t\t0x00000C02\n#define\tVMCS_HOST_SS_SELECTOR\t\t0x00000C04\n#define\tVMCS_HOST_DS_SELECTOR\t\t0x00000C06\n#define\tVMCS_HOST_FS_SELECTOR\t\t0x00000C08\n#define\tVMCS_HOST_GS_SELECTOR\t\t0x00000C0A\n#define\tVMCS_HOST_TR_SELECTOR\t\t0x00000C0C\n\n/* 64-bit control fields */\n#define\tVMCS_IO_BITMAP_A\t\t0x00002000\n#define\tVMCS_IO_BITMAP_B\t\t0x00002002\n#define\tVMCS_MSR_BITMAP\t\t\t0x00002004\n#define\tVMCS_EXIT_MSR_STORE\t\t0x00002006\n#define\tVMCS_EXIT_MSR_LOAD\t\t0x00002008\n#define\tVMCS_ENTRY_MSR_LOAD\t\t0x0000200A\n#define\tVMCS_EXECUTIVE_VMCS\t\t0x0000200C\n#define\tVMCS_TSC_OFFSET\t\t\t0x00002010\n#define\tVMCS_VIRTUAL_APIC\t\t0x00002012\n#define\tVMCS_APIC_ACCESS\t\t0x00002014\n#define\tVMCS_PIR_DESC\t\t\t0x00002016\n#define\tVMCS_EPTP\t\t\t0x0000201A\n#define\tVMCS_EOI_EXIT0\t\t\t0x0000201C\n#define\tVMCS_EOI_EXIT1\t\t\t0x0000201E\n#define\tVMCS_EOI_EXIT2\t\t\t0x00002020\n#define\tVMCS_EOI_EXIT3\t\t\t0x00002022\n#define\tVMCS_EOI_EXIT(vector)\t\t(VMCS_EOI_EXIT0 + ((vector) / 64) * 2)\n\n/* 64-bit read-only fields */\n#define\tVMCS_GUEST_PHYSICAL_ADDRESS\t0x00002400\n\n/* 64-bit guest-state fields */\n#define\tVMCS_LINK_POINTER\t\t0x00002800\n#define\tVMCS_GUEST_IA32_DEBUGCTL\t0x00002802\n#define\tVMCS_GUEST_IA32_PAT\t\t0x00002804\n#define\tVMCS_GUEST_IA32_EFER\t\t0x00002806\n#define\tVMCS_GUEST_IA32_PERF_GLOBAL_CTRL 0x00002808\n#define\tVMCS_GUEST_PDPTE0\t\t0x0000280A\n#define\tVMCS_GUEST_PDPTE1\t\t0x0000280C\n#define\tVMCS_GUEST_PDPTE2\t\t0x0000280E\n#define\tVMCS_GUEST_PDPTE3\t\t0x00002810\n\n/* 64-bit host-state fields */\n#define\tVMCS_HOST_IA32_PAT\t\t0x00002C00\n#define\tVMCS_HOST_IA32_EFER\t\t0x00002C02\n#define\tVMCS_HOST_IA32_PERF_GLOBAL_CTRL\t0x00002C04\n\n/* 32-bit control fields */\n#define\tVMCS_PIN_BASED_CTLS\t\t0x00004000\n#define\tVMCS_PRI_PROC_BASED_CTLS\t0x00004002\n#define\tVMCS_EXCEPTION_BITMAP\t\t0x00004004\n#define\tVMCS_PF_ERROR_MASK\t\t0x00004006\n#define\tVMCS_PF_ERROR_MATCH\t\t0x00004008\n#define\tVMCS_CR3_TARGET_COUNT\t\t0x0000400A\n#define\tVMCS_EXIT_CTLS\t\t\t0x0000400C\n#define\tVMCS_EXIT_MSR_STORE_COUNT\t0x0000400E\n#define\tVMCS_EXIT_MSR_LOAD_COUNT\t0x00004010\n#define\tVMCS_ENTRY_CTLS\t\t\t0x00004012\n#define\tVMCS_ENTRY_MSR_LOAD_COUNT\t0x00004014\n#define\tVMCS_ENTRY_INTR_INFO\t\t0x00004016\n#define\tVMCS_ENTRY_EXCEPTION_ERROR\t0x00004018\n#define\tVMCS_ENTRY_INST_LENGTH\t\t0x0000401A\n#define\tVMCS_TPR_THRESHOLD\t\t0x0000401C\n#define\tVMCS_SEC_PROC_BASED_CTLS\t0x0000401E\n#define\tVMCS_PLE_GAP\t\t\t0x00004020\n#define\tVMCS_PLE_WINDOW\t\t\t0x00004022\n\n/* 32-bit read-only data fields */\n#define\tVMCS_INSTRUCTION_ERROR\t\t0x00004400\n#define\tVMCS_EXIT_REASON\t\t0x00004402\n#define\tVMCS_EXIT_INTR_INFO\t\t0x00004404\n#define\tVMCS_EXIT_INTR_ERRCODE\t\t0x00004406\n#define\tVMCS_IDT_VECTORING_INFO\t\t0x00004408\n#define\tVMCS_IDT_VECTORING_ERROR\t0x0000440A\n#define\tVMCS_EXIT_INSTRUCTION_LENGTH\t0x0000440C\n#define\tVMCS_EXIT_INSTRUCTION_INFO\t0x0000440E\n\n/* 32-bit guest-state fields */\n#define\tVMCS_GUEST_ES_LIMIT\t\t0x00004800\n#define\tVMCS_GUEST_CS_LIMIT\t\t0x00004802\n#define\tVMCS_GUEST_SS_LIMIT\t\t0x00004804\n#define\tVMCS_GUEST_DS_LIMIT\t\t0x00004806\n#define\tVMCS_GUEST_FS_LIMIT\t\t0x00004808\n#define\tVMCS_GUEST_GS_LIMIT\t\t0x0000480A\n#define\tVMCS_GUEST_LDTR_LIMIT\t\t0x0000480C\n#define\tVMCS_GUEST_TR_LIMIT\t\t0x0000480E\n#define\tVMCS_GUEST_GDTR_LIMIT\t\t0x00004810\n#define\tVMCS_GUEST_IDTR_LIMIT\t\t0x00004812\n#define\tVMCS_GUEST_ES_ACCESS_RIGHTS\t0x00004814\n#define\tVMCS_GUEST_CS_ACCESS_RIGHTS\t0x00004816\n#define\tVMCS_GUEST_SS_ACCESS_RIGHTS\t0x00004818\n#define\tVMCS_GUEST_DS_ACCESS_RIGHTS\t0x0000481A\n#define\tVMCS_GUEST_FS_ACCESS_RIGHTS\t0x0000481C\n#define\tVMCS_GUEST_GS_ACCESS_RIGHTS\t0x0000481E\n#define\tVMCS_GUEST_LDTR_ACCESS_RIGHTS\t0x00004820\n#define\tVMCS_GUEST_TR_ACCESS_RIGHTS\t0x00004822\n#define\tVMCS_GUEST_INTERRUPTIBILITY\t0x00004824\n#define\tVMCS_GUEST_ACTIVITY\t\t0x00004826\n#define VMCS_GUEST_SMBASE\t\t0x00004828\n#define\tVMCS_GUEST_IA32_SYSENTER_CS\t0x0000482A\n#define\tVMCS_PREEMPTION_TIMER_VALUE\t0x0000482E\n\n/* 32-bit host state fields */\n#define\tVMCS_HOST_IA32_SYSENTER_CS\t0x00004C00\n\n/* Natural Width control fields */\n#define\tVMCS_CR0_MASK\t\t\t0x00006000\n#define\tVMCS_CR4_MASK\t\t\t0x00006002\n#define\tVMCS_CR0_SHADOW\t\t\t0x00006004\n#define\tVMCS_CR4_SHADOW\t\t\t0x00006006\n#define\tVMCS_CR3_TARGET0\t\t0x00006008\n#define\tVMCS_CR3_TARGET1\t\t0x0000600A\n#define\tVMCS_CR3_TARGET2\t\t0x0000600C\n#define\tVMCS_CR3_TARGET3\t\t0x0000600E\n\n/* Natural Width read-only fields */\n#define\tVMCS_EXIT_QUALIFICATION\t\t0x00006400\n#define\tVMCS_IO_RCX\t\t\t0x00006402\n#define\tVMCS_IO_RSI\t\t\t0x00006404\n#define\tVMCS_IO_RDI\t\t\t0x00006406\n#define\tVMCS_IO_RIP\t\t\t0x00006408\n#define\tVMCS_GUEST_LINEAR_ADDRESS\t0x0000640A\n\n/* Natural Width guest-state fields */\n#define\tVMCS_GUEST_CR0\t\t\t0x00006800\n#define\tVMCS_GUEST_CR3\t\t\t0x00006802\n#define\tVMCS_GUEST_CR4\t\t\t0x00006804\n#define\tVMCS_GUEST_ES_BASE\t\t0x00006806\n#define\tVMCS_GUEST_CS_BASE\t\t0x00006808\n#define\tVMCS_GUEST_SS_BASE\t\t0x0000680A\n#define\tVMCS_GUEST_DS_BASE\t\t0x0000680C\n#define\tVMCS_GUEST_FS_BASE\t\t0x0000680E\n#define\tVMCS_GUEST_GS_BASE\t\t0x00006810\n#define\tVMCS_GUEST_LDTR_BASE\t\t0x00006812\n#define\tVMCS_GUEST_TR_BASE\t\t0x00006814\n#define\tVMCS_GUEST_GDTR_BASE\t\t0x00006816\n#define\tVMCS_GUEST_IDTR_BASE\t\t0x00006818\n#define\tVMCS_GUEST_DR7\t\t\t0x0000681A\n#define\tVMCS_GUEST_RSP\t\t\t0x0000681C\n#define\tVMCS_GUEST_RIP\t\t\t0x0000681E\n#define\tVMCS_GUEST_RFLAGS\t\t0x00006820\n#define\tVMCS_GUEST_PENDING_DBG_EXCEPTIONS 0x00006822\n#define\tVMCS_GUEST_IA32_SYSENTER_ESP\t0x00006824\n#define\tVMCS_GUEST_IA32_SYSENTER_EIP\t0x00006826\n\n/* Natural Width host-state fields */\n#define\tVMCS_HOST_CR0\t\t\t0x00006C00\n#define\tVMCS_HOST_CR3\t\t\t0x00006C02\n#define\tVMCS_HOST_CR4\t\t\t0x00006C04\n#define\tVMCS_HOST_FS_BASE\t\t0x00006C06\n#define\tVMCS_HOST_GS_BASE\t\t0x00006C08\n#define\tVMCS_HOST_TR_BASE\t\t0x00006C0A\n#define\tVMCS_HOST_GDTR_BASE\t\t0x00006C0C\n#define\tVMCS_HOST_IDTR_BASE\t\t0x00006C0E\n#define\tVMCS_HOST_IA32_SYSENTER_ESP\t0x00006C10\n#define\tVMCS_HOST_IA32_SYSENTER_EIP\t0x00006C12\n#define\tVMCS_HOST_RSP\t\t\t0x00006C14\n#define\tVMCS_HOST_RIP\t\t\t0x00006c16\n\n/*\n * VM instruction error numbers\n */\n#define\tVMRESUME_WITH_NON_LAUNCHED_VMCS\t5\n\n/*\n * VMCS exit reasons\n */\n#define EXIT_REASON_EXCEPTION\t\t0\n#define EXIT_REASON_EXT_INTR\t\t1\n#define EXIT_REASON_TRIPLE_FAULT\t2\n#define EXIT_REASON_INIT\t\t3\n#define EXIT_REASON_SIPI\t\t4\n#define EXIT_REASON_IO_SMI\t\t5\n#define EXIT_REASON_SMI\t\t\t6\n#define EXIT_REASON_INTR_WINDOW\t\t7\n#define EXIT_REASON_NMI_WINDOW\t\t8\n#define EXIT_REASON_TASK_SWITCH\t\t9\n#define EXIT_REASON_CPUID\t\t10\n#define EXIT_REASON_GETSEC\t\t11\n#define EXIT_REASON_HLT\t\t\t12\n#define EXIT_REASON_INVD\t\t13\n#define EXIT_REASON_INVLPG\t\t14\n#define EXIT_REASON_RDPMC\t\t15\n#define EXIT_REASON_RDTSC\t\t16\n#define EXIT_REASON_RSM\t\t\t17\n#define EXIT_REASON_VMCALL\t\t18\n#define EXIT_REASON_VMCLEAR\t\t19\n#define EXIT_REASON_VMLAUNCH\t\t20\n#define EXIT_REASON_VMPTRLD\t\t21\n#define EXIT_REASON_VMPTRST\t\t22\n#define EXIT_REASON_VMREAD\t\t23\n#define EXIT_REASON_VMRESUME\t\t24\n#define EXIT_REASON_VMWRITE\t\t25\n#define EXIT_REASON_VMXOFF\t\t26\n#define EXIT_REASON_VMXON\t\t27\n#define EXIT_REASON_CR_ACCESS\t\t28\n#define EXIT_REASON_DR_ACCESS\t\t29\n#define EXIT_REASON_INOUT\t\t30\n#define EXIT_REASON_RDMSR\t\t31\n#define EXIT_REASON_WRMSR\t\t32\n#define EXIT_REASON_INVAL_VMCS\t\t33\n#define EXIT_REASON_INVAL_MSR\t\t34\n#define EXIT_REASON_MWAIT\t\t36\n#define EXIT_REASON_MTF\t\t\t37\n#define EXIT_REASON_MONITOR\t\t39\n#define EXIT_REASON_PAUSE\t\t40\n#define EXIT_REASON_MCE_DURING_ENTRY\t41\n#define EXIT_REASON_TPR\t\t\t43\n#define EXIT_REASON_APIC_ACCESS\t\t44\n#define\tEXIT_REASON_VIRTUALIZED_EOI\t45\n#define EXIT_REASON_GDTR_IDTR\t\t46\n#define EXIT_REASON_LDTR_TR\t\t47\n#define EXIT_REASON_EPT_FAULT\t\t48\n#define EXIT_REASON_EPT_MISCONFIG\t49\n#define EXIT_REASON_INVEPT\t\t50\n#define EXIT_REASON_RDTSCP\t\t51\n#define EXIT_REASON_VMX_PREEMPT\t\t52\n#define EXIT_REASON_INVVPID\t\t53\n#define EXIT_REASON_WBINVD\t\t54\n#define EXIT_REASON_XSETBV\t\t55\n#define\tEXIT_REASON_APIC_WRITE\t\t56\n\n/*\n * NMI unblocking due to IRET.\n *\n * Applies to VM-exits due to hardware exception or EPT fault.\n */\n#define\tEXIT_QUAL_NMIUDTI\t(1U << 12)\n/*\n * VMCS interrupt information fields\n */\n#define\tVMCS_INTR_VALID\t\t(1U << 31)\n#define\tVMCS_INTR_T_MASK\t0x700U\t\t/* Interruption-info type */\n#define\tVMCS_INTR_T_HWINTR\t(0U << 8)\n#define\tVMCS_INTR_T_NMI\t\t(2U << 8)\n#define\tVMCS_INTR_T_HWEXCEPTION\t(3U << 8)\n#define\tVMCS_INTR_T_SWINTR\t(4U << 8)\n#define\tVMCS_INTR_T_PRIV_SWEXCEPTION (5U << 8)\n#define\tVMCS_INTR_T_SWEXCEPTION\t(6U << 8)\n#define\tVMCS_INTR_DEL_ERRCODE\t(1U << 11)\n\n/*\n * VMCS IDT-Vectoring information fields\n */\n#define\tVMCS_IDT_VEC_VALID\t\t(1U << 31)\n#define\tVMCS_IDT_VEC_ERRCODE_VALID\t(1U << 11)\n\n/*\n * VMCS Guest interruptibility field\n */\n#define\tVMCS_INTERRUPTIBILITY_STI_BLOCKING\t(1U << 0)\n#define\tVMCS_INTERRUPTIBILITY_MOVSS_BLOCKING\t(1U << 1)\n#define\tVMCS_INTERRUPTIBILITY_SMI_BLOCKING\t(1U << 2)\n#define\tVMCS_INTERRUPTIBILITY_NMI_BLOCKING\t(1U << 3)\n\n/*\n * Exit qualification for EXIT_REASON_INVAL_VMCS\n */\n#define\tEXIT_QUAL_NMI_WHILE_STI_BLOCKING\t3\n\n/*\n * Exit qualification for EPT violation\n */\n#define\tEPT_VIOLATION_DATA_READ\t\t(1UL << 0)\n#define\tEPT_VIOLATION_DATA_WRITE\t(1UL << 1)\n#define\tEPT_VIOLATION_INST_FETCH\t(1UL << 2)\n#define\tEPT_VIOLATION_GPA_READABLE\t(1UL << 3)\n#define\tEPT_VIOLATION_GPA_WRITEABLE\t(1UL << 4)\n#define\tEPT_VIOLATION_GPA_EXECUTABLE\t(1UL << 5)\n#define\tEPT_VIOLATION_GLA_VALID\t\t(1UL << 7)\n#define\tEPT_VIOLATION_XLAT_VALID\t(1UL << 8)\n\n/*\n * Exit qualification for APIC-access VM exit\n */\n#define\tAPIC_ACCESS_OFFSET(qual)\t((qual) & 0xFFF)\n#define\tAPIC_ACCESS_TYPE(qual)\t\t(((qual) >> 12) & 0xF)\n\n/*\n * Exit qualification for APIC-write VM exit\n */\n#define\tAPIC_WRITE_OFFSET(qual)\t\t((qual) & 0xFFF)\n"
  },
  {
    "path": "include/xhyve/vmm/intel/vmx.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stddef.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/intel/vmcs.h>\n\nstruct vmxcap {\n\tint\tset;\n\tuint32_t proc_ctls;\n\tuint32_t proc_ctls2;\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vmxstate {\n\tuint64_t nextrip;\t/* next instruction to be executed by guest */\n\tint\tlastcpu;\t/* host cpu that this 'vcpu' last ran on */\n\tuint16_t vpid;\n    uint32_t entry_ctls;\n};\n#pragma clang diagnostic pop\n\nstruct apic_page {\n\tuint32_t reg[XHYVE_PAGE_SIZE / 4];\n};\nCTASSERT(sizeof(struct apic_page) == XHYVE_PAGE_SIZE);\n\n/* Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM) */\nstruct pir_desc {\n\tuint64_t\tpir[4];\n\tuint64_t\tpending;\n\tuint64_t\tunused[3];\n} __aligned(64);\nCTASSERT(sizeof(struct pir_desc) == 64);\n\n/* Index into the 'guest_msrs[]' array */\nenum {\n\tIDX_MSR_LSTAR,\n\tIDX_MSR_CSTAR,\n\tIDX_MSR_STAR,\n\tIDX_MSR_SF_MASK,\n\tIDX_MSR_KGSBASE,\n\tIDX_MSR_PAT,\n\tGUEST_MSR_NUM\t\t/* must be the last enumeration */\n};\n\n/* virtual machine softc */\nstruct vmx {\n\tstruct apic_page apic_page[VM_MAXCPU]; /* one apic page per vcpu */\n\tuint64_t guest_msrs[VM_MAXCPU][GUEST_MSR_NUM];\n\tstruct vmxcap cap[VM_MAXCPU];\n\tstruct vmxstate state[VM_MAXCPU];\n\tstruct vm *vm;\n};\n\n#define\tVMX_GUEST_VMEXIT\t0\n#define\tVMX_VMRESUME_ERROR\t1\n#define\tVMX_VMLAUNCH_ERROR\t2\n#define\tVMX_INVEPT_ERROR\t3\nvoid\tvmx_call_isr(uintptr_t entry);\n\nu_long\tvmx_fix_cr0(u_long cr0);\nu_long\tvmx_fix_cr4(u_long cr4);\n\nextern char\tvmx_exit_guest[];\n"
  },
  {
    "path": "include/xhyve/vmm/intel/vmx_controls.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n/* Pin-Based VM-Execution Controls */\n#define\tPINBASED_EXTINT_EXITING\t\t(1u << 0)\n#define\tPINBASED_NMI_EXITING\t\t(1u << 3)\n#define\tPINBASED_VIRTUAL_NMI\t\t(1u << 5)\n#define\tPINBASED_PREMPTION_TIMER\t(1u << 6)\n#define\tPINBASED_POSTED_INTERRUPT\t(1u << 7)\n\n/* Primary Processor-Based VM-Execution Controls */\n#define\tPROCBASED_INT_WINDOW_EXITING\t(1u << 2)\n#define\tPROCBASED_TSC_OFFSET\t\t(1u << 3)\n#define\tPROCBASED_HLT_EXITING\t\t(1u << 7)\n#define\tPROCBASED_INVLPG_EXITING\t(1u << 9)\n#define\tPROCBASED_MWAIT_EXITING\t\t(1u << 10)\n#define\tPROCBASED_RDPMC_EXITING\t\t(1u << 11)\n#define\tPROCBASED_RDTSC_EXITING\t\t(1u << 12)\n#define\tPROCBASED_CR3_LOAD_EXITING\t(1u << 15)\n#define\tPROCBASED_CR3_STORE_EXITING\t(1u << 16)\n#define\tPROCBASED_CR8_LOAD_EXITING\t(1u << 19)\n#define\tPROCBASED_CR8_STORE_EXITING\t(1u << 20)\n#define\tPROCBASED_USE_TPR_SHADOW\t(1u << 21)\n#define\tPROCBASED_NMI_WINDOW_EXITING\t(1u << 22)\n#define PROCBASED_MOV_DR_EXITING\t(1u << 23)\n#define\tPROCBASED_IO_EXITING\t\t(1u << 24)\n#define\tPROCBASED_IO_BITMAPS\t\t(1u << 25)\n#define\tPROCBASED_MTF\t\t\t(1u << 27)\n#define\tPROCBASED_MSR_BITMAPS\t\t(1u << 28)\n#define\tPROCBASED_MONITOR_EXITING\t(1u << 29)\n#define\tPROCBASED_PAUSE_EXITING\t\t(1u << 30)\n#define\tPROCBASED_SECONDARY_CONTROLS\t(1U << 31)\n\n/* Secondary Processor-Based VM-Execution Controls */\n#define\tPROCBASED2_VIRTUALIZE_APIC_ACCESSES\t(1u << 0)\n#define\tPROCBASED2_ENABLE_EPT\t\t\t(1u << 1)\n#define\tPROCBASED2_DESC_TABLE_EXITING\t\t(1u << 2)\n#define\tPROCBASED2_ENABLE_RDTSCP\t\t(1u << 3)\n#define\tPROCBASED2_VIRTUALIZE_X2APIC_MODE\t(1u << 4)\n#define\tPROCBASED2_ENABLE_VPID\t\t\t(1u << 5)\n#define\tPROCBASED2_WBINVD_EXITING\t\t(1u << 6)\n#define\tPROCBASED2_UNRESTRICTED_GUEST\t\t(1u << 7)\n#define\tPROCBASED2_APIC_REGISTER_VIRTUALIZATION\t(1u << 8)\n#define\tPROCBASED2_VIRTUAL_INTERRUPT_DELIVERY\t(1u << 9)\n#define\tPROCBASED2_PAUSE_LOOP_EXITING\t\t(1u << 10)\n#define\tPROCBASED2_RDRAND_EXITING\t\t(1u << 11)\n#define\tPROCBASED2_ENABLE_INVPCID\t\t(1u << 12)\n#define\tPROCBASED2_VMCS_SHADOW\t\t\t(1u << 14)\n#define\tPROCBASED2_RDSEED_EXITING\t\t(1u << 16)\n#define\tPROCBASED2_ENABLE_XSAVES_XRSTORS\t(1u << 20)\n\n/* VM Exit Controls */\n#define\tVM_EXIT_SAVE_DEBUG_CONTROLS\t(1u << 2)\n#define\tVM_EXIT_HOST_LMA\t\t(1u << 9)\n#define\tVM_EXIT_LOAD_PERF_GLOBAL_CTRL\t(1u << 12)\n#define\tVM_EXIT_ACKNOWLEDGE_INTERRUPT\t(1u << 15)\n#define\tVM_EXIT_SAVE_PAT\t\t(1u << 18)\n#define\tVM_EXIT_LOAD_PAT\t\t(1u << 19)\n#define\tVM_EXIT_SAVE_EFER\t\t(1u << 20)\n#define\tVM_EXIT_LOAD_EFER\t\t(1u << 21)\n#define\tVM_EXIT_SAVE_PREEMPTION_TIMER\t(1u << 22)\n\n/* VM Entry Controls */\n#define\tVM_ENTRY_LOAD_DEBUG_CONTROLS\t(1u << 2)\n#define\tVM_ENTRY_GUEST_LMA\t\t(1u << 9)\n#define\tVM_ENTRY_INTO_SMM\t\t(1u << 10)\n#define\tVM_ENTRY_DEACTIVATE_DUAL_MONITOR (1u << 11)\n#define\tVM_ENTRY_LOAD_PERF_GLOBAL_CTRL\t(1u << 13)\n#define\tVM_ENTRY_LOAD_PAT\t\t(1u << 14)\n#define\tVM_ENTRY_LOAD_EFER\t\t(1u << 15)\n"
  },
  {
    "path": "include/xhyve/vmm/intel/vmx_msr.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <Hypervisor/hv.h>\n#include <Hypervisor/hv_vmx.h>\n#include <xhyve/support/misc.h>\n\nstruct vmx;\n\nvoid vmx_msr_init(void);\nvoid vmx_msr_guest_init(struct vmx *vmx, int vcpuid);\nint vmx_rdmsr(struct vmx *, int vcpuid, u_int num, uint64_t *val);\nint vmx_wrmsr(struct vmx *, int vcpuid, u_int num, uint64_t val);\n\nint vmx_set_ctlreg(int vcpu_id, uint32_t field, hv_vmx_capability_t cap_field, uint32_t ones_mask,\n\t\t\t\t   uint32_t zeros_mask, uint32_t *retval);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vatpic.h",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <xhyve/vmm/vmm.h>\n\n#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */\n#define IO_ICU2 0x0a0 /* 8259A Interrupt Controller #2 */\n\n#define ICU_IMR_OFFSET 1\n\n#define IO_ELCR1 0x4d0\n#define IO_ELCR2 0x4d1\n\nstruct vatpic *vatpic_init(struct vm *vm);\nvoid vatpic_cleanup(struct vatpic *vatpic);\n\nint vatpic_master_handler(struct vm *vm, int vcpuid, bool in, int port,\n    int bytes, uint32_t *eax);\nint vatpic_slave_handler(struct vm *vm, int vcpuid, bool in, int port,\n    int bytes, uint32_t *eax);\nint vatpic_elc_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,\n    uint32_t *eax);\n\nint vatpic_assert_irq(struct vm *vm, int irq);\nint vatpic_deassert_irq(struct vm *vm, int irq);\nint vatpic_pulse_irq(struct vm *vm, int irq);\nint vatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger);\n\nvoid vatpic_pending_intr(struct vm *vm, int *vecptr);\nvoid vatpic_intr_accepted(struct vm *vm, int vector);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vatpit.h",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n\n//#include <machine/timerreg.h>\n\n#define\tNMISC_PORT\t0x61\n\nstruct vm;\nstruct vatpit;\n\nstruct vatpit *vatpit_init(struct vm *vm);\nvoid vatpit_cleanup(struct vatpit *vatpit);\n\nint vatpit_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,\n\tuint32_t *eax);\nint vatpit_nmisc_handler(struct vm *vm, int vcpuid, bool in, int port,\n\tint bytes, uint32_t *eax);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vhpet.h",
    "content": "/*-\n * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n#define VHPET_BASE 0xfed00000\n#define VHPET_SIZE 0x400\n\nstruct vm;\nstruct vhpet;\n\nstruct vhpet *vhpet_init(struct vm *vm);\nvoid vhpet_cleanup(struct vhpet *vhpet);\nint vhpet_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t val,\n\tint size, void *arg);\nint vhpet_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *val,\n\tint size, void *arg);\nint vhpet_getcap(uint32_t *cap);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vioapic.h",
    "content": "/*-\n * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n#define VIOAPIC_BASE 0xfec00000\n#define VIOAPIC_SIZE 0x1000\n\nstruct vm;\nstruct vioapic;\n\nstruct vioapic *vioapic_init(struct vm *vm);\nvoid vioapic_cleanup(struct vioapic *vioapic);\n\nint vioapic_assert_irq(struct vm *vm, int irq);\nint vioapic_deassert_irq(struct vm *vm, int irq);\nint vioapic_pulse_irq(struct vm *vm, int irq);\n\nint vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa,\n\tuint64_t wval, int size, void *arg);\nint vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa,\n\tuint64_t *rval, int size, void *arg);\n\nint vioapic_pincount(struct vm *vm);\nvoid vioapic_process_eoi(struct vm *vm, int vcpuid, int vector);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vlapic.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <xhyve/vmm/vmm.h>\n\nstruct vm;\n\nint vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset,\n    uint64_t data, bool *retu);\nint vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset,\n    uint64_t *data, bool *retu);\n\n/*\n * Returns 0 if there is no eligible vector that can be delivered to the\n * guest at this time and non-zero otherwise.\n *\n * If an eligible vector number is found and 'vecptr' is not NULL then it will\n * be stored in the location pointed to by 'vecptr'.\n *\n * Note that the vector does not automatically transition to the ISR as a\n * result of calling this function.\n */\nint vlapic_pending_intr(struct vlapic *vlapic, int *vecptr);\n\n/*\n * Transition 'vector' from IRR to ISR. This function is called with the\n * vector returned by 'vlapic_pending_intr()' when the guest is able to\n * accept this interrupt (i.e. RFLAGS.IF = 1 and no conditions exist that\n * block interrupt delivery).\n */\nvoid vlapic_intr_accepted(struct vlapic *vlapic, int vector);\n\n/*\n * Returns 1 if the vcpu needs to be notified of the interrupt and 0 otherwise.\n */\nint vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level);\n\n/*\n * Post an interrupt to the vcpu running on 'hostcpu'. This will use a\n * hardware assist if available (e.g. Posted Interrupt) or fall back to\n * sending an 'ipinum' to interrupt the 'hostcpu'.\n */\nvoid vlapic_post_intr(struct vlapic *vlapic, int hostcpu, int ipinum);\n\nvoid vlapic_set_error(struct vlapic *vlapic, uint32_t mask);\nvoid vlapic_fire_cmci(struct vlapic *vlapic);\nint vlapic_trigger_lvt(struct vlapic *vlapic, int vector);\n\nuint64_t vlapic_get_apicbase(struct vlapic *vlapic);\nint vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val);\nvoid vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state s);\nbool vlapic_enabled(struct vlapic *vlapic);\n\nvoid vlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys,\n    int delmode, int vec);\n\n/* Reset the trigger-mode bits for all vectors to be edge-triggered */\nvoid vlapic_reset_tmr(struct vlapic *vlapic);\n\n/*\n * Set the trigger-mode bit associated with 'vector' to level-triggered if\n * the (dest,phys,delmode) tuple resolves to an interrupt being delivered to\n * this 'vlapic'.\n */\nvoid vlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys,\n    int delmode, int vector);\n\nvoid vlapic_set_cr8(struct vlapic *vlapic, uint64_t val);\nuint64_t vlapic_get_cr8(struct vlapic *vlapic);\n\n/* APIC write handlers */\nvoid vlapic_id_write_handler(struct vlapic *vlapic);\nvoid vlapic_ldr_write_handler(struct vlapic *vlapic);\nvoid vlapic_dfr_write_handler(struct vlapic *vlapic);\nvoid vlapic_svr_write_handler(struct vlapic *vlapic);\nvoid vlapic_esr_write_handler(struct vlapic *vlapic);\nint vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu);\nvoid vlapic_icrtmr_write_handler(struct vlapic *vlapic);\nvoid vlapic_dcr_write_handler(struct vlapic *vlapic);\nvoid vlapic_lvt_write_handler(struct vlapic *vlapic, uint32_t offset);\nvoid vlapic_self_ipi_handler(struct vlapic *vlapic, uint64_t val);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vlapic_priv.h",
    "content": "/*-\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <xhyve/lock.h>\n#include <xhyve/support/apicreg.h>\n#include <xhyve/vmm/vmm_callout.h>\n\n/*\n * APIC Register:\t\tOffset\t   Description\n */\n#define APIC_OFFSET_ID\t\t0x20\t/* Local APIC ID\t\t*/\n#define APIC_OFFSET_VER\t\t0x30\t/* Local APIC Version\t\t*/\n#define APIC_OFFSET_TPR\t\t0x80\t/* Task Priority Register\t*/\n#define APIC_OFFSET_APR\t\t0x90\t/* Arbitration Priority\t\t*/\n#define APIC_OFFSET_PPR\t\t0xA0\t/* Processor Priority Register\t*/\n#define APIC_OFFSET_EOI\t\t0xB0\t/* EOI Register\t\t\t*/\n#define APIC_OFFSET_RRR\t\t0xC0\t/* Remote read\t\t\t*/\n#define APIC_OFFSET_LDR\t\t0xD0\t/* Logical Destination\t\t*/\n#define APIC_OFFSET_DFR\t\t0xE0\t/* Destination Format Register\t*/\n#define APIC_OFFSET_SVR\t\t0xF0\t/* Spurious Vector Register\t*/\n#define APIC_OFFSET_ISR0\t0x100\t/* In Service Register\t\t*/\n#define APIC_OFFSET_ISR1\t0x110\n#define APIC_OFFSET_ISR2\t0x120\n#define APIC_OFFSET_ISR3\t0x130\n#define APIC_OFFSET_ISR4\t0x140\n#define APIC_OFFSET_ISR5\t0x150\n#define APIC_OFFSET_ISR6\t0x160\n#define APIC_OFFSET_ISR7\t0x170\n#define APIC_OFFSET_TMR0\t0x180\t/* Trigger Mode Register\t*/\n#define APIC_OFFSET_TMR1\t0x190\n#define APIC_OFFSET_TMR2\t0x1A0\n#define APIC_OFFSET_TMR3\t0x1B0\n#define APIC_OFFSET_TMR4\t0x1C0\n#define APIC_OFFSET_TMR5\t0x1D0\n#define APIC_OFFSET_TMR6\t0x1E0\n#define APIC_OFFSET_TMR7\t0x1F0\n#define APIC_OFFSET_IRR0\t0x200\t/* Interrupt Request Register\t*/\n#define APIC_OFFSET_IRR1\t0x210\n#define APIC_OFFSET_IRR2\t0x220\n#define APIC_OFFSET_IRR3\t0x230\n#define APIC_OFFSET_IRR4\t0x240\n#define APIC_OFFSET_IRR5\t0x250\n#define APIC_OFFSET_IRR6\t0x260\n#define APIC_OFFSET_IRR7\t0x270\n#define APIC_OFFSET_ESR\t\t0x280\t/* Error Status Register\t*/\n#define APIC_OFFSET_CMCI_LVT\t0x2F0\t/* Local Vector Table (CMCI)\t*/\n#define APIC_OFFSET_ICR_LOW\t0x300\t/* Interrupt Command Register\t*/\n#define APIC_OFFSET_ICR_HI\t0x310\n#define APIC_OFFSET_TIMER_LVT\t0x320\t/* Local Vector Table (Timer)\t*/\n#define APIC_OFFSET_THERM_LVT\t0x330\t/* Local Vector Table (Thermal)\t*/\n#define APIC_OFFSET_PERF_LVT\t0x340\t/* Local Vector Table (PMC)\t*/\n#define APIC_OFFSET_LINT0_LVT\t0x350\t/* Local Vector Table (LINT0)\t*/\n#define APIC_OFFSET_LINT1_LVT\t0x360\t/* Local Vector Table (LINT1)\t*/\n#define APIC_OFFSET_ERROR_LVT\t0x370\t/* Local Vector Table (ERROR)\t*/\n#define APIC_OFFSET_TIMER_ICR\t0x380\t/* Timer's Initial Count\t*/\n#define APIC_OFFSET_TIMER_CCR\t0x390\t/* Timer's Current Count\t*/\n#define APIC_OFFSET_TIMER_DCR\t0x3E0\t/* Timer's Divide Configuration\t*/\n#define\tAPIC_OFFSET_SELF_IPI\t0x3F0\t/* Self IPI register */\n\n#define\tVLAPIC_CTR0(vlapic, format)\t\t\t\t\t\\\n\tVCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format)\n\n#define\tVLAPIC_CTR1(vlapic, format, p1)\t\t\t\t\t\\\n\tVCPU_CTR1((vlapic)->vm, (vlapic)->vcpuid, format, p1)\n\n#define\tVLAPIC_CTR2(vlapic, format, p1, p2)\t\t\t\t\\\n\tVCPU_CTR2((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2)\n\n#define\tVLAPIC_CTR3(vlapic, format, p1, p2, p3)\t\t\t\t\\\n\tVCPU_CTR3((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2, p3)\n\n#define\tVLAPIC_CTR_IRR(vlapic, msg) \\\ndo { \\\n\tuint32_t *x = &(vlapic)->apic_page->irr0; \\\n\tx[0] = x[0]; /* silence compiler */ \\\n\tVLAPIC_CTR1((vlapic), msg \" irr0 0x%08x\", x[0 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr1 0x%08x\", x[1 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr2 0x%08x\", x[2 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr3 0x%08x\", x[3 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr4 0x%08x\", x[4 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr5 0x%08x\", x[5 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr6 0x%08x\", x[6 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" irr7 0x%08x\", x[7 << 2]); \\\n} while (0)\n\n#define\tVLAPIC_CTR_ISR(vlapic, msg) \\\ndo { \\\n\tuint32_t *x = &(vlapic)->apic_page->isr0; \\\n\tx[0] = x[0]; /* silence compiler */ \\\n\tVLAPIC_CTR1((vlapic), msg \" isr0 0x%08x\", x[0 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr1 0x%08x\", x[1 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr2 0x%08x\", x[2 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr3 0x%08x\", x[3 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr4 0x%08x\", x[4 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr5 0x%08x\", x[5 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr6 0x%08x\", x[6 << 2]); \\\n\tVLAPIC_CTR1((vlapic), msg \" isr7 0x%08x\", x[7 << 2]); \\\n} while (0)\n\nenum boot_state {\n\tBS_INIT,\n\tBS_SIPI,\n\tBS_RUNNING\n};\n\n/*\n * 16 priority levels with at most one vector injected per level.\n */\n#define\tISRVEC_STK_SIZE\t\t(16 + 1)\n\n#define VLAPIC_MAXLVT_INDEX\tAPIC_LVT_CMCI\n\nstruct vlapic;\n\nstruct vlapic_ops {\n\tint (*set_intr_ready)(struct vlapic *vlapic, int vector, bool level);\n\tint (*pending_intr)(struct vlapic *vlapic, int *vecptr);\n\tvoid (*intr_accepted)(struct vlapic *vlapic, int vector);\n\tvoid (*post_intr)(struct vlapic *vlapic, int hostcpu);\n\tvoid (*set_tmr)(struct vlapic *vlapic, int vector, bool level);\n\tvoid (*enable_x2apic_mode)(struct vlapic *vlapic);\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vlapic {\n\tstruct vm *vm;\n\tint vcpuid;\n\tstruct LAPIC *apic_page;\n\tstruct vlapic_ops ops;\n\tuint32_t esr_pending;\n\tint esr_firing;\n\tstruct callout callout; /* vlapic timer */\n\tstruct bintime timer_fire_bt; /* callout expiry time */\n\tstruct bintime timer_freq_bt; /* timer frequency */\n\tstruct bintime timer_period_bt; /* timer period */\n\txhyve_lock_t timer_lock;\n\t/*\n\t * The 'isrvec_stk' is a stack of vectors injected by the local apic.\n\t * A vector is popped from the stack when the processor does an EOI.\n\t * The vector on the top of the stack is used to compute the\n\t * Processor Priority in conjunction with the TPR.\n\t */\n\tuint8_t isrvec_stk[ISRVEC_STK_SIZE];\n\tint isrvec_stk_top;\n\tuint64_t msr_apicbase;\n\tenum boot_state\tboot_state;\n\t/*\n\t * Copies of some registers in the virtual APIC page. We do this for\n\t * a couple of different reasons:\n\t * - to be able to detect what changed (e.g. svr_last)\n\t * - to maintain a coherent snapshot of the register (e.g. lvt_last)\n\t */\n\tuint32_t svr_last;\n\tuint32_t lvt_last[VLAPIC_MAXLVT_INDEX + 1];\n};\n#pragma clang diagnostic pop\n\nvoid vlapic_init(struct vlapic *vlapic);\nvoid vlapic_cleanup(struct vlapic *vlapic);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vpmtmr.h",
    "content": "/*-\n * Copyright (c) 2014 Neel Natu (neel@freebsd.org)\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n#define\tIO_PMTMR 0x408\n\nstruct vm;\nstruct vpmtmr;\n\nstruct vpmtmr *vpmtmr_init(struct vm *vm);\nvoid vpmtmr_cleanup(struct vpmtmr *pmtmr);\n\nint vpmtmr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,\n\tuint32_t *val);\n"
  },
  {
    "path": "include/xhyve/vmm/io/vrtc.h",
    "content": "/*-\n * Copyright (c) 2014 Neel Natu (neel@freebsd.org)\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <time.h>\n\n#define IO_RTC 0x070 /* 4990A RTC */\n\nstruct vm;\nstruct vrtc;\n\nstruct vrtc *vrtc_init(struct vm *vm);\nvoid vrtc_cleanup(struct vrtc *vrtc);\nvoid vrtc_reset(struct vrtc *vrtc);\n\ntime_t vrtc_get_time(struct vm *vm);\nint vrtc_set_time(struct vm *vm, time_t secs);\nint vrtc_nvram_write(struct vm *vm, int offset, uint8_t value);\nint vrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval);\n\nint vrtc_addr_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,\n\tuint32_t *val);\nint vrtc_data_handler(struct vm *vm, int vcpuid, bool in, int port, int bytes,\n\tuint32_t *val);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/cpuset.h>\n#include <xhyve/support/segments.h>\n#include <xhyve/vmm/vmm_common.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\n#define\tVM_INTINFO_VECTOR(info)\t((info) & 0xff)\n#define\tVM_INTINFO_DEL_ERRCODE\t0x800\n#define\tVM_INTINFO_RSVD\t\t0x7ffff000\n#define\tVM_INTINFO_VALID\t0x80000000\n#define\tVM_INTINFO_TYPE\t\t0x700\n#define\tVM_INTINFO_HWINTR\t(0 << 8)\n#define\tVM_INTINFO_NMI\t\t(2 << 8)\n#define\tVM_INTINFO_HWEXCEPTION\t(3 << 8)\n#define\tVM_INTINFO_SWINTR\t(4 << 8)\n\nstruct vm;\nstruct vm_exception;\nstruct vm_memory_segment;\nstruct seg_desc;\nstruct vm_exit;\nstruct vm_run;\nstruct vhpet;\nstruct vioapic;\nstruct vlapic;\nstruct vmspace;\nstruct vm_object;\nstruct vm_guest_paging;\nstruct pmap;\n\ntypedef int (*vmm_init_func_t)(void);\ntypedef int (*vmm_cleanup_func_t)(void);\ntypedef void *(*vmi_vm_init_func_t)(struct vm *vm);\ntypedef int (*vmi_vcpu_init_func_t)(void *vmi, int vcpu);\ntypedef int (*vmi_run_func_t)(void *vmi, int vcpu, register_t rip,\n\tvoid *rendezvous_cookie, void *suspend_cookie);\ntypedef void (*vmi_vm_cleanup_func_t)(void *vmi);\ntypedef void (*vmi_vcpu_cleanup_func_t)(void *vmi, int vcpu);\ntypedef int (*vmi_get_register_t)(void *vmi, int vcpu, int num,\n\tuint64_t *retval);\ntypedef int (*vmi_set_register_t)(void *vmi, int vcpu, int num,\n\tuint64_t val);\ntypedef int (*vmi_get_desc_t)(void *vmi, int vcpu, int num,\n\tstruct seg_desc *desc);\ntypedef int (*vmi_set_desc_t)(void *vmi, int vcpu, int num,\n\tstruct seg_desc *desc);\ntypedef int (*vmi_get_cap_t)(void *vmi, int vcpu, int num, int *retval);\ntypedef int (*vmi_set_cap_t)(void *vmi, int vcpu, int num, int val);\ntypedef struct vlapic * (*vmi_vlapic_init)(void *vmi, int vcpu);\ntypedef void (*vmi_vlapic_cleanup)(void *vmi, struct vlapic *vlapic);\ntypedef void (*vmi_interrupt)(int vcpu);\n\nstruct vmm_ops {\n\tvmm_init_func_t init; /* module wide initialization */\n\tvmm_cleanup_func_t cleanup;\n\tvmi_vm_init_func_t vm_init; /* vm-specific initialization */\n\tvmi_vcpu_init_func_t vcpu_init;\n\tvmi_run_func_t vmrun;\n\tvmi_vm_cleanup_func_t vm_cleanup;\n\tvmi_vcpu_cleanup_func_t vcpu_cleanup;\n\tvmi_get_register_t vmgetreg;\n\tvmi_set_register_t vmsetreg;\n\tvmi_get_desc_t vmgetdesc;\n\tvmi_set_desc_t vmsetdesc;\n\tvmi_get_cap_t vmgetcap;\n\tvmi_set_cap_t vmsetcap;\n\tvmi_vlapic_init vlapic_init;\n\tvmi_vlapic_cleanup vlapic_cleanup;\n\tvmi_interrupt vcpu_interrupt;\n};\n\nextern struct vmm_ops vmm_ops_intel;\n\nint vmm_init(void);\nint vmm_cleanup(void);\nint vm_create(struct vm **retvm);\nint vcpu_create(struct vm *vm, int vcpu);\nvoid vm_destroy(struct vm *vm);\nvoid vcpu_destroy(struct vm *vm, int vcpu);\nint vm_reinit(struct vm *vm);\nconst char *vm_name(struct vm *vm);\nint vm_malloc(struct vm *vm, uint64_t gpa, size_t len, uint64_t prot);\nvoid *vm_gpa2hva(struct vm *vm, uint64_t gpa, uint64_t len);\nint vm_gpabase2memseg(struct vm *vm, uint64_t gpabase,\n\tstruct vm_memory_segment *seg);\nint vm_get_memobj(struct vm *vm, uint64_t gpa, size_t len, uint64_t *offset,\n\tvoid **object);\nbool vm_mem_allocated(struct vm *vm, uint64_t gpa);\nint vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval);\nint vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val);\nint vm_get_seg_desc(struct vm *vm, int vcpu, int reg,\n\tstruct seg_desc *ret_desc);\nint vm_set_seg_desc(struct vm *vm, int vcpu, int reg, struct seg_desc *desc);\nint vm_run(struct vm *vm, int vcpu, struct vm_exit *vm_exit);\nint vm_suspend(struct vm *vm, enum vm_suspend_how how);\nint vm_inject_nmi(struct vm *vm, int vcpu);\nint vm_nmi_pending(struct vm *vm, int vcpuid);\nvoid vm_nmi_clear(struct vm *vm, int vcpuid);\nint vm_inject_extint(struct vm *vm, int vcpu);\nint vm_extint_pending(struct vm *vm, int vcpuid);\nvoid vm_extint_clear(struct vm *vm, int vcpuid);\nstruct vlapic *vm_lapic(struct vm *vm, int cpu);\nstruct vioapic *vm_ioapic(struct vm *vm);\nstruct vhpet *vm_hpet(struct vm *vm);\nint vm_get_capability(struct vm *vm, int vcpu, int type, int *val);\nint vm_set_capability(struct vm *vm, int vcpu, int type, int val);\nint vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state);\nint vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state);\nint vm_apicid2vcpuid(struct vm *vm, int apicid);\nint vm_activate_cpu(struct vm *vm, int vcpu);\nstruct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid);\nvoid vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip);\nvoid vm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip);\n\n/*\n * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'.\n * The rendezvous 'func(arg)' is not allowed to do anything that will\n * cause the thread to be put to sleep.\n *\n * If the rendezvous is being initiated from a vcpu context then the\n * 'vcpuid' must refer to that vcpu, otherwise it should be set to -1.\n *\n * The caller cannot hold any locks when initiating the rendezvous.\n *\n * The implementation of this API may cause vcpus other than those specified\n * by 'dest' to be stalled. The caller should not rely on any vcpus making\n * forward progress when the rendezvous is in progress.\n */\ntypedef void (*vm_rendezvous_func_t)(struct vm *vm, int vcpuid, void *arg);\nvoid vm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest,\n    vm_rendezvous_func_t func, void *arg);\ncpuset_t vm_active_cpus(struct vm *vm);\ncpuset_t vm_suspended_cpus(struct vm *vm);\n\nstatic __inline int\nvcpu_rendezvous_pending(void *rendezvous_cookie)\n{\n\n\treturn (*(uintptr_t *)rendezvous_cookie != 0);\n}\n\nstatic __inline int\nvcpu_suspended(void *suspend_cookie)\n{\n\n\treturn (*(int *)suspend_cookie);\n}\n\nenum vcpu_state {\n\tVCPU_IDLE,\n\tVCPU_FROZEN,\n\tVCPU_RUNNING,\n\tVCPU_SLEEPING,\n};\n\nint vcpu_set_state(struct vm *vm, int vcpu, enum vcpu_state state,\n    bool from_idle);\nenum vcpu_state vcpu_get_state(struct vm *vm, int vcpu);\n\nstatic int __inline\nvcpu_is_running(struct vm *vm, int vcpu)\n{\n\treturn (vcpu_get_state(vm, vcpu) == VCPU_RUNNING);\n}\n\nvoid *vcpu_stats(struct vm *vm, int vcpu);\nvoid vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr);\nstruct vatpic *vm_atpic(struct vm *vm);\nstruct vatpit *vm_atpit(struct vm *vm);\nstruct vpmtmr *vm_pmtmr(struct vm *vm);\nstruct vrtc *vm_rtc(struct vm *vm);\n\n/*\n * Inject exception 'vector' into the guest vcpu. This function returns 0 on\n * success and non-zero on failure.\n *\n * Wrapper functions like 'vm_inject_gp()' should be preferred to calling\n * this function directly because they enforce the trap-like or fault-like\n * behavior of an exception.\n *\n * This function should only be called in the context of the thread that is\n * executing this vcpu.\n */\nint vm_inject_exception(struct vm *vm, int vcpuid, int vector, int err_valid,\n    uint32_t errcode, int restart_instruction);\n\n/*\n * This function is called after a VM-exit that occurred during exception or\n * interrupt delivery through the IDT. The format of 'intinfo' is described\n * in Figure 15-1, \"EXITINTINFO for All Intercepts\", APM, Vol 2.\n *\n * If a VM-exit handler completes the event delivery successfully then it\n * should call vm_exit_intinfo() to extinguish the pending event. For e.g.,\n * if the task switch emulation is triggered via a task gate then it should\n * call this function with 'intinfo=0' to indicate that the external event\n * is not pending anymore.\n *\n * Return value is 0 on success and non-zero on failure.\n */\nint vm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t intinfo);\n\n/*\n * This function is called before every VM-entry to retrieve a pending\n * event that should be injected into the guest. This function combines\n * nested events into a double or triple fault.\n *\n * Returns 0 if there are no events that need to be injected into the guest\n * and non-zero otherwise.\n */\nint vm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *info);\n\nint vm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2);\n\nenum vm_reg_name vm_segment_name(int seg_encoding);\n\nstruct vm_copyinfo {\n\tuint64_t\tgpa;\n\tsize_t\t\tlen;\n\tvoid\t\t*hva;\n};\n\n/*\n * Set up 'copyinfo[]' to copy to/from guest linear address space starting\n * at 'gla' and 'len' bytes long. The 'prot' should be set to PROT_READ for\n * a copyin or PROT_WRITE for a copyout. \n *\n * retval\tis_fault\tIntepretation\n *   0\t\t   0\t\tSuccess\n *   0\t\t   1\t\tAn exception was injected into the guest\n * EFAULT\t  N/A\t\tUnrecoverable error\n *\n * The 'copyinfo[]' can be passed to 'vm_copyin()' or 'vm_copyout()' only if\n * the return value is 0. The 'copyinfo[]' resources should be freed by calling\n * 'vm_copy_teardown()' after the copy is done.\n */\nint vm_copy_setup(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,\n    uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo,\n    int num_copyinfo, int *is_fault);\nvoid vm_copy_teardown(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo,\n    int num_copyinfo);\nvoid vm_copyin(struct vm *vm, int vcpuid, struct vm_copyinfo *copyinfo,\n    void *kaddr, size_t len);\nvoid vm_copyout(struct vm *vm, int vcpuid, const void *kaddr,\n    struct vm_copyinfo *copyinfo, size_t len);\n\nint vcpu_trace_exceptions(void);\n\n/* APIs to inject faults into the guest */\nvoid vm_inject_fault(void *vm, int vcpuid, int vector, int errcode_valid,\n    int errcode);\n\nstatic __inline void\nvm_inject_ud(void *vm, int vcpuid)\n{\n\tvm_inject_fault(vm, vcpuid, IDT_UD, 0, 0);\n}\n\nstatic __inline void\nvm_inject_gp(void *vm, int vcpuid)\n{\n\tvm_inject_fault(vm, vcpuid, IDT_GP, 1, 0);\n}\n\nstatic __inline void\nvm_inject_ac(void *vm, int vcpuid, int errcode)\n{\n\tvm_inject_fault(vm, vcpuid, IDT_AC, 1, errcode);\n}\n\nstatic __inline void\nvm_inject_ss(void *vm, int vcpuid, int errcode)\n{\n\tvm_inject_fault(vm, vcpuid, IDT_SS, 1, errcode);\n}\n\nvoid vm_inject_pf(void *vm, int vcpuid, int error_code, uint64_t cr2);\n\nint vm_restart_instruction(void *vm, int vcpuid);\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_api.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <sys/time.h>\n#include <xhyve/support/cpuset.h>\n#include <xhyve/vmm/vmm_common.h>\n\nstruct iovec;\n\n/*\n * Different styles of mapping the memory assigned to a VM into the address\n * space of the controlling process.\n */\nenum vm_mmap_style {\n\tVM_MMAP_NONE,\t\t/* no mapping */\n\tVM_MMAP_ALL,\t\t/* fully and statically mapped */\n\tVM_MMAP_SPARSE,\t\t/* mappings created on-demand */\n};\n\nint xh_vm_create(void);\nvoid xh_vm_destroy(void);\nint xh_vcpu_create(int vcpu);\nvoid xh_vcpu_destroy(int vcpu);\nint xh_vm_get_memory_seg(uint64_t gpa, size_t *ret_len);\nint xh_vm_setup_memory(size_t len, enum vm_mmap_style vms);\nint xh_setup_bootrom_memory(size_t len, void **addr);\nint xh_setup_video_memory(uint64_t gpa, size_t len, void **addr);\nvoid *xh_vm_map_gpa(uint64_t gpa, size_t len);\nint xh_vm_gla2gpa(int vcpu, struct vm_guest_paging *paging, uint64_t gla,\n\tint prot, uint64_t *gpa, int *fault);\nuint32_t xh_vm_get_lowmem_limit(void);\nvoid xh_vm_set_lowmem_limit(uint32_t limit);\nvoid xh_vm_set_memflags(int flags);\nsize_t xh_vm_get_lowmem_size(void);\nsize_t xh_vm_get_highmem_size(void);\nint xh_vm_set_desc(int vcpu, int reg, uint64_t base, uint32_t limit,\n\tuint32_t access);\nint xh_vm_get_desc(int vcpu, int reg, uint64_t *base, uint32_t *limit,\n\tuint32_t *access);\nint xh_vm_get_seg_desc(int vcpu, int reg, struct seg_desc *seg_desc);\nint xh_vm_set_register(int vcpu, int reg, uint64_t val);\nint xh_vm_get_register(int vcpu, int reg, uint64_t *retval);\nint xh_vm_run(int vcpu, struct vm_exit *ret_vmexit);\nint xh_vm_suspend(enum vm_suspend_how how);\nint xh_vm_reinit(void);\nint xh_vm_apicid2vcpu(int apicid);\nint xh_vm_inject_exception(int vcpu, int vector, int errcode_valid,\n\tuint32_t errcode, int restart_instruction);\nint xh_vm_lapic_irq(int vcpu, int vector);\nint xh_vm_lapic_local_irq(int vcpu, int vector);\nint xh_vm_lapic_msi(uint64_t addr, uint64_t msg);\nint xh_vm_ioapic_assert_irq(int irq);\nint xh_vm_ioapic_deassert_irq(int irq);\nint xh_vm_ioapic_pulse_irq(int irq);\nint xh_vm_ioapic_pincount(int *pincount);\nint xh_vm_isa_assert_irq(int atpic_irq, int ioapic_irq);\nint xh_vm_isa_deassert_irq(int atpic_irq, int ioapic_irq);\nint xh_vm_isa_pulse_irq(int atpic_irq, int ioapic_irq);\nint xh_vm_isa_set_irq_trigger(int atpic_irq, enum vm_intr_trigger trigger);\nint xh_vm_inject_nmi(int vcpu);\nint xh_vm_capability_name2type(const char *capname);\nconst char *xh_vm_capability_type2name(int type);\nint xh_vm_get_capability(int vcpu, enum vm_cap_type cap, int *retval);\nint xh_vm_set_capability(int vcpu, enum vm_cap_type cap, int val);\nint xh_vm_get_intinfo(int vcpu, uint64_t *i1, uint64_t *i2);\nint xh_vm_set_intinfo(int vcpu, uint64_t exit_intinfo);\nuint64_t *xh_vm_get_stats(int vcpu, struct timeval *ret_tv, int *ret_entries);\nconst char *xh_vm_get_stat_desc(int index);\nint xh_vm_get_x2apic_state(int vcpu, enum x2apic_state *s);\nint xh_vm_set_x2apic_state(int vcpu, enum x2apic_state s);\nint xh_vm_get_hpet_capabilities(uint32_t *capabilities);\nint xh_vm_copy_setup(int vcpu, struct vm_guest_paging *pg, uint64_t gla,\n\tsize_t len, int prot, struct iovec *iov, int iovcnt, int *fault);\nvoid xh_vm_copyin(struct iovec *iov, void *dst, size_t len);\nvoid xh_vm_copyout(const void *src, struct iovec *iov, size_t len);\nint xh_vm_rtc_write(int offset, uint8_t value);\nint xh_vm_rtc_read(int offset, uint8_t *retval);\nint xh_vm_rtc_settime(time_t secs);\nint xh_vm_rtc_gettime(time_t *secs);\nint xh_vcpu_reset(int vcpu);\nint xh_vm_active_cpus(cpuset_t *cpus);\nint xh_vm_suspended_cpus(cpuset_t *cpus);\nint xh_vm_activate_cpu(int vcpu);\nint xh_vm_restart_instruction(int vcpu);\nint xh_vm_emulate_instruction(int vcpu, uint64_t gpa, struct vie *vie,\n\tstruct vm_guest_paging *paging, mem_region_read_t memread,\n\tmem_region_write_t memwrite, void *memarg);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_callout.h",
    "content": "#pragma once\n\n#include <stdint.h>\n#include <time.h>\n#include <sys/time.h>\n#include <dispatch/dispatch.h>\n\n#define SBT_1S  ((sbintime_t)1 << 32)\n#define SBT_1M  (SBT_1S * 60)\n#define SBT_1MS (SBT_1S / 1000)\n#define SBT_1US (SBT_1S / 1000000)\n#define SBT_1NS (SBT_1S / 1000000000)\n#define SBT_MAX 0x7fffffffffffffffLL\n\n#define\tFREQ2BT(freq, bt) \\\n{ \\\n  (bt)->sec = 0; \\\n  (bt)->frac = ((uint64_t)0x8000000000000000  / (freq)) << 1; \\\n}\n\n#define BT2FREQ(bt) \\\n  (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \\\n    ((bt)->frac >> 1))\n\nstruct bintime {\n  uint64_t sec;\n  uint64_t frac;\n};\n\ntypedef int64_t sbintime_t;\n\nstatic inline sbintime_t bttosbt(const struct bintime bt) {\n  return (sbintime_t) ((bt.sec << 32) + (bt.frac >> 32));\n}\n\nstatic inline void bintime_mul(struct bintime *bt, unsigned int x) {\n  uint64_t p1, p2;\n  \n  p1 = (bt->frac & 0xffffffffull) * x;\n  p2 = (bt->frac >> 32) * x + (p1 >> 32);\n  bt->sec *= x;\n  bt->sec += (p2 >> 32);\n  bt->frac = (p2 << 32) | (p1 & 0xffffffffull);\n}\n\nstatic inline void bintime_add(struct bintime *_bt, const struct bintime *_bt2)\n{\n  uint64_t _u;\n\n  _u = _bt->frac;\n  _bt->frac += _bt2->frac;\n  if (_u > _bt->frac)\n    _bt->sec++;\n  _bt->sec += _bt2->sec;\n}\n\nstatic inline void bintime_sub(struct bintime *_bt, const struct bintime *_bt2)\n{\n  uint64_t _u;\n\n  _u = _bt->frac;\n  _bt->frac -= _bt2->frac;\n  if (_u < _bt->frac)\n    _bt->sec--;\n  _bt->sec -= _bt2->sec;\n}\n\n#define bintime_cmp(a, b, cmp) \\\n  (((a)->sec == (b)->sec) ? \\\n    ((a)->frac cmp (b)->frac) : \\\n    ((a)->sec cmp (b)->sec))\n\nextern int tc_precexp;\n\nvoid binuptime(struct bintime *bt);\nvoid getmicrotime(struct timeval *tv);\n\nstatic inline sbintime_t sbinuptime(void) {\n  struct bintime _bt;\n  \n  binuptime(&_bt);\n  return (bttosbt(_bt));\n}\n\nstruct callout {\n  dispatch_group_t group;\n  dispatch_source_t timer;\n  uint64_t timeout;\n  uint64_t precision;\n  void *argument;\n  void (*callout)(void *);\n  int flags;\n  int queued;\n};\n\n#define C_ABSOLUTE 0x0200 /* event time is absolute */\n#define CALLOUT_ACTIVE 0x0002 /* callout is currently active */\n#define CALLOUT_PENDING 0x0004 /* callout is waiting for timeout */\n#define CALLOUT_RETURNUNLOCKED 0x0010 /* handler returns with mtx unlocked */\n#define CALLOUT_COMPLETED 0x0020 /* callout thread finished */\n#define CALLOUT_WAITING 0x0040 /* thread waiting for callout to finish */\n//#define CALLOUT_QUEUED 0x0080\n\nvoid callout_system_init(void);\nvoid callout_init(struct callout *c, int mpsafe);\nint callout_reset_sbt(struct callout *c, sbintime_t sbt,\n  sbintime_t precision, void (*ftn)(void *), void *arg,\n  int flags);\n\nint callout_stop_safe(struct callout *c, int drain);\n\n#define callout_active(c) ((c)->flags & CALLOUT_ACTIVE)\n#define callout_deactivate(c) ((c)->flags &= ~CALLOUT_ACTIVE)\n#define callout_pending(c)  ((c)->flags & CALLOUT_PENDING)\n#define callout_completed(c)  ((c)->flags & CALLOUT_COMPLETED)\n#define callout_drain(c) callout_stop_safe(c, 1)\n#define callout_stop(c) callout_stop_safe(c, 0)\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_common.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\n#define\tVM_MAXCPU 16 /* maximum virtual cpus */\n\nenum vm_suspend_how {\n\tVM_SUSPEND_NONE,\n\tVM_SUSPEND_RESET,\n\tVM_SUSPEND_POWEROFF,\n\tVM_SUSPEND_HALT,\n\tVM_SUSPEND_TRIPLEFAULT,\n\tVM_SUSPEND_LAST\n};\n\nenum vm_cap_type {\n\tVM_CAP_HALT_EXIT,\n\tVM_CAP_MTRAP_EXIT,\n\tVM_CAP_PAUSE_EXIT,\n\tVM_CAP_MAX\n};\n\nenum vm_intr_trigger {\n\tEDGE_TRIGGER,\n\tLEVEL_TRIGGER\n};\n\nenum x2apic_state {\n\tX2APIC_DISABLED,\n\tX2APIC_ENABLED,\n\tX2APIC_STATE_LAST\n};\n\nenum vm_cpu_mode {\n\tCPU_MODE_REAL,\n\tCPU_MODE_PROTECTED,\n\tCPU_MODE_COMPATIBILITY, /* IA-32E mode (CS.L = 0) */\n\tCPU_MODE_64BIT, /* IA-32E mode (CS.L = 1) */\n};\n\nenum vm_paging_mode {\n\tPAGING_MODE_FLAT,\n\tPAGING_MODE_32,\n\tPAGING_MODE_PAE,\n\tPAGING_MODE_64,\n};\n\nstruct seg_desc {\n\tuint64_t\tbase;\n\tuint32_t\tlimit;\n\tuint32_t\taccess;\n};\n\n#define\tSEG_DESC_TYPE(access) ((access) & 0x001f)\n#define\tSEG_DESC_DPL(access) (((access) >> 5) & 0x3)\n#define\tSEG_DESC_PRESENT(access) (((access) & 0x0080) ? 1 : 0)\n#define\tSEG_DESC_DEF32(access) (((access) & 0x4000) ? 1 : 0)\n#define\tSEG_DESC_GRANULARITY(access) (((access) & 0x8000) ? 1 : 0)\n#define\tSEG_DESC_UNUSABLE(access) (((access) & 0x10000) ? 1 : 0)\n\nstruct vm_guest_paging {\n\tuint64_t cr3;\n\tint cpl;\n\tenum vm_cpu_mode cpu_mode;\n\tenum vm_paging_mode paging_mode;\n};\n\nenum vm_reg_name {\n\tVM_REG_GUEST_RAX,\n\tVM_REG_GUEST_RBX,\n\tVM_REG_GUEST_RCX,\n\tVM_REG_GUEST_RDX,\n\tVM_REG_GUEST_RSI,\n\tVM_REG_GUEST_RDI,\n\tVM_REG_GUEST_RBP,\n\tVM_REG_GUEST_R8,\n\tVM_REG_GUEST_R9,\n\tVM_REG_GUEST_R10,\n\tVM_REG_GUEST_R11,\n\tVM_REG_GUEST_R12,\n\tVM_REG_GUEST_R13,\n\tVM_REG_GUEST_R14,\n\tVM_REG_GUEST_R15,\n\tVM_REG_GUEST_CR0,\n\tVM_REG_GUEST_CR3,\n\tVM_REG_GUEST_CR4,\n\tVM_REG_GUEST_DR7,\n\tVM_REG_GUEST_RSP,\n\tVM_REG_GUEST_RIP,\n\tVM_REG_GUEST_RFLAGS,\n\tVM_REG_GUEST_ES,\n\tVM_REG_GUEST_CS,\n\tVM_REG_GUEST_SS,\n\tVM_REG_GUEST_DS,\n\tVM_REG_GUEST_FS,\n\tVM_REG_GUEST_GS,\n\tVM_REG_GUEST_LDTR,\n\tVM_REG_GUEST_TR,\n\tVM_REG_GUEST_IDTR,\n\tVM_REG_GUEST_GDTR,\n\tVM_REG_GUEST_EFER,\n\tVM_REG_GUEST_CR2,\n\tVM_REG_GUEST_PDPTE0,\n\tVM_REG_GUEST_PDPTE1,\n\tVM_REG_GUEST_PDPTE2,\n\tVM_REG_GUEST_PDPTE3,\n\tVM_REG_GUEST_INTR_SHADOW,\n\tVM_REG_LAST\n};\n\nenum vm_exitcode {\n\tVM_EXITCODE_INOUT,\n\tVM_EXITCODE_VMX,\n\tVM_EXITCODE_BOGUS,\n\tVM_EXITCODE_RDMSR,\n\tVM_EXITCODE_WRMSR,\n\tVM_EXITCODE_HLT,\n\tVM_EXITCODE_MTRAP,\n\tVM_EXITCODE_PAUSE,\n\tVM_EXITCODE_PAGING,\n\tVM_EXITCODE_INST_EMUL,\n\tVM_EXITCODE_SPINUP_AP,\n\tVM_EXITCODE_DEPRECATED1,\t/* used to be SPINDOWN_CPU */\n\tVM_EXITCODE_RENDEZVOUS,\n\tVM_EXITCODE_IOAPIC_EOI,\n\tVM_EXITCODE_SUSPENDED,\n\tVM_EXITCODE_INOUT_STR,\n\tVM_EXITCODE_TASK_SWITCH,\n\tVM_EXITCODE_MONITOR,\n\tVM_EXITCODE_MWAIT,\n\tVM_EXITCODE_MAX\n};\n\nstruct vm_inout {\n\tuint16_t bytes:3; /* 1 or 2 or 4 */\n\tuint16_t in:1;\n\tuint16_t string:1;\n\tuint16_t rep:1;\n\tuint16_t port;\n\tuint32_t eax; /* valid for out */\n};\n\nstruct vm_inout_str {\n\tstruct vm_inout inout; /* must be the first element */\n\tstruct vm_guest_paging paging;\n\tuint64_t rflags;\n\tuint64_t cr0;\n\tuint64_t index;\n\tuint64_t count; /* rep=1 (%rcx), rep=0 (1) */\n\tint addrsize;\n\tenum vm_reg_name seg_name;\n\tstruct seg_desc seg_desc;\n};\n\nstruct vie_op {\n\tuint8_t op_byte; /* actual opcode byte */\n\tuint8_t op_type; /* type of operation (e.g. MOV) */\n\tuint16_t op_flags;\n};\n\n#define\tVIE_INST_SIZE\t15\nstruct vie {\n\tuint8_t inst[VIE_INST_SIZE]; /* instruction bytes */\n\tuint8_t num_valid; /* size of the instruction */\n\tuint8_t num_processed;\n\tuint8_t addrsize:4, opsize:4; /* address and operand sizes */\n\tuint8_t rex_w:1, /* REX prefix */\n\t\t\trex_r:1,\n\t\t\trex_x:1,\n\t\t\trex_b:1,\n\t\t\trex_present:1,\n\t\t\trepz_present:1, /* REP/REPE/REPZ prefix */\n\t\t\trepnz_present:1, /* REPNE/REPNZ prefix */\n\t\t\topsize_override:1, /* Operand size override */\n\t\t\taddrsize_override:1, /* Address size override */\n\t\t\tsegment_override:1; /* Segment override */\n\tuint8_t mod:2, /* ModRM byte */\n\t\t\treg:4,\n\t\t\trm:4;\n\tuint8_t ss:2, /* SIB byte */\n\t\t\tindex:4,\n\t\t\tbase:4;\n\tuint8_t disp_bytes;\n\tuint8_t imm_bytes;\n\tuint8_t scale;\n\tint base_register; /* VM_REG_GUEST_xyz */\n\tint index_register; /* VM_REG_GUEST_xyz */\n\tint segment_register; /* VM_REG_GUEST_xyz */\n\tint64_t displacement; /* optional addr displacement */\n\tint64_t immediate; /* optional immediate operand */\n\tuint8_t decoded; /* set to 1 if successfully decoded */\n\tstruct vie_op op; /* opcode description */\n};\n\nenum task_switch_reason {\n\tTSR_CALL,\n\tTSR_IRET,\n\tTSR_JMP,\n\tTSR_IDT_GATE /* task gate in IDT */\n};\n\nstruct vm_task_switch {\n\tuint16_t tsssel; /* new TSS selector */\n\tint ext; /* task switch due to external event */\n\tuint32_t errcode;\n\tint errcode_valid; /* push 'errcode' on the new stack */\n\tenum task_switch_reason reason;\n\tstruct vm_guest_paging paging;\n};\n\nstruct vm_exit {\n\tenum vm_exitcode exitcode;\n\tint inst_length; /* 0 means unknown */\n\tuint64_t rip;\n\tunion {\n\t\tstruct vm_inout inout;\n\t\tstruct vm_inout_str inout_str;\n\t\tstruct {\n\t\t\tuint64_t gpa;\n\t\t\tint fault_type;\n\t\t} paging;\n\t\tstruct {\n\t\t\tuint64_t gpa;\n\t\t\tuint64_t gla;\n\t\t\tuint64_t cs_base;\n\t\t\tint cs_d; /* CS.D */\n\t\t\tstruct vm_guest_paging paging;\n\t\t\tstruct vie vie;\n\t\t} inst_emul;\n\t\t/*\n\t\t * VMX specific payload. Used when there is no \"better\"\n\t\t * exitcode to represent the VM-exit.\n\t\t */\n\t\tstruct {\n\t\t\tint status; /* vmx inst status */\n\t\t\t/*\n\t\t\t * 'exit_reason' and 'exit_qualification' are valid\n\t\t\t * only if 'status' is zero.\n\t\t\t */\n\t\t\tuint32_t exit_reason;\n\t\t\tuint64_t exit_qualification;\n\t\t\t/*\n\t\t\t * 'inst_error' and 'inst_type' are valid\n\t\t\t * only if 'status' is non-zero.\n\t\t\t */\n\t\t\tint inst_type;\n\t\t\tint inst_error;\n\t\t} vmx;\n\t\tstruct {\n\t\t\tuint32_t code; /* ecx value */\n\t\t\tuint64_t wval;\n\t\t} msr;\n\t\tstruct {\n\t\t\tint vcpu;\n\t\t\tuint64_t rip;\n\t\t} spinup_ap;\n\t\tstruct {\n\t\t\tuint64_t rflags;\n\t\t} hlt;\n\t\tstruct {\n\t\t\tint vector;\n\t\t} ioapic_eoi;\n\t\tstruct {\n\t\t\tenum vm_suspend_how how;\n\t\t} suspended;\n\t\tstruct vm_task_switch task_switch;\n\t} u;\n};\n\n/* FIXME remove */\nstruct vm_memory_segment {\n\tuint64_t gpa; /* in */\n\tsize_t len;\n};\n\ntypedef int (*mem_region_read_t)(void *vm, int cpuid, uint64_t gpa,\n\tuint64_t *rval, int rsize, void *arg);\n\ntypedef int (*mem_region_write_t)(void *vm, int cpuid, uint64_t gpa,\n\tuint64_t wval, int wsize, void *arg);\n\nuint64_t vie_size2mask(int size);\n\nint vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg,\n\tstruct seg_desc *desc, uint64_t off, int length, int addrsize, int prot,\n\tuint64_t *gla);\n\nint vie_alignment_check(int cpl, int operand_size, uint64_t cr0,\n\tuint64_t rflags, uint64_t gla);\n\n#pragma clang diagnostic pop\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_host.h",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct xsave_limits {\n\tint\t\txsave_enabled;\n\tuint64_t\txcr0_allowed;\n\tuint32_t\txsave_max_size;\n};\n#pragma clang diagnostic pop\n\nvoid vmm_host_state_init(void);\n\nconst struct xsave_limits *vmm_get_xsave_limits(void);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_instruction_emul.h",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/vmm/vmm.h>\n\n/*\n * Emulate the decoded 'vie' instruction.\n *\n * The callbacks 'mrr' and 'mrw' emulate reads and writes to the memory region\n * containing 'gpa'. 'mrarg' is an opaque argument that is passed into the\n * callback functions.\n *\n * 'void *vm' should be 'struct vm *' when called from kernel context and\n * 'struct vmctx *' when called from user context.\n * s\n */\nint vmm_emulate_instruction(void *vm, int cpuid, uint64_t gpa, struct vie *vie,\n    struct vm_guest_paging *paging, mem_region_read_t mrr,\n    mem_region_write_t mrw, void *mrarg);\n\nint vie_update_register(void *vm, int vcpuid, enum vm_reg_name reg,\n    uint64_t val, int size);\n\n/* Returns 1 if the 'gla' is not canonical and 0 otherwise. */\nint vie_canonical_check(enum vm_cpu_mode cpu_mode, uint64_t gla);\n\n/*\n * APIs to fetch and decode the instruction from nested page fault handler.\n *\n * 'vie' must be initialized before calling 'vmm_fetch_instruction()'\n */\nint vmm_fetch_instruction(struct vm *vm, int cpuid,\n\t\t\t  struct vm_guest_paging *guest_paging,\n\t\t\t  uint64_t rip, int inst_length, struct vie *vie,\n\t\t\t  int *is_fault);\n\n/*\n * Translate the guest linear address 'gla' to a guest physical address.\n *\n * retval\tis_fault\tInterpretation\n *   0\t\t   0\t\t'gpa' contains result of the translation\n *   0\t\t   1\t\tAn exception was injected into the guest\n * EFAULT\t  N/A\t\tAn unrecoverable hypervisor error occurred\n */\nint vm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,\n    uint64_t gla, int prot, uint64_t *gpa, int *is_fault);\n\nvoid vie_init(struct vie *vie, const char *inst_bytes, int inst_length);\n\n/*\n * Decode the instruction fetched into 'vie' so it can be emulated.\n *\n * 'gla' is the guest linear address provided by the hardware assist\n * that caused the nested page table fault. It is used to verify that\n * the software instruction decoding is in agreement with the hardware.\n * \n * Some hardware assists do not provide the 'gla' to the hypervisor.\n * To skip the 'gla' verification for this or any other reason pass\n * in VIE_INVALID_GLA instead.\n */\n#define\tVIE_INVALID_GLA\t\t(1UL << 63)\t/* a non-canonical address */\nint vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla,\n\t\t\t   enum vm_cpu_mode cpu_mode, int csd, struct vie *vie);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_ioport.h",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n\nstruct vm;\nstruct vm_exit;\n\ntypedef int (*ioport_handler_func_t)(struct vm *vm, int vcpuid,\n    bool in, int port, int bytes, uint32_t *val);\n\nint vm_handle_inout(struct vm *vm, int vcpuid, struct vm_exit *vme, bool *retu);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_ktr.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdio.h>\n\n#ifdef XHYVE_CONFIG_TRACE\n#define vmmtrace printf\n#else\n#define vmmtrace if (0) printf\n#endif\n\nstruct vm;\nextern const char *vm_name(struct vm *vm);\n\n#define\tVCPU_CTR0(vm, vcpuid, format)\t\t\t\t\t\\\nvmmtrace(\"vm %s[%d]: \" format \"\\n\", vm_name((vm)), (vcpuid))\n\n#define\tVCPU_CTR1(vm, vcpuid, format, p1)\t\t\t\t\\\nvmmtrace(\"vm %s[%d]: \" format \"\\n\", vm_name((vm)), (vcpuid), (p1))\n\n#define\tVCPU_CTR2(vm, vcpuid, format, p1, p2)\t\t\t\t\\\nvmmtrace(\"vm %s[%d]: \" format \"\\n\", vm_name((vm)), (vcpuid), (p1), (p2))\n\n#define\tVCPU_CTR3(vm, vcpuid, format, p1, p2, p3)\t\t\t\\\nvmmtrace(\"vm %s[%d]: \" format \"\\n\", vm_name((vm)), (vcpuid), (p1), (p2), (p3))\n\n#define\tVCPU_CTR4(vm, vcpuid, format, p1, p2, p3, p4)\t\t\t\\\nvmmtrace(\"vm %s[%d]: \" format \"\\n\", vm_name((vm)), (vcpuid),\t\t\\\n    (p1), (p2), (p3), (p4))\n\n#define\tVM_CTR0(vm, format)\t\t\t\t\t\t\\\nvmmtrace(\"vm %s: \" format \"\\n\", vm_name((vm)))\n\n#define\tVM_CTR1(vm, format, p1)\t\t\t\t\t\t\\\nvmmtrace(\"vm %s: \" format \"\\n\", vm_name((vm)), (p1))\n\n#define\tVM_CTR2(vm, format, p1, p2)\t\t\t\t\t\\\nvmmtrace(\"vm %s: \" format \"\\n\", vm_name((vm)), (p1), (p2))\n\n#define\tVM_CTR3(vm, format, p1, p2, p3)\t\t\t\t\t\\\nvmmtrace(\"vm %s: \" format \"\\n\", vm_name((vm)), (p1), (p2), (p3))\n\n#define\tVM_CTR4(vm, format, p1, p2, p3, p4)\t\t\t\t\\\nvmmtrace(\"vm %s: \" format \"\\n\", vm_name((vm)), (p1), (p2), (p3), (p4))\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_lapic.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <xhyve/support/misc.h>\n\nstruct vm;\n\nbool lapic_msr(u_int num);\nint\tlapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval,\n\t    bool *retu);\nint\tlapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t wval,\n\t    bool *retu);\n\nint\tlapic_mmio_read(void *vm, int cpu, uint64_t gpa,\n\t\t\tuint64_t *rval, int size, void *arg);\nint\tlapic_mmio_write(void *vm, int cpu, uint64_t gpa,\n\t\t\t uint64_t wval, int size, void *arg);\n\n/*\n * Signals to the LAPIC that an interrupt at 'vector' needs to be generated\n * to the 'cpu', the state is recorded in IRR.\n */\nint\tlapic_set_intr(struct vm *vm, int cpu, int vector, bool trig);\n\n#define\tLAPIC_TRIG_LEVEL\ttrue\n#define\tLAPIC_TRIG_EDGE\t\tfalse\nstatic __inline int\nlapic_intr_level(struct vm *vm, int cpu, int vector)\n{\n\n\treturn (lapic_set_intr(vm, cpu, vector, LAPIC_TRIG_LEVEL));\n}\n\nstatic __inline int\nlapic_intr_edge(struct vm *vm, int cpu, int vector)\n{\n\n\treturn (lapic_set_intr(vm, cpu, vector, LAPIC_TRIG_EDGE));\n}\n\n/*\n * Triggers the LAPIC local interrupt (LVT) 'vector' on 'cpu'.  'cpu' can\n * be set to -1 to trigger the interrupt on all CPUs.\n */\nint\tlapic_set_local_intr(struct vm *vm, int cpu, int vector);\n\nint\tlapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_mem.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <stdlib.h>\n\nstruct vmspace;\n\nint\tvmm_mem_init(void);\nvoid *vmm_mem_alloc(uint64_t gpa, size_t size, uint64_t prot);\nvoid vmm_mem_free(uint64_t gpa, size_t size, void *object);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_stat.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\nstruct vm;\n\n#define\tMAX_VMM_STAT_ELEMS\t64\t\t/* arbitrary */\n\nenum vmm_stat_scope {\n\tVMM_STAT_SCOPE_ANY,\n\tVMM_STAT_SCOPE_INTEL,\t\t/* Intel VMX specific statistic */\n\tVMM_STAT_SCOPE_AMD,\t\t/* AMD SVM specific statistic */\n};\n\nstruct vmm_stat_type;\ntypedef void (*vmm_stat_func_t)(struct vm *vm, int vcpu,\n    struct vmm_stat_type *stat);\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vmm_stat_type {\n\tint\tindex;\t\t\t/* position in the stats buffer */\n\tint\tnelems;\t\t\t/* standalone or array */\n\tconst char *desc;\t\t/* description of statistic */\n\tvmm_stat_func_t func;\n\tenum vmm_stat_scope scope;\n};\n#pragma clang diagnostic pop\n\nvoid\tvmm_stat_register(void *arg);\n\n#define\tVMM_STAT_FDEFINE(type, nelems, desc, func, scope)\t\t\\\n\tstruct vmm_stat_type type[1] = {\t\t\t\t\\\n\t\t{ -1, nelems, desc, func, scope }\t\t\t\\\n\t}\n\t//};\t\t\t\t\t\t\t\t\\\n\t// SYSINIT(type##_stat, SI_SUB_KLD, SI_ORDER_ANY, vmm_stat_register, type)\n\n#define VMM_STAT_DEFINE(type, nelems, desc, scope) \t\t\t\\\n\tVMM_STAT_FDEFINE(type, nelems, desc, NULL, scope)\n\n#define\tVMM_STAT_DECLARE(type)\t\t\t\t\t\t\\\n\textern struct vmm_stat_type type[1]\n\n#define\tVMM_STAT(type, desc)\t\t\\\n\tVMM_STAT_DEFINE(type, 1, desc, VMM_STAT_SCOPE_ANY)\n#define\tVMM_STAT_INTEL(type, desc)\t\\\n\tVMM_STAT_DEFINE(type, 1, desc, VMM_STAT_SCOPE_INTEL)\n\n#define\tVMM_STAT_FUNC(type, desc, func)\t\\\n\tVMM_STAT_FDEFINE(type, 1, desc, func, VMM_STAT_SCOPE_ANY)\n\n#define\tVMM_STAT_ARRAY(type, nelems, desc)\t\\\n\tVMM_STAT_DEFINE(type, nelems, desc, VMM_STAT_SCOPE_ANY)\n\nvoid\t*vmm_stat_alloc(void);\nvoid\tvmm_stat_init(void *vp);\nvoid \tvmm_stat_free(void *vp);\n\n/*\n * 'buf' should be at least fit 'MAX_VMM_STAT_TYPES' entries\n */\nint\tvmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf);\nint\tvmm_stat_desc_copy(int index, char *buf, size_t buflen);\n\nstatic void __inline\nvmm_stat_array_incr(struct vm *vm, int vcpu, struct vmm_stat_type *vst,\n\t\t    int statidx, uint64_t x)\n{\n#ifdef XHYVE_CONFIG_STATS\n\tuint64_t *stats;\n\t\n\tstats = vcpu_stats(vm, vcpu);\n\n\tif (vst->index >= 0 && statidx < vst->nelems)\n\t\tstats[vst->index + statidx] += x;\n#else\n\t(void) vm;\n\t(void) vcpu;\n\t(void) vst;\n\t(void) statidx;\n\t(void) x;\n#endif\n}\n\nstatic void __inline\nvmm_stat_array_set(struct vm *vm, int vcpu, struct vmm_stat_type *vst,\n\t\t   int statidx, uint64_t val)\n{\n#ifdef XHYVE_CONFIG_STATS\n\tuint64_t *stats;\n\t\n\tstats = vcpu_stats(vm, vcpu);\n\n\tif (vst->index >= 0 && statidx < vst->nelems)\n\t\tstats[vst->index + statidx] = val;\n#else\n\t(void) vm;\n\t(void) vcpu;\n\t(void) vst;\n\t(void) statidx;\n\t(void) val;\n#endif\n}\n\t\t   \nstatic void __inline\nvmm_stat_incr(struct vm *vm, int vcpu, struct vmm_stat_type *vst, uint64_t x)\n{\n\n#ifdef XHYVE_CONFIG_STATS\n\tvmm_stat_array_incr(vm, vcpu, vst, 0, x);\n#else\n\t(void) vm;\n\t(void) vcpu;\n\t(void) vst;\n\t(void) x;\n#endif\n}\n\nstatic void __inline\nvmm_stat_set(struct vm *vm, int vcpu, struct vmm_stat_type *vst, uint64_t val)\n{\n\n#ifdef XHYVE_CONFIG_STATS\n\tvmm_stat_array_set(vm, vcpu, vst, 0, val);\n#else\n\t(void) vm;\n\t(void) vcpu;\n\t(void) vst;\n\t(void) val;\n#endif\n}\n\nVMM_STAT_DECLARE(VCPU_MIGRATIONS);\nVMM_STAT_DECLARE(VMEXIT_COUNT);\nVMM_STAT_DECLARE(VMEXIT_EXTINT);\nVMM_STAT_DECLARE(VMEXIT_HLT);\nVMM_STAT_DECLARE(VMEXIT_CR_ACCESS);\nVMM_STAT_DECLARE(VMEXIT_RDMSR);\nVMM_STAT_DECLARE(VMEXIT_WRMSR);\nVMM_STAT_DECLARE(VMEXIT_MTRAP);\nVMM_STAT_DECLARE(VMEXIT_PAUSE);\nVMM_STAT_DECLARE(VMEXIT_INTR_WINDOW);\nVMM_STAT_DECLARE(VMEXIT_NMI_WINDOW);\nVMM_STAT_DECLARE(VMEXIT_INOUT);\nVMM_STAT_DECLARE(VMEXIT_CPUID);\nVMM_STAT_DECLARE(VMEXIT_NESTED_FAULT);\nVMM_STAT_DECLARE(VMEXIT_INST_EMUL);\nVMM_STAT_DECLARE(VMEXIT_UNKNOWN);\nVMM_STAT_DECLARE(VMEXIT_ASTPENDING);\nVMM_STAT_DECLARE(VMEXIT_USERSPACE);\nVMM_STAT_DECLARE(VMEXIT_RENDEZVOUS);\nVMM_STAT_DECLARE(VMEXIT_EXCEPTION);\n"
  },
  {
    "path": "include/xhyve/vmm/vmm_util.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\nstruct trapframe;\n\nvoid dump_trapframe(struct trapframe *tf);\n"
  },
  {
    "path": "include/xhyve/vmm/x86.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\n#define CPUID_0000_0000 (0x0)\n#define CPUID_0000_0001\t(0x1)\n#define CPUID_0000_0002 (0x2)\n#define CPUID_0000_0003 (0x3)\n#define CPUID_0000_0004 (0x4)\n#define CPUID_0000_0006 (0x6)\n#define CPUID_0000_0007 (0x7)\n#define\tCPUID_0000_000A\t(0xA)\n#define\tCPUID_0000_000B\t(0xB)\n#define\tCPUID_0000_000D\t(0xD)\n#define CPUID_8000_0000\t(0x80000000)\n#define CPUID_8000_0001\t(0x80000001)\n#define CPUID_8000_0002\t(0x80000002)\n#define CPUID_8000_0003\t(0x80000003)\n#define CPUID_8000_0004\t(0x80000004)\n#define CPUID_8000_0006\t(0x80000006)\n#define CPUID_8000_0007\t(0x80000007)\n#define CPUID_8000_0008\t(0x80000008)\n\n/*\n * CPUID instruction Fn0000_0001:\n */\n#define CPUID_0000_0001_APICID_MASK\t\t\t(0xff<<24)\n#define CPUID_0000_0001_APICID_SHIFT\t\t\t24\n\n/*\n * CPUID instruction Fn0000_0001 ECX\n */\n#define CPUID_0000_0001_FEAT0_VMX\t(1<<5)\n\nint x86_emulate_cpuid(struct vm *vm, int vcpu_id, uint32_t *eax, uint32_t *ebx,\n\t\t      uint32_t *ecx, uint32_t *edx);\n"
  },
  {
    "path": "include/xhyve/xhyve.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n#include <xhyve/support/segments.h>\n\n#ifndef CTASSERT /* Allow lint to override */\n#define\tCTASSERT(x) _CTASSERT(x, __LINE__)\n#define\t_CTASSERT(x, y) __CTASSERT(x, y)\n#define\t__CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1]\n#endif\n\n#define\tVMEXIT_CONTINUE (0)\n#define\tVMEXIT_ABORT (-1)\n\nextern int guest_ncpus;\nextern int print_mac;\nextern char *guest_uuid_str;\nextern char *vmname;\n\nvoid xh_vm_inject_fault(int vcpu, int vector, int errcode_valid,\n    uint32_t errcode);\n\nstatic __inline void\nvm_inject_ud(int vcpuid)\n{\n\txh_vm_inject_fault(vcpuid, IDT_UD, 0, 0);\n}\n\nstatic __inline void\nvm_inject_gp(int vcpuid)\n{\n\txh_vm_inject_fault(vcpuid, IDT_GP, 1, 0);\n}\n\nstatic __inline void\nvm_inject_ac(int vcpuid, uint32_t errcode)\n{\n\txh_vm_inject_fault(vcpuid, IDT_AC, 1, errcode);\n}\n\nstatic __inline void\nvm_inject_ss(int vcpuid, uint32_t errcode)\n{\n\txh_vm_inject_fault(vcpuid, IDT_SS, 1, errcode);\n}\n\nvoid *paddr_guest2host(uintptr_t addr, size_t len);\n\nvoid vcpu_set_capabilities(int cpu);\nvoid vcpu_add(int fromcpu, int newcpu, uint64_t rip);\nint fbsdrun_vmexit_on_hlt(void);\nint fbsdrun_vmexit_on_pause(void);\nint fbsdrun_virtio_msix(void);\n"
  },
  {
    "path": "include/xhyve/xmsr.h",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#pragma once\n\n#include <stdint.h>\n\nint init_msr(void);\nint emulate_wrmsr(int vcpu, uint32_t code, uint64_t val);\nint emulate_rdmsr(int vcpu, uint32_t code, uint64_t *val);\n"
  },
  {
    "path": "src/acpi.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * bhyve ACPI table generator.\n *\n * Create the minimal set of ACPI tables required to boot FreeBSD (and\n * hopefully other o/s's) by writing out ASL template files for each of\n * the tables and the compiling them to AML with the Intel iasl compiler.\n * The AML files are then read into guest memory.\n *\n *  The tables are placed in the guest's ROM area just below 1MB physical,\n * above the MPTable.\n *\n *  Layout\n *  ------\n *   RSDP  ->   0xf2400    (36 bytes fixed)\n *     RSDT  ->   0xf2440    (36 bytes + 4*7 table addrs, 4 used)\n *     XSDT  ->   0xf2480    (36 bytes + 8*7 table addrs, 4 used)\n *       MADT  ->   0xf2500  (depends on #CPUs)\n *       FADT  ->   0xf2600  (268 bytes)\n *       HPET  ->   0xf2740  (56 bytes)\n *       MCFG  ->   0xf2780  (60 bytes)\n *         FACS  ->   0xf27C0 (64 bytes)\n *         DSDT  ->   0xf2800 (variable - can go up to 0x100000)\n */\n\n#include <stdint.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <paths.h>\n#include <assert.h>\n#include <errno.h>\n#include <sys/param.h>\n#include <sys/stat.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/acpi.h>\n#include <xhyve/pci_emul.h>\n\n/*\n * Define the base address of the ACPI tables, and the offsets to\n * the individual tables\n */\n#define BHYVE_ACPI_BASE\t\t0xf2400\n#define RSDT_OFFSET\t\t0x040\n#define XSDT_OFFSET\t\t0x080\n#define MADT_OFFSET\t\t0x100\n#define FADT_OFFSET\t\t0x200\n#define\tHPET_OFFSET\t\t0x340\n#define\tMCFG_OFFSET\t\t0x380\n#define FACS_OFFSET\t\t0x3C0\n#define DSDT_OFFSET\t\t0x400\n\n#define\tBHYVE_ASL_TEMPLATE\t\"bhyve.XXXXXXX\"\n#define BHYVE_ASL_SUFFIX\t\".aml\"\n#define BHYVE_ASL_COMPILER\t\"/usr/sbin/iasl\"\n\nstatic int basl_keep_temps;\nstatic int basl_verbose_iasl;\nstatic int basl_ncpu;\nstatic uint32_t basl_acpi_base = BHYVE_ACPI_BASE;\nstatic uint32_t hpet_capabilities;\n\n/*\n * Contains the full pathname of the template to be passed\n * to mkstemp/mktemps(3)\n */\nstatic char basl_template[MAXPATHLEN];\nstatic char basl_stemplate[MAXPATHLEN];\n\n/*\n * State for dsdt_line(), dsdt_indent(), and dsdt_unindent().\n */\nstatic FILE *dsdt_fp;\nstatic int dsdt_indent_level;\nstatic int dsdt_error;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct basl_fio {\n\tint\tfd;\n\tFILE *fp;\n\tchar f_name[MAXPATHLEN];\n};\n#pragma clang diagnostic pop\n\n#define EFPRINTF(...) \\\n\terr = fprintf(__VA_ARGS__); if (err < 0) goto err_exit;\n\n#define EFFLUSH(x) \\\n\terr = fflush(x); if (err != 0) goto err_exit;\n\nstatic int\nbasl_fwrite_rsdp(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve RSDP template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tSignature : \\\"RSD PTR \\\"\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 43\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 02\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tRSDT Address : %08X\\n\",\n\t    basl_acpi_base + RSDT_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tLength : 00000024\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tXSDT Address : 00000000%08X\\n\",\n\t    basl_acpi_base + XSDT_OFFSET);\n\tEFPRINTF(fp, \"[0001]\\t\\tExtended Checksum : 00\\n\");\n\tEFPRINTF(fp, \"[0003]\\t\\tReserved : 000000\\n\");\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_rsdt(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve RSDT template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"RSDT\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tTable Length : 00000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 00\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tOem Table ID : \\\"BVRSDT  \\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOem Revision : 00000001\\n\");\n\t/* iasl will fill in the compiler ID/revision fields */\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler ID : \\\"xxxx\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler Revision : 00000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\t/* Add in pointers to the MADT, FADT and HPET */\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 0 : %08X\\n\",\n\t    basl_acpi_base + MADT_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 1 : %08X\\n\",\n\t    basl_acpi_base + FADT_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 2 : %08X\\n\",\n\t    basl_acpi_base + HPET_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 3 : %08X\\n\",\n\t    basl_acpi_base + MCFG_OFFSET);\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_xsdt(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve XSDT template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"XSDT\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tTable Length : 00000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 00\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tOem Table ID : \\\"BVXSDT  \\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOem Revision : 00000001\\n\");\n\t/* iasl will fill in the compiler ID/revision fields */\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler ID : \\\"xxxx\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler Revision : 00000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\t/* Add in pointers to the MADT, FADT and HPET */\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 0 : 00000000%08X\\n\",\n\t    basl_acpi_base + MADT_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 1 : 00000000%08X\\n\",\n\t    basl_acpi_base + FADT_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 2 : 00000000%08X\\n\",\n\t    basl_acpi_base + HPET_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tACPI Table Address 3 : 00000000%08X\\n\",\n\t    basl_acpi_base + MCFG_OFFSET);\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_madt(FILE *fp)\n{\n\tint err;\n\tint i;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve MADT template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"APIC\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tTable Length : 00000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 00\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tOem Table ID : \\\"BVMADT  \\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOem Revision : 00000001\\n\");\n\n\t/* iasl will fill in the compiler ID/revision fields */\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler ID : \\\"xxxx\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler Revision : 00000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0004]\\t\\tLocal Apic Address : FEE00000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tFlags (decoded below) : 00000001\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPC-AT Compatibility : 1\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\t/* Add a Processor Local APIC entry for each CPU */\n\tfor (i = 0; i < basl_ncpu; i++) {\n\t\tEFPRINTF(fp, \"[0001]\\t\\tSubtable Type : 00\\n\");\n\t\tEFPRINTF(fp, \"[0001]\\t\\tLength : 08\\n\");\n\t\t/* iasl expects hex values for the proc and apic id's */\n\t\tEFPRINTF(fp, \"[0001]\\t\\tProcessor ID : %02x\\n\", i);\n\t\tEFPRINTF(fp, \"[0001]\\t\\tLocal Apic ID : %02x\\n\", i);\n\t\tEFPRINTF(fp, \"[0004]\\t\\tFlags (decoded below) : 00000001\\n\");\n\t\tEFPRINTF(fp, \"\\t\\t\\tProcessor Enabled : 1\\n\");\n\t\tEFPRINTF(fp, \"\\n\");\n\t}\n\n\t/* Always a single IOAPIC entry, with ID 0 */\n\tEFPRINTF(fp, \"[0001]\\t\\tSubtable Type : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tLength : 0C\\n\");\n\t/* iasl expects a hex value for the i/o apic id */\n\tEFPRINTF(fp, \"[0001]\\t\\tI/O Apic ID : %02x\\n\", 0);\n\tEFPRINTF(fp, \"[0001]\\t\\tReserved : 00\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAddress : fec00000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tInterrupt : 00000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\t/* Legacy IRQ0 is connected to pin 2 of the IOAPIC */\n\tEFPRINTF(fp, \"[0001]\\t\\tSubtable Type : 02\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tLength : 0A\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBus : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSource : 00\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tInterrupt : 00000002\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tFlags (decoded below) : 0005\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPolarity : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tTrigger Mode : 1\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0001]\\t\\tSubtable Type : 02\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tLength : 0A\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBus : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSource : %02X\\n\", SCI_INT);\n\tEFPRINTF(fp, \"[0004]\\t\\tInterrupt : %08X\\n\", SCI_INT);\n\tEFPRINTF(fp, \"[0002]\\t\\tFlags (decoded below) : 0000\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPolarity : 3\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tTrigger Mode : 3\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\t/* Local APIC NMI is connected to LINT 1 on all CPUs */\n\tEFPRINTF(fp, \"[0001]\\t\\tSubtable Type : 04\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tLength : 06\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tProcessorId : FF\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tFlags (decoded below) : 0005\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPolarity : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tTrigger Mode : 1\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tInterrupt : 01\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_fadt(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve FADT template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"FACP\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tTable Length : 0000010C\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 05\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 00\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tOem Table ID : \\\"BVFACP  \\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOem Revision : 00000001\\n\");\n\t/* iasl will fill in the compiler ID/revision fields */\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler ID : \\\"xxxx\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler Revision : 00000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0004]\\t\\tFACS Address : %08X\\n\",\n\t    basl_acpi_base + FACS_OFFSET);\n\tEFPRINTF(fp, \"[0004]\\t\\tDSDT Address : %08X\\n\",\n\t    basl_acpi_base + DSDT_OFFSET);\n\tEFPRINTF(fp, \"[0001]\\t\\tModel : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tPM Profile : 00 [Unspecified]\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tSCI Interrupt : %04X\\n\",\n\t    SCI_INT);\n\tEFPRINTF(fp, \"[0004]\\t\\tSMI Command Port : %08X\\n\",\n\t    SMI_CMD);\n\tEFPRINTF(fp, \"[0001]\\t\\tACPI Enable Value : %02X\\n\",\n\t    BHYVE_ACPI_ENABLE);\n\tEFPRINTF(fp, \"[0001]\\t\\tACPI Disable Value : %02X\\n\",\n\t    BHYVE_ACPI_DISABLE);\n\tEFPRINTF(fp, \"[0001]\\t\\tS4BIOS Command : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tP-State Control : 00\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tPM1A Event Block Address : %08X\\n\",\n\t    PM1A_EVT_ADDR);\n\tEFPRINTF(fp, \"[0004]\\t\\tPM1B Event Block Address : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tPM1A Control Block Address : %08X\\n\",\n\t    PM1A_CNT_ADDR);\n\tEFPRINTF(fp, \"[0004]\\t\\tPM1B Control Block Address : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tPM2 Control Block Address : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tPM Timer Block Address : %08X\\n\",\n\t    IO_PMTMR);\n\tEFPRINTF(fp, \"[0004]\\t\\tGPE0 Block Address : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tGPE1 Block Address : 00000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tPM1 Event Block Length : 04\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tPM1 Control Block Length : 02\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tPM2 Control Block Length : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tPM Timer Block Length : 04\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tGPE0 Block Length : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tGPE1 Block Length : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tGPE1 Base Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\t_CST Support : 00\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tC2 Latency : 0000\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tC3 Latency : 0000\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tCPU Cache Size : 0000\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tCache Flush Stride : 0000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tDuty Cycle Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tDuty Cycle Width : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRTC Day Alarm Index : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRTC Month Alarm Index : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRTC Century Index : 32\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tBoot Flags (decoded below) : 0000\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tLegacy Devices Supported (V2) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\t8042 Present on ports 60/64 (V2) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tVGA Not Present (V4) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tMSI Not Supported (V4) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPCIe ASPM Not Supported (V4) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tCMOS RTC Not Present (V5) : 0\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tReserved : 00\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tFlags (decoded below) : 00000000\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tWBINVD instruction is operational (V1) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tWBINVD flushes all caches (V1) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tAll CPUs support C1 (V1) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tC2 works on MP system (V1) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tControl Method Power Button (V1) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tControl Method Sleep Button (V1) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tRTC wake not in fixed reg space (V1) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tRTC can wake system from S4 (V1) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\t32-bit PM Timer (V1) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tDocking Supported (V1) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tReset Register Supported (V2) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tSealed Case (V3) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tHeadless - No Video (V3) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tUse native instr after SLP_TYPx (V3) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPCIEXP_WAK Bits Supported (V4) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tUse Platform Timer (V4) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tRTC_STS valid on S4 wake (V4) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tRemote Power-on capable (V4) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tUse APIC Cluster Model (V4) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tUse APIC Physical Destination Mode (V4) : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tHardware Reduced (V5) : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tLow Power S0 Idle (V5) : 0\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tReset Register : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 08\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEncoded Access Width : 01 [Byte Access:8]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000CF9\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0001]\\t\\tValue to cause reset : 06\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tARM Flags (decoded below): 0000\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tPSCI Compliant : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tMust use HVC for PSCI : 0\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tFADT Minor Revision : 01\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tFACS Address : 00000000%08X\\n\",\n\t    basl_acpi_base + FACS_OFFSET);\n\tEFPRINTF(fp, \"[0008]\\t\\tDSDT Address : 00000000%08X\\n\",\n\t    basl_acpi_base + DSDT_OFFSET);\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tPM1A Event Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 20\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEncoded Access Width : 02 [Word Access:16]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 00000000%08X\\n\",\n\t    PM1A_EVT_ADDR);\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tPM1B Event Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp,\n\t    \"[0001]\\t\\tEncoded Access Width : 00 [Undefined/Legacy]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tPM1A Control Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 10\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEncoded Access Width : 02 [Word Access:16]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 00000000%08X\\n\",\n\t    PM1A_CNT_ADDR);\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tPM1B Control Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp,\n\t    \"[0001]\\t\\tEncoded Access Width : 00 [Undefined/Legacy]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tPM2 Control Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 08\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp,\n\t    \"[0001]\\t\\tEncoded Access Width : 00 [Undefined/Legacy]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\t/* Valid for bhyve */\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tPM Timer Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 20\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp,\n\t    \"[0001]\\t\\tEncoded Access Width : 03 [DWord Access:32]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 00000000%08X\\n\",\n\t    IO_PMTMR);\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0012]\\t\\tGPE0 Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEncoded Access Width : 01 [Byte Access:8]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0012]\\t\\tGPE1 Block : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp,\n\t    \"[0001]\\t\\tEncoded Access Width : 00 [Undefined/Legacy]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t   \"[0012]\\t\\tSleep Control Register : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 08\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEncoded Access Width : 01 [Byte Access:8]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tSleep Status Register : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 01 [SystemIO]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 08\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEncoded Access Width : 01 [Byte Access:8]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 0000000000000000\\n\");\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_hpet(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve HPET template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"HPET\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tTable Length : 00000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 00\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tOem Table ID : \\\"BVHPET  \\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOem Revision : 00000001\\n\");\n\n\t/* iasl will fill in the compiler ID/revision fields */\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler ID : \\\"xxxx\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler Revision : 00000000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0004]\\t\\tTimer Block ID : %08X\\n\", hpet_capabilities);\n\tEFPRINTF(fp,\n\t    \"[0012]\\t\\tTimer Block Register : [Generic Address Structure]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tSpace ID : 00 [SystemMemory]\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Width : 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tBit Offset : 00\\n\");\n\tEFPRINTF(fp,\n\t\t \"[0001]\\t\\tEncoded Access Width : 00 [Undefined/Legacy]\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tAddress : 00000000FED00000\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0001]\\t\\tHPET Number : 00\\n\");\n\tEFPRINTF(fp, \"[0002]\\t\\tMinimum Clock Ticks : 0000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tFlags (decoded below) : 00000001\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\t4K Page Protect : 1\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\t64K Page Protect : 0\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_mcfg(FILE *fp)\n{\n\tint err = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve MCFG template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"MCFG\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tTable Length : 00000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tRevision : 01\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tChecksum : 00\\n\");\n\tEFPRINTF(fp, \"[0006]\\t\\tOem ID : \\\"BHYVE \\\"\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tOem Table ID : \\\"BVMCFG  \\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOem Revision : 00000001\\n\");\n\n\t/* iasl will fill in the compiler ID/revision fields */\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler ID : \\\"xxxx\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tAsl Compiler Revision : 00000000\\n\");\n\tEFPRINTF(fp, \"[0008]\\t\\tReserved : 0\\n\");\n\tEFPRINTF(fp, \"\\n\");\n\n\tEFPRINTF(fp, \"[0008]\\t\\tBase Address : %016llx\\n\", pci_ecfg_base());\n\tEFPRINTF(fp, \"[0002]\\t\\tSegment Group: 0000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tStart Bus: 00\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tEnd Bus: FF\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tReserved : 0\\n\");\n\tEFFLUSH(fp);\n\treturn (0);\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_fwrite_facs(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\n\tEFPRINTF(fp, \"/*\\n\");\n\tEFPRINTF(fp, \" * bhyve FACS template\\n\");\n\tEFPRINTF(fp, \" */\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tSignature : \\\"FACS\\\"\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tLength : 00000040\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tHardware Signature : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\t32 Firmware Waking Vector : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tGlobal Lock : 00000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tFlags (decoded below) : 00000000\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\tS4BIOS Support Present : 0\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\t64-bit Wake Supported (V2) : 0\\n\");\n\tEFPRINTF(fp,\n\t    \"[0008]\\t\\t64 Firmware Waking Vector : 0000000000000000\\n\");\n\tEFPRINTF(fp, \"[0001]\\t\\tVersion : 02\\n\");\n\tEFPRINTF(fp, \"[0003]\\t\\tReserved : 000000\\n\");\n\tEFPRINTF(fp, \"[0004]\\t\\tOspmFlags (decoded below) : 00000000\\n\");\n\tEFPRINTF(fp, \"\\t\\t\\t64-bit Wake Env Required (V2) : 0\\n\");\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wformat-nonliteral\"\n/*\n * Helper routines for writing to the DSDT from other modules.\n */\nvoid\ndsdt_line(const char *fmt, ...)\n{\n\tva_list ap;\n\tint err;\n\n\terr = 0;\n\n\tif (dsdt_error != 0)\n\t\treturn;\n\n\tif (strcmp(fmt, \"\") != 0) {\n\t\tif (dsdt_indent_level != 0)\n\t\t\tEFPRINTF(dsdt_fp, \"%*c\", dsdt_indent_level * 2, ' ');\n\t\tva_start(ap, fmt);\n\t\tif (vfprintf(dsdt_fp, fmt, ap) < 0)\n\t\t\tgoto err_exit;\n\t\tva_end(ap);\n\t}\n\tEFPRINTF(dsdt_fp, \"\\n\");\n\treturn;\n\nerr_exit:\n\tdsdt_error = errno;\n}\n#pragma clang diagnostic pop\n\nvoid\ndsdt_indent(int levels)\n{\n\n\tdsdt_indent_level += levels;\n\tassert(dsdt_indent_level >= 0);\n}\n\nvoid\ndsdt_unindent(int levels)\n{\n\n\tassert(dsdt_indent_level >= levels);\n\tdsdt_indent_level -= levels;\n}\n\nvoid\ndsdt_fixed_ioport(uint16_t iobase, uint16_t length)\n{\n\n\tdsdt_line(\"IO (Decode16,\");\n\tdsdt_line(\"  0x%04X,             // Range Minimum\", iobase);\n\tdsdt_line(\"  0x%04X,             // Range Maximum\", iobase);\n\tdsdt_line(\"  0x01,               // Alignment\");\n\tdsdt_line(\"  0x%02X,               // Length\", length);\n\tdsdt_line(\"  )\");\n}\n\nvoid\ndsdt_fixed_irq(uint8_t irq)\n{\n\n\tdsdt_line(\"IRQNoFlags ()\");\n\tdsdt_line(\"  {%d}\", irq);\n}\n\nvoid\ndsdt_fixed_mem32(uint32_t base, uint32_t length)\n{\n\n\tdsdt_line(\"Memory32Fixed (ReadWrite,\");\n\tdsdt_line(\"  0x%08X,         // Address Base\", base);\n\tdsdt_line(\"  0x%08X,         // Address Length\", length);\n\tdsdt_line(\"  )\");\n}\n\nstatic int\nbasl_fwrite_dsdt(FILE *fp)\n{\n\tint err;\n\n\terr = 0;\n\tdsdt_fp = fp;\n\tdsdt_error = 0;\n\tdsdt_indent_level = 0;\n\n\tdsdt_line(\"/*\");\n\tdsdt_line(\" * bhyve DSDT template\");\n\tdsdt_line(\" */\");\n\tdsdt_line(\"DefinitionBlock (\\\"bhyve_dsdt.aml\\\", \\\"DSDT\\\", 2,\"\n\t\t \"\\\"BHYVE \\\", \\\"BVDSDT  \\\", 0x00000001)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_S5, Package ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"      0x05,\");\n\tdsdt_line(\"      Zero,\");\n\tdsdt_line(\"  })\");\n\n\tpci_write_dsdt();\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"  Scope (_SB.PC00)\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Device (HPET)\");\n\tdsdt_line(\"    {\");\n\tdsdt_line(\"      Name (_HID, EISAID(\\\"PNP0103\\\"))\");\n\tdsdt_line(\"      Name (_UID, 0)\");\n\tdsdt_line(\"      Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"      {\");\n\tdsdt_indent(4);\n\tdsdt_fixed_mem32(0xFED00000, 0x400);\n\tdsdt_unindent(4);\n\tdsdt_line(\"      })\");\n\tdsdt_line(\"    }\");\n\tdsdt_line(\"  }\");\n\tdsdt_line(\"}\");\n\n\tif (dsdt_error != 0)\n\t\treturn (dsdt_error);\n\n\tEFFLUSH(fp);\n\n\treturn (0);\n\nerr_exit:\n\treturn (errno);\n}\n\nstatic int\nbasl_open(struct basl_fio *bf, int suffix)\n{\n\tint err;\n\n\terr = 0;\n\n\tif (suffix) {\n\t\tstrlcpy(bf->f_name, basl_stemplate, MAXPATHLEN);\n\t\tbf->fd = mkstemps(bf->f_name, strlen(BHYVE_ASL_SUFFIX));\n\t} else {\n\t\tstrlcpy(bf->f_name, basl_template, MAXPATHLEN);\n\t\tbf->fd = mkstemp(bf->f_name);\n\t}\n\n\tif (bf->fd > 0) {\n\t\tbf->fp = fdopen(bf->fd, \"w+\");\n\t\tif (bf->fp == NULL) {\n\t\t\tunlink(bf->f_name);\n\t\t\tclose(bf->fd);\n\t\t}\n\t} else {\n\t\terr = 1;\n\t}\n\n\treturn (err);\n}\n\nstatic void\nbasl_close(struct basl_fio *bf)\n{\n\n\tif (!basl_keep_temps)\n\t\tunlink(bf->f_name);\n\tfclose(bf->fp);\n}\n\nstatic int\nbasl_start(struct basl_fio *in, struct basl_fio *out)\n{\n\tint err;\n\n\terr = basl_open(in, 0);\n\tif (!err) {\n\t\terr = basl_open(out, 1);\n\t\tif (err) {\n\t\t\tbasl_close(in);\n\t\t}\n\t}\n\n\treturn (err);\n}\n\nstatic void\nbasl_end(struct basl_fio *in, struct basl_fio *out)\n{\n\tbasl_close(in);\n\tbasl_close(out);\n}\n\nstatic int\nbasl_load(int fd, uint64_t off)\n{\n\tstruct stat sb;\n\tvoid *gaddr;\n\n\tif (fstat(fd, &sb) < 0)\n\t\treturn (errno);\n\n\tgaddr = paddr_guest2host(basl_acpi_base + off, ((size_t) sb.st_size));\n\tif (gaddr == NULL)\n\t\treturn (EFAULT);\n\n\tif (read(fd, gaddr, ((size_t) sb.st_size)) < 0)\n\t\treturn (errno);\n\n\treturn (0);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wformat-nonliteral\"\nstatic int\nbasl_compile(int (*fwrite_section)(FILE *), uint64_t offset)\n{\n\tstruct basl_fio io[2];\n\tstatic char iaslbuf[3*MAXPATHLEN + 10];\n\tchar *fmt;\n\tint err;\n\n\terr = basl_start(&io[0], &io[1]);\n\tif (!err) {\n\t\terr = (*fwrite_section)(io[0].fp);\n\n\t\tif (!err) {\n\t\t\t/*\n\t\t\t * iasl sends the results of the compilation to\n\t\t\t * stdout. Shut this down by using the shell to\n\t\t\t * redirect stdout to /dev/null, unless the user\n\t\t\t * has requested verbose output for debugging\n\t\t\t * purposes\n\t\t\t */\n\t\t\tfmt = basl_verbose_iasl ?\n\t\t\t\t\"%s -p %s %s\" :\n\t\t\t\t\"/bin/sh -c \\\"%s -p %s %s\\\" 1> /dev/null\";\n\n\t\t\tsnprintf(iaslbuf, sizeof(iaslbuf),\n\t\t\t\t fmt,\n\t\t\t\t BHYVE_ASL_COMPILER,\n\t\t\t\t io[1].f_name, io[0].f_name);\n\t\t\terr = system(iaslbuf);\n\n\t\t\tif (!err) {\n\t\t\t\t/*\n\t\t\t\t * Copy the aml output file into guest\n\t\t\t\t * memory at the specified location\n\t\t\t\t */\n\t\t\t\terr = basl_load(io[1].fd, offset);\n\t\t\t}\n\t\t}\n\t\tbasl_end(&io[0], &io[1]);\n\t}\n\n\treturn (err);\n}\n#pragma clang diagnostic pop\n\nstatic int\nbasl_make_templates(void)\n{\n\tconst char *tmpdir;\n\tint err;\n\tint len;\n\n\terr = 0;\n\n\t/*\n\t *\n\t */\n\tif ((tmpdir = getenv(\"BHYVE_TMPDIR\")) == NULL || *tmpdir == '\\0' ||\n\t    (tmpdir = getenv(\"TMPDIR\")) == NULL || *tmpdir == '\\0') {\n\t\ttmpdir = _PATH_TMP;\n\t}\n\n\tlen = (int) strlen(tmpdir);\n\n\tif ((((unsigned long) len) + sizeof(BHYVE_ASL_TEMPLATE) + 1) < MAXPATHLEN) {\n\t\tstrcpy(basl_template, tmpdir);\n\t\twhile (len > 0 && basl_template[len - 1] == '/')\n\t\t\tlen--;\n\t\tbasl_template[len] = '/';\n\t\tstrcpy(&basl_template[len + 1], BHYVE_ASL_TEMPLATE);\n\t} else\n\t\terr = E2BIG;\n\n\tif (!err) {\n\t\t/*\n\t\t * len has been intialized (and maybe adjusted) above\n\t\t */\n\t\tif ((((unsigned long) len) + sizeof(BHYVE_ASL_TEMPLATE) + 1 +\n\t\t     sizeof(BHYVE_ASL_SUFFIX)) < MAXPATHLEN) {\n\t\t\tstrcpy(basl_stemplate, tmpdir);\n\t\t\tbasl_stemplate[len] = '/';\n\t\t\tstrcpy(&basl_stemplate[len + 1], BHYVE_ASL_TEMPLATE);\n\t\t\tlen = (int) strlen(basl_stemplate);\n\t\t\tstrcpy(&basl_stemplate[len], BHYVE_ASL_SUFFIX);\n\t\t} else\n\t\t\terr = E2BIG;\n\t}\n\n\treturn (err);\n}\n\nstatic struct {\n\tint\t(*wsect)(FILE *fp);\n\tuint64_t  offset;\n} basl_ftables[] =\n{\n\t{ basl_fwrite_rsdp, 0},\n\t{ basl_fwrite_rsdt, RSDT_OFFSET },\n\t{ basl_fwrite_xsdt, XSDT_OFFSET },\n\t{ basl_fwrite_madt, MADT_OFFSET },\n\t{ basl_fwrite_fadt, FADT_OFFSET },\n\t{ basl_fwrite_hpet, HPET_OFFSET },\n\t{ basl_fwrite_mcfg, MCFG_OFFSET },\n\t{ basl_fwrite_facs, FACS_OFFSET },\n\t{ basl_fwrite_dsdt, DSDT_OFFSET },\n\t{ NULL , 0}\n};\n\nint\nacpi_build(int ncpu)\n{\n\tint err;\n\tint i;\n\n\tbasl_ncpu = ncpu;\n\n\terr = xh_vm_get_hpet_capabilities(&hpet_capabilities);\n\tif (err != 0)\n\t\treturn (err);\n\n\t/*\n\t * For debug, allow the user to have iasl compiler output sent\n\t * to stdout rather than /dev/null\n\t */\n\tif (getenv(\"BHYVE_ACPI_VERBOSE_IASL\"))\n\t\tbasl_verbose_iasl = 1;\n\n\t/*\n\t * Allow the user to keep the generated ASL files for debugging\n\t * instead of deleting them following use\n\t */\n\tif (getenv(\"BHYVE_ACPI_KEEPTMPS\"))\n\t\tbasl_keep_temps = 1;\n\n\ti = 0;\n\terr = basl_make_templates();\n\n\t/*\n\t * Run through all the ASL files, compiling them and\n\t * copying them into guest memory\n\t */\n\twhile (!err && basl_ftables[i].wsect != NULL) {\n\t\terr = basl_compile(basl_ftables[i].wsect,\n\t\t\t\t   basl_ftables[i].offset);\n\t\ti++;\n\t}\n\n\treturn (err);\n}\n"
  },
  {
    "path": "src/acpitbl.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * xhyve ACPI table generator.\n *\n * Does not require iasl but DSDT is limited to 1 PCI bus (0) and 8 devices.\n *\n * slot 0 hostbridge\n * slot 31 lpc\n */\n\n/*\n * The tables are placed in the guest's ROM area just below 1MB physical,\n * above the MPTable.\n *\n *  Layout\n *  ------\n *   RSDP  ->   0xf2400    (36 bytes fixed)\n *     RSDT  ->   0xf2440    (36 bytes + 4*7 table addrs, 4 used)\n *     XSDT  ->   0xf2480    (36 bytes + 8*7 table addrs, 4 used)\n *       MADT  ->   0xf2500  (depends on #CPUs)\n *       FADT  ->   0xf2600  (268 bytes)\n *       HPET  ->   0xf2740  (56 bytes)\n *       MCFG  ->   0xf2780  (60 bytes)\n *         FACS  ->   0xf27C0 (64 bytes)\n *         DSDT  ->   0xf2800 (variable - can go up to 0x100000)\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include <errno.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/acpi.h>\n\n#define XHYVE_ACPI_BASE 0xf2400\n#define XHYVE_ACPI_SIZE 0xdc00\n#define RSDT_OFFSET 0x040\n#define XSDT_OFFSET 0x080\n#define MADT_OFFSET 0x100\n#define FADT_OFFSET 0x200\n#define HPET_OFFSET 0x340\n#define MCFG_OFFSET 0x380\n#define FACS_OFFSET 0x3C0\n#define DSDT_OFFSET 0x400\n\n/* ACPI table base in guest memory */\nstatic void *tb;\nstatic int acpi_ncpu;\nstatic uint32_t hpet_capabilities;\nstatic void *dsdt;\n\nvoid\ndsdt_line(UNUSED const char *fmt, ...)\n{\n}\n\nvoid\ndsdt_fixed_ioport(UNUSED uint16_t iobase, UNUSED uint16_t length)\n{\n}\n\nvoid\ndsdt_fixed_irq(UNUSED uint8_t irq)\n{\n}\n\nvoid\ndsdt_fixed_mem32(UNUSED uint32_t base, UNUSED uint32_t length)\n{\n}\n\nvoid\ndsdt_indent(UNUSED int levels)\n{\n}\n\nvoid dsdt_unindent(UNUSED int levels)\n{\n}\n\nstatic uint8_t\nacpitbl_checksum(void *table, size_t length) {\n\tunsigned int i;\n\tuint8_t sum;\n\n\tfor (sum = 0, i = 0; i < length; i++) {\n\t\tsum += ((uint8_t *) table)[i];\n\t}\n\n\treturn (((uint8_t) 0) - sum);\n}\n\nstatic void\nacpitbl_write8(void *base, uint64_t offset, uint8_t val) {\n\tmemcpy(((void *) (((uintptr_t) base) + offset)), &val, 1);\n}\n\nstatic void\nacpitbl_write16(void *base, uint64_t offset, uint16_t val) {\n\tmemcpy(((void *) (((uintptr_t) base) + offset)), &val, 2);\n}\n\nstatic void\nacpitbl_write32(void *base, uint64_t offset, uint32_t val) {\n\tmemcpy(((void *) (((uintptr_t) base) + offset)), &val, 4);\n}\n\nstatic void\nacpitbl_write64(void *base, uint64_t offset, uint64_t val) {\n\tmemcpy(((void *) (((uintptr_t) base) + offset)), &val, 8);\n}\n\nstatic void\nacpitbl_build_rdsp(void) {\n\tvoid *rdsp;\n\t/*\n\t * [000h 0000  8]                    Signature : \"RSD PTR \"\n\t * [008h 0008  1]                     Checksum : 00\n\t * [009h 0009  6]                       Oem ID : \"BHYVE \"\n\t * [00Fh 0015  1]                     Revision : 02\n\t * [010h 0016  4]                 RSDT Address : 00000000\n\t * [014h 0020  4]                       Length : 00000024\n\t * [018h 0024  8]                 XSDT Address : 0000000000000000\n\t * [020h 0032  1]            Extended Checksum : 00\n\t * [021h 0033  3]                     Reserved : 000000\n\t */\n\tstatic const uint8_t rdsp_tmpl[36] = {\n\t\t0x52, 0x53, 0x44, 0x20, 0x50, 0x54, 0x52, 0x20,\n\t\t0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20, 0x02,\n\t\t0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00\n\t};\n\n\trdsp = (void *) (((uintptr_t) tb) + 0);\n\t/* copy RDSP template to guest memory */\n\tmemcpy(rdsp, rdsp_tmpl, 36);\n\t/* fixup table */\n\tacpitbl_write32(rdsp, 0x10, ((uint32_t) (XHYVE_ACPI_BASE + RSDT_OFFSET)));\n\tacpitbl_write64(rdsp, 0x18, ((uint64_t) (XHYVE_ACPI_BASE + XSDT_OFFSET)));\n\t/* write checksum */\n\tacpitbl_write8(rdsp, 0x8, acpitbl_checksum(rdsp, 20));\n\t/* write extended checksum */\n\tacpitbl_write8(rdsp, 0x20, acpitbl_checksum(rdsp, 36));\n}\n\nstatic void\nacpitbl_build_rsdt(void) {\n\tvoid *rsdt;\n\t/*\n\t * [000h 0000  4]                    Signature : \"RSDT\"\n\t * [004h 0004  4]                 Table Length : 00000034\n\t * [008h 0008  1]                     Revision : 01\n\t * [009h 0009  1]                     Checksum : 00\n\t * [00Ah 0010  6]                       Oem ID : \"BHYVE \"\n\t * [010h 0016  8]                 Oem Table ID : \"BVRSDT  \"\n\t * [018h 0024  4]                 Oem Revision : 00000001\n\t * [01Ch 0028  4]              Asl Compiler ID : \"INTL\"\n\t * [020h 0032  4]        Asl Compiler Revision : 20140828\n\t * [024h 0036  4]       ACPI Table Address   0 : 00000000\n\t * [028h 0040  4]       ACPI Table Address   1 : 00000000\n\t * [02Ch 0044  4]       ACPI Table Address   2 : 00000000\n\t * [030h 0048  4]       ACPI Table Address   3 : 00000000\n\t */\n\tstatic const uint8_t rsdt_tmpl[52] = {\n\t\t0x52, 0x53, 0x44, 0x54, 0x34, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n\t\t0x42, 0x56, 0x52, 0x53, 0x44, 0x54, 0x20, 0x20,\n\t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,\n\t\t0x28, 0x08, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00\n\t};\n\n\trsdt = (void *) (((uintptr_t) tb) + RSDT_OFFSET);\n\t/* copy RSDT template to guest memory */\n\tmemcpy(rsdt, rsdt_tmpl, 52);\n\t/* fixup table */\n\tacpitbl_write32(rsdt, 0x24, ((uint32_t) (XHYVE_ACPI_BASE + MADT_OFFSET)));\n\tacpitbl_write32(rsdt, 0x28, ((uint32_t) (XHYVE_ACPI_BASE + FADT_OFFSET)));\n\tacpitbl_write32(rsdt, 0x2c, ((uint32_t) (XHYVE_ACPI_BASE + HPET_OFFSET)));\n\tacpitbl_write32(rsdt, 0x30, ((uint32_t) (XHYVE_ACPI_BASE + MCFG_OFFSET)));\n\t/* write checksum */\n\tacpitbl_write8(rsdt, 0x9, acpitbl_checksum(rsdt, 52));\n}\n\nstatic void\nacpitbl_build_xsdt(void) {\n\tvoid *xsdt;\n\t/*\n\t * [000h 0000  4]                    Signature : \"XSDT\"\n\t * [004h 0004  4]                 Table Length : 00000044\n\t * [008h 0008  1]                     Revision : 01\n\t * [009h 0009  1]                     Checksum : 00\n\t * [00Ah 0010  6]                       Oem ID : \"BHYVE \"\n\t * [010h 0016  8]                 Oem Table ID : \"BVXSDT  \"\n\t * [018h 0024  4]                 Oem Revision : 00000001\n\t * [01Ch 0028  4]              Asl Compiler ID : \"INTL\"\n\t * [020h 0032  4]        Asl Compiler Revision : 20140828\n\t * [024h 0036  8]       ACPI Table Address   0 : 0000000000000000\n\t * [02Ch 0044  8]       ACPI Table Address   1 : 0000000000000000\n\t * [034h 0052  8]       ACPI Table Address   2 : 0000000000000000\n\t * [03Ch 0060  8]       ACPI Table Address   3 : 0000000000000000\n\t */\n\tstatic const uint8_t xsdt_tmpl[68] = {\n  \t\t0x58, 0x53, 0x44, 0x54, 0x44, 0x00, 0x00, 0x00,\n  \t\t0x01, 0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n  \t\t0x42, 0x56, 0x58, 0x53, 0x44, 0x54, 0x20, 0x20,\n  \t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,\n  \t\t0x28, 0x08, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00,\n  \t\t0x00, 0x00, 0x00, 0x00,\t0x00, 0x00, 0x00, 0x00,\n  \t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  \t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  \t\t0x00, 0x00, 0x00, 0x00\n\t};\n\n\txsdt = (void *) (((uintptr_t) tb) + XSDT_OFFSET);\n\t/* copy XSDT template to guest memory */\n\tmemcpy(xsdt, xsdt_tmpl, 68);\n\t/* fixup table */\n\tacpitbl_write64(xsdt, 0x24, ((uint64_t) (XHYVE_ACPI_BASE + MADT_OFFSET)));\n\tacpitbl_write64(xsdt, 0x2c, ((uint64_t) (XHYVE_ACPI_BASE + FADT_OFFSET)));\n\tacpitbl_write64(xsdt, 0x34, ((uint64_t) (XHYVE_ACPI_BASE + HPET_OFFSET)));\n\tacpitbl_write64(xsdt, 0x3c, ((uint64_t) (XHYVE_ACPI_BASE + MCFG_OFFSET)));\n\t/* write checksum */\n\tacpitbl_write8(xsdt, 0x9, acpitbl_checksum(xsdt, 68));\n}\n\nstatic void\nacpitbl_build_madt(void) {\n\tvoid *madt_head, *madt_apic, *madt_tail;\n\tint i;\n\t/*\n\t * [000h 0000  4]                    Signature : \"APIC\"\n\t * [004h 0004  4]                 Table Length : 00000000\n\t * [008h 0008  1]                     Revision : 01\n\t * [009h 0009  1]                     Checksum : 4E\n\t * [00Ah 0010  6]                       Oem ID : \"BHYVE \"\n\t * [010h 0016  8]                 Oem Table ID : \"BVMADT  \"\n\t * [018h 0024  4]                 Oem Revision : 00000001\n\t * [01Ch 0028  4]              Asl Compiler ID : \"INTL\"\n\t * [020h 0032  4]        Asl Compiler Revision : 20140828\n\t * [024h 0036  4]           Local Apic Address : FEE00000\n\t * [028h 0040  4]        Flags (decoded below) : 00000001\n     *                         PC-AT Compatibility : 1\n\t */\n\tstatic const uint8_t madt_head_tmpl[44] = {\n\t\t0x41, 0x50, 0x49, 0x43, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n\t\t0x42, 0x56, 0x4D, 0x41, 0x44, 0x54, 0x20, 0x20,\n\t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,\n\t\t0x28, 0x08, 0x14, 0x20, 0x00, 0x00, 0xE0, 0xFE,\n\t\t0x01, 0x00, 0x00, 0x00,\n\t};\n\t/*\n\t * [+000h +0000  1]              Subtable Type : 00 <Processor Local APIC>\n\t * [+001h +0001  1]                     Length : 08\n\t * [+002h +0002  1]               Processor ID : 00\n\t * [+003h +0003  1]              Local Apic ID : 00\n\t * [+004h +0004  4]      Flags (decoded below) : 00000001\n\t *                           Processor Enabled : 1\n\t */\n\tstatic const uint8_t madt_apic_tmpl[8] = {\n\t\t0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t};\n\t/*\n\t * [+000h +0000  1]              Subtable Type : 01 <I/O APIC>\n\t * [+001h +0001  1]                     Length : 0C\n\t * [+002h +0002  1]                I/O Apic ID : 00\n\t * [+003h +0003  1]                   Reserved : 00\n\t * [+004h +0004  4]                    Address : FEC00000\n\t * [+008h +0008  4]                  Interrupt : 00000000\n\t * [+00Ch +0012  1]              Subtable Type : 02 <IRQ Source Override>\n\t * [+00Dh +0013  1]                     Length : 0A\n\t * [+00Eh +0014  1]                        Bus : 00\n\t * [+00Fh +0015  1]                     Source : 00\n\t * [+010h +0016  4]                  Interrupt : 00000002\n\t * [+014h +0020  2]      Flags (decoded below) : 0005\n\t *                                  Polarity : 1\n\t *                              Trigger Mode : 1\n\t * [+016h +0022  1]              Subtable Type : 02 <IRQ Source Override>\n\t * [+017h +0023  1]                     Length : 0A\n\t * [+018h +0024  1]                        Bus : 00\n\t * [+019h +0025  1]                     Source : 00\n\t * [+01Ah +0026  4]                  Interrupt : 00000000\n\t * [+01Eh +0030  2]      Flags (decoded below) : 000F\n\t *                                  Polarity : 3\n\t *                              Trigger Mode : 3\n\t * [+020h +0032  1]              Subtable Type : 04 <Local APIC NMI>\n\t * [+021h +0033  1]                     Length : 06\n\t * [+022h +0034  1]               Processor ID : FF\n\t * [+023h +0035  2]      Flags (decoded below) : 0005\n\t *                                  Polarity : 1\n\t *                              Trigger Mode : 1\n\t * [+025h +0037  1]       Interrupt Input LINT : 01\n\t */\n\tstatic const uint8_t madt_tail_tmpl[38] = {\n\t\t0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFE,\n\t\t0x00, 0x00, 0x00, 0x00, 0x02, 0x0A, 0x00, 0x00,\n\t\t0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x0A,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00,\n\t\t0x04, 0x06, 0xFF, 0x05, 0x00, 0x01\n\t};\n\n\tmadt_head = (void *) (((uintptr_t) tb) + MADT_OFFSET);\n\t/* copy MADT head template to guest memory */\n\tmemcpy(madt_head, madt_head_tmpl, 44);\n\n\tfor (i = 0; i < acpi_ncpu; i++) {\n\t\tmadt_apic = (void *) (((uintptr_t) tb)\n\t\t\t+ ((size_t) ((MADT_OFFSET + 44) + (8 * i))));\n\t\t/* copy MADT APIC template to guest memory */\n\t\tmemcpy(madt_apic, madt_apic_tmpl, 8);\n\t\t/* fixup table */\n\t\tacpitbl_write8(madt_apic, 0x2, ((uint8_t) i));\n\t\tacpitbl_write8(madt_apic, 0x3, ((uint8_t) i));\n\t}\n\n\tmadt_tail = (void *) (((uintptr_t) tb)\n\t\t+ ((size_t) ((MADT_OFFSET + 44) + (8 * acpi_ncpu))));\n\t/* copy MADT tail template to guest memory */\n\tmemcpy(madt_tail, madt_tail_tmpl, 38);\n\t/* fixup table */\n\tacpitbl_write8(madt_tail, 0x2, 0);\n\tacpitbl_write8(madt_tail, 0x19, SCI_INT);\n\tacpitbl_write32(madt_tail, 0x1a, SCI_INT);\n\t/* write checksum */\n\tacpitbl_write32(madt_head, 0x4, ((uint32_t) (44 + (8 * acpi_ncpu) + 38)));\n\tacpitbl_write8(madt_head, 0x9,\n\t\tacpitbl_checksum(madt_head, ((size_t) (44 + (8 * acpi_ncpu) + 38))));\n}\n\nstatic void\nacpitbl_build_fadt(void) {\n\tvoid *fadt;\n\t/*\n\t * [000h 0000  4]                    Signature : \"FACP\"\n\t * [004h 0004  4]                 Table Length : 0000010C\n\t * [008h 0008  1]                     Revision : 05\n\t * [009h 0009  1]                     Checksum : 00\n\t * [00Ah 0010  6]                       Oem ID : \"BHYVE \"\n\t * [010h 0016  8]                 Oem Table ID : \"BVFACP  \"\n\t * [018h 0024  4]                 Oem Revision : 00000001\n\t * [01Ch 0028  4]              Asl Compiler ID : \"INTL\"\n\t * [020h 0032  4]        Asl Compiler Revision : 20140828\n\t * [024h 0036  4]                 FACS Address : 00000000\n\t * [028h 0040  4]                 DSDT Address : 00000000\n\t * [02Ch 0044  1]                        Model : 01\n\t * [02Dh 0045  1]                   PM Profile : 00 (Unspecified)\n\t * [02Eh 0046  2]                SCI Interrupt : 0000\n\t * [030h 0048  4]             SMI Command Port : 00000000\n\t * [034h 0052  1]            ACPI Enable Value : 00\n\t * [035h 0053  1]           ACPI Disable Value : 00\n\t * [036h 0054  1]               S4BIOS Command : 00\n\t * [037h 0055  1]              P-State Control : 00\n\t * [038h 0056  4]     PM1A Event Block Address : 00000000\n\t * [03Ch 0060  4]     PM1B Event Block Address : 00000000\n\t * [040h 0064  4]   PM1A Control Block Address : 00000000\n\t * [044h 0068  4]   PM1B Control Block Address : 00000000\n\t * [048h 0072  4]    PM2 Control Block Address : 00000000\n\t * [04Ch 0076  4]       PM Timer Block Address : 00000000\n\t * [050h 0080  4]           GPE0 Block Address : 00000000\n\t * [054h 0084  4]           GPE1 Block Address : 00000000\n\t * [058h 0088  1]       PM1 Event Block Length : 04\n\t * [059h 0089  1]     PM1 Control Block Length : 02\n\t * [05Ah 0090  1]     PM2 Control Block Length : 00\n\t * [05Bh 0091  1]        PM Timer Block Length : 04\n\t * [05Ch 0092  1]            GPE0 Block Length : 00\n\t * [05Dh 0093  1]            GPE1 Block Length : 00\n\t * [05Eh 0094  1]             GPE1 Base Offset : 00\n\t * [05Fh 0095  1]                 _CST Support : 00\n\t * [060h 0096  2]                   C2 Latency : 0000\n\t * [062h 0098  2]                   C3 Latency : 0000\n\t * [064h 0100  2]               CPU Cache Size : 0000\n\t * [066h 0102  2]           Cache Flush Stride : 0000\n\t * [068h 0104  1]            Duty Cycle Offset : 00\n\t * [069h 0105  1]             Duty Cycle Width : 00\n\t * [06Ah 0106  1]          RTC Day Alarm Index : 00\n\t * [06Bh 0107  1]        RTC Month Alarm Index : 00\n\t * [06Ch 0108  1]            RTC Century Index : 32\n\t * [06Dh 0109  2]   Boot Flags (decoded below) : 0014\n\t *               Legacy Devices Supported (V2) : 0\n\t *            8042 Present on ports 60/64 (V2) : 0\n\t *                        VGA Not Present (V4) : 1\n\t *                      MSI Not Supported (V4) : 0\n\t *                PCIe ASPM Not Supported (V4) : 1\n\t * [06Fh 0111  1]                     Reserved : 00\n\t * [070h 0112  4]        Flags (decoded below) : 00081525\n\t *      WBINVD instruction is operational (V1) : 1\n\t *              WBINVD flushes all caches (V1) : 0\n\t *                    All CPUs support C1 (V1) : 1\n\t *                  C2 works on MP system (V1) : 0\n\t *            Control Method Power Button (V1) : 0\n\t *            Control Method Sleep Button (V1) : 1\n\t *        RTC wake not in fixed reg space (V1) : 0\n\t *            RTC can wake system from S4 (V1) : 0\n\t *                        32-bit PM Timer (V1) : 1\n\t *                      Docking Supported (V1) : 0\n\t *               Reset Register Supported (V2) : 1\n\t *                            Sealed Case (V3) : 0\n\t *                    Headless - No Video (V3) : 1\n\t *        Use native instr after SLP_TYPx (V3) : 0\n\t *              PCIEXP_WAK Bits Supported (V4) : 0\n\t *                     Use Platform Timer (V4) : 0\n\t *               RTC_STS valid on S4 wake (V4) : 0\n\t *                Remote Power-on capable (V4) : 0\n\t *                 Use APIC Cluster Model (V4) : 0\n\t *     Use APIC Physical Destination Mode (V4) : 1\n\t * [074h 0116 12]               Reset Register : <Generic Address Structure>\n\t * [074h 0116  1]                     Space ID : 01 (SystemIO)\n\t * [075h 0117  1]                    Bit Width : 08\n\t * [076h 0118  1]                   Bit Offset : 00\n\t * [077h 0119  1]                 Access Width : 01\n\t * [078h 0120  8]                      Address : 0000000000000CF9\n\t * [080h 0128  1]         Value to cause reset : 06\n\t * [081h 0129  3]                     Reserved : 000001\n\t * [084h 0132  8]                 FACS Address : 0000000000000000\n\t * [08Ch 0140  8]                 DSDT Address : 0000000000000000\n\t * [094h 0148 12]             PM1A Event Block : <Generic Address Structure>\n\t * [094h 0148  1]                     Space ID : 01 (SystemIO)\n\t * [095h 0149  1]                    Bit Width : 20\n\t * [096h 0150  1]                   Bit Offset : 00\n\t * [097h 0151  1]                 Access Width : 02\n\t * [098h 0152  8]                      Address : 0000000000000000\n\t * [0A0h 0160 12]             PM1B Event Block : <Generic Address Structure>\n\t * [0A0h 0160  1]                     Space ID : 01 (SystemIO)\n\t * [0A1h 0161  1]                    Bit Width : 00\n\t * [0A2h 0162  1]                   Bit Offset : 00\n\t * [0A3h 0163  1]                 Access Width : 00\n\t * [0A4h 0164  8]                      Address : 0000000000000000\n\t * [0ACh 0172 12]           PM1A Control Block : <Generic Address Structure>\n\t * [0ACh 0172  1]                     Space ID : 01 (SystemIO)\n\t * [0ADh 0173  1]                    Bit Width : 10\n\t * [0AEh 0174  1]                   Bit Offset : 00\n\t * [0AFh 0175  1]                 Access Width : 02\n\t * [0B0h 0176  8]                      Address : 0000000000000000\n\t * [0B8h 0184 12]           PM1B Control Block : <Generic Address Structure>\n\t * [0B8h 0184  1]                     Space ID : 01 (SystemIO)\n\t * [0B9h 0185  1]                    Bit Width : 00\n\t * [0BAh 0186  1]                   Bit Offset : 00\n\t * [0BBh 0187  1]                 Access Width : 00\n\t * [0BCh 0188  8]                      Address : 0000000000000000\n\t * [0C4h 0196 12]            PM2 Control Block : <Generic Address Structure>\n\t * [0C4h 0196  1]                     Space ID : 01 (SystemIO)\n\t * [0C5h 0197  1]                    Bit Width : 08\n\t * [0C6h 0198  1]                   Bit Offset : 00\n\t * [0C7h 0199  1]                 Access Width : 00\n\t * [0C8h 0200  8]                      Address : 0000000000000000\n\t * [0D0h 0208 12]               PM Timer Block : <Generic Address Structure>\n\t * [0D0h 0208  1]                     Space ID : 01 (SystemIO)\n\t * [0D1h 0209  1]                    Bit Width : 20\n\t * [0D2h 0210  1]                   Bit Offset : 00\n\t * [0D3h 0211  1]                 Access Width : 03\n\t * [0D4h 0212  8]                      Address : 0000000000000000\n\t * [0DCh 0220 12]                   GPE0 Block : <Generic Address Structure>\n\t * [0DCh 0220  1]                     Space ID : 01 (SystemIO)\n\t * [0DDh 0221  1]                    Bit Width : 00\n\t * [0DEh 0222  1]                   Bit Offset : 00\n\t * [0DFh 0223  1]                 Access Width : 01\n\t * [0E0h 0224  8]                      Address : 0000000000000000\n\t * [0E8h 0232 12]                   GPE1 Block : <Generic Address Structure>\n\t * [0E8h 0232  1]                     Space ID : 01 (SystemIO)\n\t * [0E9h 0233  1]                    Bit Width : 00\n\t * [0EAh 0234  1]                   Bit Offset : 00\n\t * [0EBh 0235  1]                 Access Width : 00\n\t * [0ECh 0236  8]                      Address : 0000000000000000\n\t * [0F4h 0244 12]       Sleep Control Register : <Generic Address Structure>\n\t * [0F4h 0244  1]                     Space ID : 01 (SystemIO)\n\t * [0F5h 0245  1]                    Bit Width : 08\n\t * [0F6h 0246  1]                   Bit Offset : 00\n\t * [0F7h 0247  1]                 Access Width : 01\n\t * [0F8h 0248  8]                      Address : 0000000000000000\n\t * [100h 0256 12]        Sleep Status Register : <Generic Address Structure>\n\t * [100h 0256 01]                     Space ID : 01 (SystemIO)\n\t * [101h 0257 01]                    Bit Width : 08\n\t * [102h 0258 01]                   Bit Offset : 00\n\t * [103h 0259 01]                 Access Width : 01\n\t * [104h 0260 08]                      Address : 0000000000000000\n\t */\n\tstatic const uint8_t fadt_tmpl[268] = {\n\t\t0x46, 0x41, 0x43, 0x50, 0x0C, 0x01, 0x00, 0x00,\n\t\t0x05, 0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n\t\t0x42, 0x56, 0x46, 0x41, 0x43, 0x50, 0x20, 0x20,\n\t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,\n\t\t0x28, 0x08, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x04, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x32, 0x14, 0x00, 0x00,\n\t\t0x25, 0x15, 0x08, 0x00, 0x01, 0x08, 0x00, 0x01,\n\t\t0xF9, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x02,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x02,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x01,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x01, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00\n\t};\n\n\tfadt = (void *) (((uintptr_t) tb) + FADT_OFFSET);\n\t/* copy FADT template to guest memory */\n\tmemcpy(fadt, fadt_tmpl, 268);\n\t/* fixup table */\n\tacpitbl_write32(fadt, 0x24, ((uint32_t) (XHYVE_ACPI_BASE + FACS_OFFSET)));\n\tacpitbl_write32(fadt, 0x28, ((uint32_t) (XHYVE_ACPI_BASE + DSDT_OFFSET)));\n\tacpitbl_write16(fadt, 0x2e, SCI_INT);\n\tacpitbl_write32(fadt, 0x30, SMI_CMD);\n\tacpitbl_write8(fadt, 0x34, BHYVE_ACPI_ENABLE);\n\tacpitbl_write8(fadt, 0x35, BHYVE_ACPI_DISABLE);\n\tacpitbl_write32(fadt, 0x38, PM1A_EVT_ADDR);\n\tacpitbl_write32(fadt, 0x40, PM1A_CNT_ADDR);\n\tacpitbl_write32(fadt, 0x4c, IO_PMTMR);\n\tacpitbl_write64(fadt, 0x84, ((uint64_t) (XHYVE_ACPI_BASE + FACS_OFFSET)));\n\tacpitbl_write64(fadt, 0x8c, ((uint64_t) (XHYVE_ACPI_BASE + DSDT_OFFSET)));\n\tacpitbl_write64(fadt, 0x98, ((uint64_t) PM1A_EVT_ADDR));\n\tacpitbl_write64(fadt, 0xb0, ((uint64_t) PM1A_CNT_ADDR));\n\tacpitbl_write64(fadt, 0xd4, ((uint64_t) IO_PMTMR));\n\t/* write checksum */\n\tacpitbl_write8(fadt, 0x9, acpitbl_checksum(fadt, 268));\n}\n\nstatic void\nacpitbl_build_hpet(void) {\n\tvoid *hpet;\n\t/*\n\t * [000h 0000  4]                    Signature : \"HPET\"\n\t * [004h 0004  4]                 Table Length : 00000038\n\t * [008h 0008  1]                     Revision : 01\n\t * [009h 0009  1]                     Checksum : 00\n\t * [00Ah 0010  6]                       Oem ID : \"BHYVE \"\n\t * [010h 0016  8]                 Oem Table ID : \"BVHPET  \"\n\t * [018h 0024  4]                 Oem Revision : 00000001\n\t * [01Ch 0028  4]              Asl Compiler ID : \"INTL\"\n\t * [020h 0032  4]        Asl Compiler Revision : 20140828\n\t * [024h 0036  4]            Hardware Block ID : 00000000\n\t * [028h 0040 12]         Timer Block Register : <Generic Address Structure>\n\t * [028h 0040  1]                     Space ID : 00 (SystemMemory)\n\t * [029h 0041  1]                    Bit Width : 00\n\t * [02Ah 0042  1]                   Bit Offset : 00\n\t * [02Bh 0043  1]                 Access Width : 00\n\t * [02Ch 0044  8]                      Address : 00000000FED00000\n\t * [034h 0052  1]              Sequence Number : 00\n\t * [035h 0053  2]          Minimum Clock Ticks : 0000\n\t * [037h 0055  1]        Flags (decoded below) : 01\n\t *                             4K Page Protect : 1\n\t *                            64K Page Protect : 0\n\t */\n\tstatic const uint8_t hpet_tmpl[56] = {\n\t\t0x48, 0x50, 0x45, 0x54, 0x38, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n\t\t0x42, 0x56, 0x48, 0x50, 0x45, 0x54, 0x20, 0x20,\n\t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,\n\t\t0x28, 0x08, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xFE,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01\n\t};\n\n\thpet = (void *) (((uintptr_t) tb) + HPET_OFFSET);\n\t/* copy HPET template to guest memory */\n\tmemcpy(hpet, hpet_tmpl, 56);\n\t/* fixup table */\n\tacpitbl_write32(hpet, 0x24, hpet_capabilities);\n\t/* write checksum */\n\tacpitbl_write8(hpet, 0x9, acpitbl_checksum(hpet, 56));\n}\n\nstatic void\nacpitbl_build_mcfg(void) {\n\tvoid *mcfg;\n\t/*\n\t * [000h 0000  4]                    Signature : \"MCFG\"\n\t * [004h 0004  4]                 Table Length : 0000003C\n\t * [008h 0008  1]                     Revision : 01\n\t * [009h 0009  1]                     Checksum : 00\n\t * [00Ah 0010  6]                       Oem ID : \"BHYVE \"\n\t * [010h 0016  8]                 Oem Table ID : \"BVMCFG  \"\n\t * [018h 0024  4]                 Oem Revision : 00000001\n\t * [01Ch 0028  4]              Asl Compiler ID : \"INTL\"\n\t * [020h 0032  4]        Asl Compiler Revision : 20140828\n\t * [024h 0036  8]                     Reserved : 0000000000000000\n\t * [02Ch 0044  8]                 Base Address : 0000000000000000\n\t * [034h 0052  2]         Segment Group Number : 0000\n\t * [036h 0054  1]             Start Bus Number : 00\n\t * [037h 0055  1]               End Bus Number : FF\n\t * [038h 0056  4]                     Reserved : 00000000\n\t */\n\tstatic const uint8_t mcfg_tmpl[60] = {\n\t\t0x4D, 0x43, 0x46, 0x47, 0x3C, 0x00, 0x00, 0x00,\n\t\t0x01, 0x00, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n\t\t0x42, 0x56, 0x4D, 0x43, 0x46, 0x47, 0x20, 0x20,\n\t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4E, 0x54, 0x4C,\n\t\t0x28, 0x08, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,\n\t\t0x00, 0x00, 0x00, 0x00\n\t};\n\n\tmcfg = (void *) (((uintptr_t) tb) + MCFG_OFFSET);\n\t/* copy MCFG template to guest memory */\n\tmemcpy(mcfg, mcfg_tmpl, 60);\n\t/* fixup table */\n\tacpitbl_write64(mcfg, 0x2c, pci_ecfg_base());\n\t/* write checksum */\n\tacpitbl_write8(mcfg, 0x9, acpitbl_checksum(mcfg, 60));\n}\n\nstatic void\nacpitbl_build_facs(void) {\n\tvoid *facs;\n\t/*\n\t * [000h 0000  4]                    Signature : \"FACS\"\n\t * [004h 0004  4]                       Length : 00000040\n\t * [008h 0008  4]           Hardware Signature : 00000000\n\t * [00Ch 0012  4]    32 Firmware Waking Vector : 00000000\n\t * [010h 0016  4]                  Global Lock : 00000000\n\t * [014h 0020  4]        Flags (decoded below) : 00000000\n\t *                      S4BIOS Support Present : 0\n\t *                  64-bit Wake Supported (V2) : 0\n\t * [018h 0024  8]    64 Firmware Waking Vector : 0000000000000000\n\t * [020h 0032  1]                      Version : 02\n\t * [021h 0033  3]                     Reserved : 000000\n\t * [024h 0036  4]    OspmFlags (decoded below) : 00000000\n\t *               64-bit Wake Env Required (V2) : 0\n\t */\n\tstatic const uint8_t facs_tmpl[64] = {\n\t\t0x46, 0x41, 0x43, 0x53, 0x40, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\t};\n\n\tfacs = (void *) (((uintptr_t) tb) + FACS_OFFSET);\n\t/* copy MCFG template to guest memory */\n\tmemcpy(facs, facs_tmpl, 64);\n}\n\nvoid dsdt_fixup(int bus, uint16_t iobase, uint16_t iolimit, uint32_t membase32,\n\tuint32_t memlimit32, uint64_t membase64, uint64_t memlimit64)\n{\n\tif (bus != 0) {\n\t\tfprintf(stderr, \"DSDT, unsupported PCI bus (%d)\\n\", bus);\n\t\texit(-1);\n\t}\n\n\tacpitbl_write16(dsdt, 0xb6, iobase);\n\tacpitbl_write16(dsdt, 0xb8, (iolimit - 1));\n\tacpitbl_write16(dsdt, 0xbc, (iolimit - iobase));\n\tacpitbl_write32(dsdt, 0xc8, membase32);\n\tacpitbl_write32(dsdt, 0xcc, (memlimit32 - 1));\n\tacpitbl_write32(dsdt, 0xd4, (memlimit32 - membase32));\n\tacpitbl_write64(dsdt, 0xe6, membase64);\n\tacpitbl_write64(dsdt, 0xee, (memlimit64 - 1));\n\tacpitbl_write64(dsdt, 0xfe, (memlimit64 - membase64));\n}\n\nstatic void\nacpitbl_build_dsdt(void) {\n\tstatic const uint8_t dsdt_tmpl[2604] = {\n\t\t0x44, 0x53, 0x44, 0x54, 0x2d, 0x0a, 0x00, 0x00,\n\t\t0x02, 0x5d, 0x42, 0x48, 0x59, 0x56, 0x45, 0x20,\n\t\t0x42, 0x56, 0x44, 0x53, 0x44, 0x54, 0x20, 0x20,\n\t\t0x01, 0x00, 0x00, 0x00, 0x49, 0x4e, 0x54, 0x4c,\n\t\t0x28, 0x08, 0x14, 0x20, 0x08, 0x5f, 0x53, 0x35,\n\t\t0x5f, 0x12, 0x05, 0x02, 0x0a, 0x05, 0x00, 0x08,\n\t\t0x50, 0x49, 0x43, 0x4d, 0x0a, 0x00, 0x14, 0x0c,\n\t\t0x5f, 0x50, 0x49, 0x43, 0x01, 0x70, 0x68, 0x50,\n\t\t0x49, 0x43, 0x4d, 0x10, 0x4f, 0x9a, 0x5f, 0x53,\n\t\t0x42, 0x5f, 0x5b, 0x82, 0x47, 0x9a, 0x50, 0x43,\n\t\t0x30, 0x30, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c,\n\t\t0x41, 0xd0, 0x0a, 0x03, 0x08, 0x5f, 0x41, 0x44,\n\t\t0x52, 0x00, 0x14, 0x09, 0x5f, 0x42, 0x42, 0x4e,\n\t\t0x00, 0xa4, 0x0a, 0x00, 0x08, 0x5f, 0x43, 0x52,\n\t\t0x53, 0x11, 0x46, 0x09, 0x0a, 0x92, 0x88, 0x0d,\n\t\t0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x47, 0x01,\n\t\t0xf8, 0x0c, 0xf8, 0x0c, 0x01, 0x08, 0x88, 0x0d,\n\t\t0x00, 0x01, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00,\n\t\t0xf7, 0x0c, 0x00, 0x00, 0xf8, 0x0c, 0x88, 0x0d,\n\t\t0x00, 0x01, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x0d,\n\t\t0xff, 0x1f, 0x00, 0x00, 0x00, 0x13, 0x88, 0x0d,\n\t\t0x00, 0x01, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x20,\n\t\t0x1f, 0x20, 0x00, 0x00, 0x20, 0x00, 0x87, 0x17,\n\t\t0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x1f, 0xc0,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,\n\t\t0x8a, 0x2b, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,\n\t\t0x0f, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x10, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x79, 0x00,\n\t\t0x08, 0x50, 0x50, 0x52, 0x54, 0x12, 0x4b, 0x0f,\n\t\t0x08, 0x12, 0x1e, 0x04, 0x0c, 0xff, 0xff, 0x01,\n\t\t0x00, 0x0a, 0x00, 0x5c, 0x2f, 0x04, 0x5f, 0x53,\n\t\t0x42, 0x5f, 0x50, 0x43, 0x30, 0x30, 0x49, 0x53,\n\t\t0x41, 0x5f, 0x4c, 0x4e, 0x4b, 0x41, 0x0a, 0x00,\n\t\t0x12, 0x1e, 0x04, 0x0c, 0xff, 0xff, 0x02, 0x00,\n\t\t0x0a, 0x00, 0x5c, 0x2f, 0x04, 0x5f, 0x53, 0x42,\n\t\t0x5f, 0x50, 0x43, 0x30, 0x30, 0x49, 0x53, 0x41,\n\t\t0x5f, 0x4c, 0x4e, 0x4b, 0x42, 0x0a, 0x00, 0x12,\n\t\t0x1e, 0x04, 0x0c, 0xff, 0xff, 0x03, 0x00, 0x0a,\n\t\t0x00, 0x5c, 0x2f, 0x04, 0x5f, 0x53, 0x42, 0x5f,\n\t\t0x50, 0x43, 0x30, 0x30, 0x49, 0x53, 0x41, 0x5f,\n\t\t0x4c, 0x4e, 0x4b, 0x43, 0x0a, 0x00, 0x12, 0x1e,\n\t\t0x04, 0x0c, 0xff, 0xff, 0x04, 0x00, 0x0a, 0x00,\n\t\t0x5c, 0x2f, 0x04, 0x5f, 0x53, 0x42, 0x5f, 0x50,\n\t\t0x43, 0x30, 0x30, 0x49, 0x53, 0x41, 0x5f, 0x4c,\n\t\t0x4e, 0x4b, 0x44, 0x0a, 0x00, 0x12, 0x1e, 0x04,\n\t\t0x0c, 0xff, 0xff, 0x05, 0x00, 0x0a, 0x00, 0x5c,\n\t\t0x2f, 0x04, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43,\n\t\t0x30, 0x30, 0x49, 0x53, 0x41, 0x5f, 0x4c, 0x4e,\n\t\t0x4b, 0x45, 0x0a, 0x00, 0x12, 0x1e, 0x04, 0x0c,\n\t\t0xff, 0xff, 0x06, 0x00, 0x0a, 0x00, 0x5c, 0x2f,\n\t\t0x04, 0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43, 0x30,\n\t\t0x30, 0x49, 0x53, 0x41, 0x5f, 0x4c, 0x4e, 0x4b,\n\t\t0x46, 0x0a, 0x00, 0x12, 0x1e, 0x04, 0x0c, 0xff,\n\t\t0xff, 0x07, 0x00, 0x0a, 0x00, 0x5c, 0x2f, 0x04,\n\t\t0x5f, 0x53, 0x42, 0x5f, 0x50, 0x43, 0x30, 0x30,\n\t\t0x49, 0x53, 0x41, 0x5f, 0x4c, 0x4e, 0x4b, 0x47,\n\t\t0x0a, 0x00, 0x12, 0x1e, 0x04, 0x0c, 0xff, 0xff,\n\t\t0x08, 0x00, 0x0a, 0x00, 0x5c, 0x2f, 0x04, 0x5f,\n\t\t0x53, 0x42, 0x5f, 0x50, 0x43, 0x30, 0x30, 0x49,\n\t\t0x53, 0x41, 0x5f, 0x4c, 0x4e, 0x4b, 0x48, 0x0a,\n\t\t0x00, 0x08, 0x41, 0x50, 0x52, 0x54, 0x12, 0x4b,\n\t\t0x06, 0x08, 0x12, 0x0c, 0x04, 0x0c, 0xff, 0xff,\n\t\t0x01, 0x00, 0x0a, 0x00, 0x00, 0x0a, 0x10, 0x12,\n\t\t0x0c, 0x04, 0x0c, 0xff, 0xff, 0x02, 0x00, 0x0a,\n\t\t0x00, 0x00, 0x0a, 0x11, 0x12, 0x0c, 0x04, 0x0c,\n\t\t0xff, 0xff, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x0a,\n\t\t0x12, 0x12, 0x0c, 0x04, 0x0c, 0xff, 0xff, 0x04,\n\t\t0x00, 0x0a, 0x00, 0x00, 0x0a, 0x13, 0x12, 0x0c,\n\t\t0x04, 0x0c, 0xff, 0xff, 0x05, 0x00, 0x0a, 0x00,\n\t\t0x00, 0x0a, 0x14, 0x12, 0x0c, 0x04, 0x0c, 0xff,\n\t\t0xff, 0x06, 0x00, 0x0a, 0x00, 0x00, 0x0a, 0x15,\n\t\t0x12, 0x0c, 0x04, 0x0c, 0xff, 0xff, 0x07, 0x00,\n\t\t0x0a, 0x00, 0x00, 0x0a, 0x16, 0x12, 0x0c, 0x04,\n\t\t0x0c, 0xff, 0xff, 0x08, 0x00, 0x0a, 0x00, 0x00,\n\t\t0x0a, 0x17, 0x14, 0x18, 0x5f, 0x50, 0x52, 0x54,\n\t\t0x00, 0xa0, 0x0a, 0x50, 0x49, 0x43, 0x4d, 0xa4,\n\t\t0x41, 0x50, 0x52, 0x54, 0xa1, 0x06, 0xa4, 0x50,\n\t\t0x50, 0x52, 0x54, 0x5b, 0x82, 0x4e, 0x75, 0x49,\n\t\t0x53, 0x41, 0x5f, 0x08, 0x5f, 0x41, 0x44, 0x52,\n\t\t0x0c, 0x00, 0x00, 0x1f, 0x00, 0x5b, 0x80, 0x4c,\n\t\t0x50, 0x43, 0x52, 0x02, 0x0a, 0x00, 0x0b, 0x00,\n\t\t0x01, 0x5b, 0x81, 0x33, 0x4c, 0x50, 0x43, 0x52,\n\t\t0x00, 0x00, 0x40, 0x30, 0x50, 0x49, 0x52, 0x41,\n\t\t0x08, 0x50, 0x49, 0x52, 0x42, 0x08, 0x50, 0x49,\n\t\t0x52, 0x43, 0x08, 0x50, 0x49, 0x52, 0x44, 0x08,\n\t\t0x00, 0x20, 0x50, 0x49, 0x52, 0x45, 0x08, 0x50,\n\t\t0x49, 0x52, 0x46, 0x08, 0x50, 0x49, 0x52, 0x47,\n\t\t0x08, 0x50, 0x49, 0x52, 0x48, 0x08, 0x14, 0x33,\n\t\t0x50, 0x49, 0x52, 0x56, 0x01, 0xa0, 0x09, 0x7b,\n\t\t0x68, 0x0a, 0x80, 0x00, 0xa4, 0x0a, 0x00, 0x7b,\n\t\t0x68, 0x0a, 0x0f, 0x60, 0xa0, 0x08, 0x95, 0x60,\n\t\t0x0a, 0x03, 0xa4, 0x0a, 0x00, 0xa0, 0x08, 0x93,\n\t\t0x60, 0x0a, 0x08, 0xa4, 0x0a, 0x00, 0xa0, 0x08,\n\t\t0x93, 0x60, 0x0a, 0x0d, 0xa4, 0x0a, 0x00, 0xa4,\n\t\t0x0a, 0x01, 0x5b, 0x82, 0x4f, 0x0a, 0x4c, 0x4e,\n\t\t0x4b, 0x41, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c,\n\t\t0x41, 0xd0, 0x0c, 0x0f, 0x08, 0x5f, 0x55, 0x49,\n\t\t0x44, 0x0a, 0x01, 0x14, 0x18, 0x5f, 0x53, 0x54,\n\t\t0x41, 0x00, 0xa0, 0x0c, 0x50, 0x49, 0x52, 0x56,\n\t\t0x50, 0x49, 0x52, 0x41, 0xa4, 0x0a, 0x0b, 0xa1,\n\t\t0x04, 0xa4, 0x0a, 0x09, 0x08, 0x5f, 0x50, 0x52,\n\t\t0x53, 0x11, 0x09, 0x0a, 0x06, 0x23, 0xf8, 0xde,\n\t\t0x18, 0x79, 0x00, 0x08, 0x43, 0x42, 0x30, 0x31,\n\t\t0x11, 0x09, 0x0a, 0x06, 0x23, 0x00, 0x00, 0x18,\n\t\t0x79, 0x00, 0x8b, 0x43, 0x42, 0x30, 0x31, 0x0a,\n\t\t0x01, 0x43, 0x49, 0x52, 0x41, 0x14, 0x2b, 0x5f,\n\t\t0x43, 0x52, 0x53, 0x00, 0x7b, 0x50, 0x49, 0x52,\n\t\t0x41, 0x0a, 0x8f, 0x60, 0xa0, 0x0e, 0x50, 0x49,\n\t\t0x52, 0x56, 0x60, 0x79, 0x0a, 0x01, 0x60, 0x43,\n\t\t0x49, 0x52, 0x41, 0xa1, 0x08, 0x70, 0x0a, 0x00,\n\t\t0x43, 0x49, 0x52, 0x41, 0xa4, 0x43, 0x42, 0x30,\n\t\t0x31, 0x14, 0x0d, 0x5f, 0x44, 0x49, 0x53, 0x00,\n\t\t0x70, 0x0a, 0x80, 0x50, 0x49, 0x52, 0x41, 0x14,\n\t\t0x1b, 0x5f, 0x53, 0x52, 0x53, 0x01, 0x8b, 0x68,\n\t\t0x0a, 0x01, 0x53, 0x49, 0x52, 0x41, 0x82, 0x53,\n\t\t0x49, 0x52, 0x41, 0x60, 0x70, 0x76, 0x60, 0x50,\n\t\t0x49, 0x52, 0x41, 0x5b, 0x82, 0x4f, 0x0a, 0x4c,\n\t\t0x4e, 0x4b, 0x42, 0x08, 0x5f, 0x48, 0x49, 0x44,\n\t\t0x0c, 0x41, 0xd0, 0x0c, 0x0f, 0x08, 0x5f, 0x55,\n\t\t0x49, 0x44, 0x0a, 0x02, 0x14, 0x18, 0x5f, 0x53,\n\t\t0x54, 0x41, 0x00, 0xa0, 0x0c, 0x50, 0x49, 0x52,\n\t\t0x56, 0x50, 0x49, 0x52, 0x42, 0xa4, 0x0a, 0x0b,\n\t\t0xa1, 0x04, 0xa4, 0x0a, 0x09, 0x08, 0x5f, 0x50,\n\t\t0x52, 0x53, 0x11, 0x09, 0x0a, 0x06, 0x23, 0xf8,\n\t\t0xde, 0x18, 0x79, 0x00, 0x08, 0x43, 0x42, 0x30,\n\t\t0x32, 0x11, 0x09, 0x0a, 0x06, 0x23, 0x00, 0x00,\n\t\t0x18, 0x79, 0x00, 0x8b, 0x43, 0x42, 0x30, 0x32,\n\t\t0x0a, 0x01, 0x43, 0x49, 0x52, 0x42, 0x14, 0x2b,\n\t\t0x5f, 0x43, 0x52, 0x53, 0x00, 0x7b, 0x50, 0x49,\n\t\t0x52, 0x42, 0x0a, 0x8f, 0x60, 0xa0, 0x0e, 0x50,\n\t\t0x49, 0x52, 0x56, 0x60, 0x79, 0x0a, 0x01, 0x60,\n\t\t0x43, 0x49, 0x52, 0x42, 0xa1, 0x08, 0x70, 0x0a,\n\t\t0x00, 0x43, 0x49, 0x52, 0x42, 0xa4, 0x43, 0x42,\n\t\t0x30, 0x32, 0x14, 0x0d, 0x5f, 0x44, 0x49, 0x53,\n\t\t0x00, 0x70, 0x0a, 0x80, 0x50, 0x49, 0x52, 0x42,\n\t\t0x14, 0x1b, 0x5f, 0x53, 0x52, 0x53, 0x01, 0x8b,\n\t\t0x68, 0x0a, 0x01, 0x53, 0x49, 0x52, 0x42, 0x82,\n\t\t0x53, 0x49, 0x52, 0x42, 0x60, 0x70, 0x76, 0x60,\n\t\t0x50, 0x49, 0x52, 0x42, 0x5b, 0x82, 0x4f, 0x0a,\n\t\t0x4c, 0x4e, 0x4b, 0x43, 0x08, 0x5f, 0x48, 0x49,\n\t\t0x44, 0x0c, 0x41, 0xd0, 0x0c, 0x0f, 0x08, 0x5f,\n\t\t0x55, 0x49, 0x44, 0x0a, 0x03, 0x14, 0x18, 0x5f,\n\t\t0x53, 0x54, 0x41, 0x00, 0xa0, 0x0c, 0x50, 0x49,\n\t\t0x52, 0x56, 0x50, 0x49, 0x52, 0x43, 0xa4, 0x0a,\n\t\t0x0b, 0xa1, 0x04, 0xa4, 0x0a, 0x09, 0x08, 0x5f,\n\t\t0x50, 0x52, 0x53, 0x11, 0x09, 0x0a, 0x06, 0x23,\n\t\t0xf8, 0xde, 0x18, 0x79, 0x00, 0x08, 0x43, 0x42,\n\t\t0x30, 0x33, 0x11, 0x09, 0x0a, 0x06, 0x23, 0x00,\n\t\t0x00, 0x18, 0x79, 0x00, 0x8b, 0x43, 0x42, 0x30,\n\t\t0x33, 0x0a, 0x01, 0x43, 0x49, 0x52, 0x43, 0x14,\n\t\t0x2b, 0x5f, 0x43, 0x52, 0x53, 0x00, 0x7b, 0x50,\n\t\t0x49, 0x52, 0x43, 0x0a, 0x8f, 0x60, 0xa0, 0x0e,\n\t\t0x50, 0x49, 0x52, 0x56, 0x60, 0x79, 0x0a, 0x01,\n\t\t0x60, 0x43, 0x49, 0x52, 0x43, 0xa1, 0x08, 0x70,\n\t\t0x0a, 0x00, 0x43, 0x49, 0x52, 0x43, 0xa4, 0x43,\n\t\t0x42, 0x30, 0x33, 0x14, 0x0d, 0x5f, 0x44, 0x49,\n\t\t0x53, 0x00, 0x70, 0x0a, 0x80, 0x50, 0x49, 0x52,\n\t\t0x43, 0x14, 0x1b, 0x5f, 0x53, 0x52, 0x53, 0x01,\n\t\t0x8b, 0x68, 0x0a, 0x01, 0x53, 0x49, 0x52, 0x43,\n\t\t0x82, 0x53, 0x49, 0x52, 0x43, 0x60, 0x70, 0x76,\n\t\t0x60, 0x50, 0x49, 0x52, 0x43, 0x5b, 0x82, 0x4f,\n\t\t0x0a, 0x4c, 0x4e, 0x4b, 0x44, 0x08, 0x5f, 0x48,\n\t\t0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0c, 0x0f, 0x08,\n\t\t0x5f, 0x55, 0x49, 0x44, 0x0a, 0x04, 0x14, 0x18,\n\t\t0x5f, 0x53, 0x54, 0x41, 0x00, 0xa0, 0x0c, 0x50,\n\t\t0x49, 0x52, 0x56, 0x50, 0x49, 0x52, 0x44, 0xa4,\n\t\t0x0a, 0x0b, 0xa1, 0x04, 0xa4, 0x0a, 0x09, 0x08,\n\t\t0x5f, 0x50, 0x52, 0x53, 0x11, 0x09, 0x0a, 0x06,\n\t\t0x23, 0xf8, 0xde, 0x18, 0x79, 0x00, 0x08, 0x43,\n\t\t0x42, 0x30, 0x34, 0x11, 0x09, 0x0a, 0x06, 0x23,\n\t\t0x00, 0x00, 0x18, 0x79, 0x00, 0x8b, 0x43, 0x42,\n\t\t0x30, 0x34, 0x0a, 0x01, 0x43, 0x49, 0x52, 0x44,\n\t\t0x14, 0x2b, 0x5f, 0x43, 0x52, 0x53, 0x00, 0x7b,\n\t\t0x50, 0x49, 0x52, 0x44, 0x0a, 0x8f, 0x60, 0xa0,\n\t\t0x0e, 0x50, 0x49, 0x52, 0x56, 0x60, 0x79, 0x0a,\n\t\t0x01, 0x60, 0x43, 0x49, 0x52, 0x44, 0xa1, 0x08,\n\t\t0x70, 0x0a, 0x00, 0x43, 0x49, 0x52, 0x44, 0xa4,\n\t\t0x43, 0x42, 0x30, 0x34, 0x14, 0x0d, 0x5f, 0x44,\n\t\t0x49, 0x53, 0x00, 0x70, 0x0a, 0x80, 0x50, 0x49,\n\t\t0x52, 0x44, 0x14, 0x1b, 0x5f, 0x53, 0x52, 0x53,\n\t\t0x01, 0x8b, 0x68, 0x0a, 0x01, 0x53, 0x49, 0x52,\n\t\t0x44, 0x82, 0x53, 0x49, 0x52, 0x44, 0x60, 0x70,\n\t\t0x76, 0x60, 0x50, 0x49, 0x52, 0x44, 0x5b, 0x82,\n\t\t0x4f, 0x0a, 0x4c, 0x4e, 0x4b, 0x45, 0x08, 0x5f,\n\t\t0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0c, 0x0f,\n\t\t0x08, 0x5f, 0x55, 0x49, 0x44, 0x0a, 0x05, 0x14,\n\t\t0x18, 0x5f, 0x53, 0x54, 0x41, 0x00, 0xa0, 0x0c,\n\t\t0x50, 0x49, 0x52, 0x56, 0x50, 0x49, 0x52, 0x45,\n\t\t0xa4, 0x0a, 0x0b, 0xa1, 0x04, 0xa4, 0x0a, 0x09,\n\t\t0x08, 0x5f, 0x50, 0x52, 0x53, 0x11, 0x09, 0x0a,\n\t\t0x06, 0x23, 0xf8, 0xde, 0x18, 0x79, 0x00, 0x08,\n\t\t0x43, 0x42, 0x30, 0x35, 0x11, 0x09, 0x0a, 0x06,\n\t\t0x23, 0x00, 0x00, 0x18, 0x79, 0x00, 0x8b, 0x43,\n\t\t0x42, 0x30, 0x35, 0x0a, 0x01, 0x43, 0x49, 0x52,\n\t\t0x45, 0x14, 0x2b, 0x5f, 0x43, 0x52, 0x53, 0x00,\n\t\t0x7b, 0x50, 0x49, 0x52, 0x45, 0x0a, 0x8f, 0x60,\n\t\t0xa0, 0x0e, 0x50, 0x49, 0x52, 0x56, 0x60, 0x79,\n\t\t0x0a, 0x01, 0x60, 0x43, 0x49, 0x52, 0x45, 0xa1,\n\t\t0x08, 0x70, 0x0a, 0x00, 0x43, 0x49, 0x52, 0x45,\n\t\t0xa4, 0x43, 0x42, 0x30, 0x35, 0x14, 0x0d, 0x5f,\n\t\t0x44, 0x49, 0x53, 0x00, 0x70, 0x0a, 0x80, 0x50,\n\t\t0x49, 0x52, 0x45, 0x14, 0x1b, 0x5f, 0x53, 0x52,\n\t\t0x53, 0x01, 0x8b, 0x68, 0x0a, 0x01, 0x53, 0x49,\n\t\t0x52, 0x45, 0x82, 0x53, 0x49, 0x52, 0x45, 0x60,\n\t\t0x70, 0x76, 0x60, 0x50, 0x49, 0x52, 0x45, 0x5b,\n\t\t0x82, 0x4f, 0x0a, 0x4c, 0x4e, 0x4b, 0x46, 0x08,\n\t\t0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0c,\n\t\t0x0f, 0x08, 0x5f, 0x55, 0x49, 0x44, 0x0a, 0x06,\n\t\t0x14, 0x18, 0x5f, 0x53, 0x54, 0x41, 0x00, 0xa0,\n\t\t0x0c, 0x50, 0x49, 0x52, 0x56, 0x50, 0x49, 0x52,\n\t\t0x46, 0xa4, 0x0a, 0x0b, 0xa1, 0x04, 0xa4, 0x0a,\n\t\t0x09, 0x08, 0x5f, 0x50, 0x52, 0x53, 0x11, 0x09,\n\t\t0x0a, 0x06, 0x23, 0xf8, 0xde, 0x18, 0x79, 0x00,\n\t\t0x08, 0x43, 0x42, 0x30, 0x36, 0x11, 0x09, 0x0a,\n\t\t0x06, 0x23, 0x00, 0x00, 0x18, 0x79, 0x00, 0x8b,\n\t\t0x43, 0x42, 0x30, 0x36, 0x0a, 0x01, 0x43, 0x49,\n\t\t0x52, 0x46, 0x14, 0x2b, 0x5f, 0x43, 0x52, 0x53,\n\t\t0x00, 0x7b, 0x50, 0x49, 0x52, 0x46, 0x0a, 0x8f,\n\t\t0x60, 0xa0, 0x0e, 0x50, 0x49, 0x52, 0x56, 0x60,\n\t\t0x79, 0x0a, 0x01, 0x60, 0x43, 0x49, 0x52, 0x46,\n\t\t0xa1, 0x08, 0x70, 0x0a, 0x00, 0x43, 0x49, 0x52,\n\t\t0x46, 0xa4, 0x43, 0x42, 0x30, 0x36, 0x14, 0x0d,\n\t\t0x5f, 0x44, 0x49, 0x53, 0x00, 0x70, 0x0a, 0x80,\n\t\t0x50, 0x49, 0x52, 0x46, 0x14, 0x1b, 0x5f, 0x53,\n\t\t0x52, 0x53, 0x01, 0x8b, 0x68, 0x0a, 0x01, 0x53,\n\t\t0x49, 0x52, 0x46, 0x82, 0x53, 0x49, 0x52, 0x46,\n\t\t0x60, 0x70, 0x76, 0x60, 0x50, 0x49, 0x52, 0x46,\n\t\t0x5b, 0x82, 0x4f, 0x0a, 0x4c, 0x4e, 0x4b, 0x47,\n\t\t0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0,\n\t\t0x0c, 0x0f, 0x08, 0x5f, 0x55, 0x49, 0x44, 0x0a,\n\t\t0x07, 0x14, 0x18, 0x5f, 0x53, 0x54, 0x41, 0x00,\n\t\t0xa0, 0x0c, 0x50, 0x49, 0x52, 0x56, 0x50, 0x49,\n\t\t0x52, 0x47, 0xa4, 0x0a, 0x0b, 0xa1, 0x04, 0xa4,\n\t\t0x0a, 0x09, 0x08, 0x5f, 0x50, 0x52, 0x53, 0x11,\n\t\t0x09, 0x0a, 0x06, 0x23, 0xf8, 0xde, 0x18, 0x79,\n\t\t0x00, 0x08, 0x43, 0x42, 0x30, 0x37, 0x11, 0x09,\n\t\t0x0a, 0x06, 0x23, 0x00, 0x00, 0x18, 0x79, 0x00,\n\t\t0x8b, 0x43, 0x42, 0x30, 0x37, 0x0a, 0x01, 0x43,\n\t\t0x49, 0x52, 0x47, 0x14, 0x2b, 0x5f, 0x43, 0x52,\n\t\t0x53, 0x00, 0x7b, 0x50, 0x49, 0x52, 0x47, 0x0a,\n\t\t0x8f, 0x60, 0xa0, 0x0e, 0x50, 0x49, 0x52, 0x56,\n\t\t0x60, 0x79, 0x0a, 0x01, 0x60, 0x43, 0x49, 0x52,\n\t\t0x47, 0xa1, 0x08, 0x70, 0x0a, 0x00, 0x43, 0x49,\n\t\t0x52, 0x47, 0xa4, 0x43, 0x42, 0x30, 0x37, 0x14,\n\t\t0x0d, 0x5f, 0x44, 0x49, 0x53, 0x00, 0x70, 0x0a,\n\t\t0x80, 0x50, 0x49, 0x52, 0x47, 0x14, 0x1b, 0x5f,\n\t\t0x53, 0x52, 0x53, 0x01, 0x8b, 0x68, 0x0a, 0x01,\n\t\t0x53, 0x49, 0x52, 0x47, 0x82, 0x53, 0x49, 0x52,\n\t\t0x47, 0x60, 0x70, 0x76, 0x60, 0x50, 0x49, 0x52,\n\t\t0x47, 0x5b, 0x82, 0x4f, 0x0a, 0x4c, 0x4e, 0x4b,\n\t\t0x48, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41,\n\t\t0xd0, 0x0c, 0x0f, 0x08, 0x5f, 0x55, 0x49, 0x44,\n\t\t0x0a, 0x08, 0x14, 0x18, 0x5f, 0x53, 0x54, 0x41,\n\t\t0x00, 0xa0, 0x0c, 0x50, 0x49, 0x52, 0x56, 0x50,\n\t\t0x49, 0x52, 0x48, 0xa4, 0x0a, 0x0b, 0xa1, 0x04,\n\t\t0xa4, 0x0a, 0x09, 0x08, 0x5f, 0x50, 0x52, 0x53,\n\t\t0x11, 0x09, 0x0a, 0x06, 0x23, 0xf8, 0xde, 0x18,\n\t\t0x79, 0x00, 0x08, 0x43, 0x42, 0x30, 0x38, 0x11,\n\t\t0x09, 0x0a, 0x06, 0x23, 0x00, 0x00, 0x18, 0x79,\n\t\t0x00, 0x8b, 0x43, 0x42, 0x30, 0x38, 0x0a, 0x01,\n\t\t0x43, 0x49, 0x52, 0x48, 0x14, 0x2b, 0x5f, 0x43,\n\t\t0x52, 0x53, 0x00, 0x7b, 0x50, 0x49, 0x52, 0x48,\n\t\t0x0a, 0x8f, 0x60, 0xa0, 0x0e, 0x50, 0x49, 0x52,\n\t\t0x56, 0x60, 0x79, 0x0a, 0x01, 0x60, 0x43, 0x49,\n\t\t0x52, 0x48, 0xa1, 0x08, 0x70, 0x0a, 0x00, 0x43,\n\t\t0x49, 0x52, 0x48, 0xa4, 0x43, 0x42, 0x30, 0x38,\n\t\t0x14, 0x0d, 0x5f, 0x44, 0x49, 0x53, 0x00, 0x70,\n\t\t0x0a, 0x80, 0x50, 0x49, 0x52, 0x48, 0x14, 0x1b,\n\t\t0x5f, 0x53, 0x52, 0x53, 0x01, 0x8b, 0x68, 0x0a,\n\t\t0x01, 0x53, 0x49, 0x52, 0x48, 0x82, 0x53, 0x49,\n\t\t0x52, 0x48, 0x60, 0x70, 0x76, 0x60, 0x50, 0x49,\n\t\t0x52, 0x48, 0x5b, 0x82, 0x48, 0x07, 0x53, 0x49,\n\t\t0x4f, 0x5f, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c,\n\t\t0x41, 0xd0, 0x0c, 0x02, 0x08, 0x5f, 0x43, 0x52,\n\t\t0x53, 0x11, 0x42, 0x06, 0x0a, 0x5e, 0x47, 0x01,\n\t\t0x60, 0x00, 0x60, 0x00, 0x01, 0x01, 0x47, 0x01,\n\t\t0x64, 0x00, 0x64, 0x00, 0x01, 0x01, 0x47, 0x01,\n\t\t0x20, 0x02, 0x20, 0x02, 0x01, 0x04, 0x47, 0x01,\n\t\t0x24, 0x02, 0x24, 0x02, 0x01, 0x04, 0x86, 0x09,\n\t\t0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00,\n\t\t0x00, 0x10, 0x47, 0x01, 0xd0, 0x04, 0xd0, 0x04,\n\t\t0x01, 0x02, 0x47, 0x01, 0x61, 0x00, 0x61, 0x00,\n\t\t0x01, 0x01, 0x47, 0x01, 0x00, 0x04, 0x00, 0x04,\n\t\t0x01, 0x08, 0x47, 0x01, 0xb2, 0x00, 0xb2, 0x00,\n\t\t0x01, 0x01, 0x47, 0x01, 0x84, 0x00, 0x84, 0x00,\n\t\t0x01, 0x01, 0x47, 0x01, 0x72, 0x00, 0x72, 0x00,\n\t\t0x01, 0x06, 0x79, 0x00, 0x5b, 0x82, 0x2c, 0x43,\n\t\t0x4f, 0x4d, 0x31, 0x08, 0x5f, 0x48, 0x49, 0x44,\n\t\t0x0c, 0x41, 0xd0, 0x05, 0x01, 0x08, 0x5f, 0x55,\n\t\t0x49, 0x44, 0x0a, 0x01, 0x08, 0x5f, 0x43, 0x52,\n\t\t0x53, 0x11, 0x10, 0x0a, 0x0d, 0x47, 0x01, 0xf8,\n\t\t0x03, 0xf8, 0x03, 0x01, 0x08, 0x22, 0x10, 0x00,\n\t\t0x79, 0x00, 0x5b, 0x82, 0x2c, 0x43, 0x4f, 0x4d,\n\t\t0x32, 0x08, 0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41,\n\t\t0xd0, 0x05, 0x01, 0x08, 0x5f, 0x55, 0x49, 0x44,\n\t\t0x0a, 0x02, 0x08, 0x5f, 0x43, 0x52, 0x53, 0x11,\n\t\t0x10, 0x0a, 0x0d, 0x47, 0x01, 0xf8, 0x02, 0xf8,\n\t\t0x02, 0x01, 0x08, 0x22, 0x08, 0x00, 0x79, 0x00,\n\t\t0x5b, 0x82, 0x25, 0x52, 0x54, 0x43, 0x5f, 0x08,\n\t\t0x5f, 0x48, 0x49, 0x44, 0x0c, 0x41, 0xd0, 0x0b,\n\t\t0x00, 0x08, 0x5f, 0x43, 0x52, 0x53, 0x11, 0x10,\n\t\t0x0a, 0x0d, 0x47, 0x01, 0x70, 0x00, 0x70, 0x00,\n\t\t0x01, 0x02, 0x22, 0x00, 0x01, 0x79, 0x00, 0x5b,\n\t\t0x82, 0x2b, 0x50, 0x49, 0x43, 0x5f, 0x08, 0x5f,\n\t\t0x48, 0x49, 0x44, 0x0b, 0x41, 0xd0, 0x08, 0x5f,\n\t\t0x43, 0x52, 0x53, 0x11, 0x18, 0x0a, 0x15, 0x47,\n\t\t0x01, 0x20, 0x00, 0x20, 0x00, 0x01, 0x02, 0x47,\n\t\t0x01, 0xa0, 0x00, 0xa0, 0x00, 0x01, 0x02, 0x22,\n\t\t0x04, 0x00, 0x79, 0x00, 0x5b, 0x82, 0x25, 0x54,\n\t\t0x49, 0x4d, 0x52, 0x08, 0x5f, 0x48, 0x49, 0x44,\n\t\t0x0c, 0x41, 0xd0, 0x01, 0x00, 0x08, 0x5f, 0x43,\n\t\t0x52, 0x53, 0x11, 0x10, 0x0a, 0x0d, 0x47, 0x01,\n\t\t0x40, 0x00, 0x40, 0x00, 0x01, 0x04, 0x22, 0x01,\n\t\t0x00, 0x79, 0x00, 0x10, 0x39, 0x2e, 0x5f, 0x53,\n\t\t0x42, 0x5f, 0x50, 0x43, 0x30, 0x30, 0x5b, 0x82,\n\t\t0x2d, 0x48, 0x50, 0x45, 0x54, 0x08, 0x5f, 0x48,\n\t\t0x49, 0x44, 0x0c, 0x41, 0xd0, 0x01, 0x03, 0x08,\n\t\t0x5f, 0x55, 0x49, 0x44, 0x0a, 0x00, 0x08, 0x5f,\n\t\t0x43, 0x52, 0x53, 0x11, 0x11, 0x0a, 0x0e, 0x86,\n\t\t0x09, 0x00, 0x01, 0x00, 0x00, 0xd0, 0xfe, 0x00,\n\t\t0x04, 0x00, 0x00, 0x79\n\t};\n\n\tdsdt = (void *) (((uintptr_t) tb) + DSDT_OFFSET);\n\t/* copy DSDT template to guest memory */\n\tmemcpy(dsdt, dsdt_tmpl, 2604);\n\n\tpci_write_dsdt();\n\n\t/* write checksum */\n\tacpitbl_write8(dsdt, 0x9, acpitbl_checksum(dsdt, 2604));\n}\n\nint\nacpi_build(int ncpu)\n{\n\tint err;\n\n\tacpi_ncpu = ncpu;\n\ttb = paddr_guest2host(XHYVE_ACPI_BASE, XHYVE_ACPI_SIZE);\n\tif (tb == NULL) {\n\t\treturn (EFAULT);\n\t}\n\n\terr = xh_vm_get_hpet_capabilities(&hpet_capabilities);\n\tif (err != 0) {\n\t\treturn (err);\n\t}\n\n\tacpitbl_build_rdsp();\n\tacpitbl_build_rsdt();\n\tacpitbl_build_xsdt();\n\tacpitbl_build_madt();\n\tacpitbl_build_fadt();\n\tacpitbl_build_hpet();\n\tacpitbl_build_mcfg();\n\tacpitbl_build_facs();\n\tacpitbl_build_dsdt();\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/atkbdc.c",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 Nahanni Systems Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n\n#include <assert.h>\n#include <errno.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <pthread.h>\n\n#include <xhyve/support/misc.h>\n\n#include <xhyve/acpi.h>\n#include <xhyve/atkbdc.h>\n#include <xhyve/inout.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/pci_irq.h>\n#include <xhyve/pci_lpc.h>\n#include <xhyve/ps2kbd.h>\n#include <xhyve/ps2mouse.h>\n#include <xhyve/vmm/vmm_api.h>\n\n#define\tKBD_DATA_PORT\t\t0x60\n\n#define\tKBD_STS_CTL_PORT\t0x64\n\n#define\tKBDC_RESET\t\t0xfe\n\n#define\tKBD_DEV_IRQ\t\t1\n#define\tAUX_DEV_IRQ\t\t12\n\n/* controller commands */\n#define\tKBDC_SET_COMMAND_BYTE\t0x60\n#define\tKBDC_GET_COMMAND_BYTE\t0x20\n#define\tKBDC_DISABLE_AUX_PORT\t0xa7\n#define\tKBDC_ENABLE_AUX_PORT\t0xa8\n#define\tKBDC_TEST_AUX_PORT\t0xa9\n#define\tKBDC_TEST_CTRL\t\t0xaa\n#define\tKBDC_TEST_KBD_PORT\t0xab\n#define\tKBDC_DISABLE_KBD_PORT\t0xad\n#define\tKBDC_ENABLE_KBD_PORT\t0xae\n#define\tKBDC_READ_INPORT\t0xc0\n#define\tKBDC_READ_OUTPORT\t0xd0\n#define\tKBDC_WRITE_OUTPORT\t0xd1\n#define\tKBDC_WRITE_KBD_OUTBUF\t0xd2\n#define\tKBDC_WRITE_AUX_OUTBUF\t0xd3\n#define\tKBDC_WRITE_TO_AUX\t0xd4\n\n/* controller command byte (set by KBDC_SET_COMMAND_BYTE) */\n#define\tKBD_TRANSLATION\t\t0x40\n#define\tKBD_SYS_FLAG_BIT\t0x04\n#define\tKBD_DISABLE_KBD_PORT\t0x10\n#define\tKBD_DISABLE_AUX_PORT\t0x20\n#define\tKBD_ENABLE_AUX_INT\t0x02\n#define\tKBD_ENABLE_KBD_INT\t0x01\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-macros\"\n\n#define\tKBD_KBD_CONTROL_BITS\t(KBD_DISABLE_KBD_PORT | KBD_ENABLE_KBD_INT)\n#define\tKBD_AUX_CONTROL_BITS\t(KBD_DISABLE_AUX_PORT | KBD_ENABLE_AUX_INT)\n\n#pragma clang diagnostic pop\n\n/* controller status bits */\n#define\tKBDS_KBD_BUFFER_FULL\t0x01\n#define KBDS_SYS_FLAG\t\t0x04\n#define KBDS_CTRL_FLAG\t\t0x08\n#define\tKBDS_AUX_BUFFER_FULL\t0x20\n\n/* controller output port */\n#define\tKBDO_KBD_OUTFULL\t0x10\n#define\tKBDO_AUX_OUTFULL\t0x20\n\n#define\tRAMSZ\t\t\t32\n#define\tFIFOSZ\t\t\t15\n#define\tCTRL_CMD_FLAG\t\t0x8000\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct kbd_dev {\n\tbool\tirq_active;\n\tint\tirq;\n\n\tuint8_t\tbuffer[FIFOSZ];\n\tint\tbrd, bwr;\n\tint\tbcnt;\n};\n\nstruct aux_dev {\n\tbool\tirq_active;\n\tint\tirq;\n};\n\nstruct atkbdc_softc {\n\tpthread_mutex_t mtx;\n\n\tstruct ps2kbd_softc\t*ps2kbd_sc;\n\tstruct ps2mouse_softc\t*ps2mouse_sc;\n\n\tuint8_t\tstatus;\t\t/* status register */\n\tuint8_t\toutport;\t/* controller output port */\n\tuint8_t\tram[RAMSZ];\t/* byte0 = controller config */\n\n\tuint32_t curcmd;\t/* current command for next byte */\n\tuint32_t  ctrlbyte;\n\n\tstruct kbd_dev kbd;\n\tstruct aux_dev aux;\n};\n\n#pragma clang diagnostic pop\n\nstatic void\natkbdc_assert_kbd_intr(struct atkbdc_softc *sc)\n{\n\tif ((sc->ram[0] & KBD_ENABLE_KBD_INT) != 0) {\n\t\tsc->kbd.irq_active = true;\n\t\txh_vm_isa_pulse_irq(sc->kbd.irq, sc->kbd.irq);\n\t}\n}\n\nstatic void\natkbdc_assert_aux_intr(struct atkbdc_softc *sc)\n{\n\tif ((sc->ram[0] & KBD_ENABLE_AUX_INT) != 0) {\n\t\tsc->aux.irq_active = true;\n\t\txh_vm_isa_pulse_irq(sc->aux.irq, sc->aux.irq);\n\t}\n}\n\nstatic int\natkbdc_kbd_queue_data(struct atkbdc_softc *sc, uint8_t val)\n{\n\tif (sc->kbd.bcnt < FIFOSZ) {\n\t\tsc->kbd.buffer[sc->kbd.bwr] = val;\n\t\tsc->kbd.bwr = (sc->kbd.bwr + 1) % FIFOSZ;\n\t\tsc->kbd.bcnt++;\n\t\tsc->status |= KBDS_KBD_BUFFER_FULL;\n\t\tsc->outport |= KBDO_KBD_OUTFULL;\n\t} else {\n\t\tprintf(\"atkbd data buffer full\\n\");\n\t}\n\n\treturn (sc->kbd.bcnt < FIFOSZ);\n}\n\nstatic void\natkbdc_kbd_read(struct atkbdc_softc *sc)\n{\n\tconst uint8_t translation[256] = {\n\t\t0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,\n\t\t0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,\n\t\t0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,\n\t\t0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,\n\t\t0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,\n\t\t0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,\n\t\t0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,\n\t\t0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,\n\t\t0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,\n\t\t0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,\n\t\t0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,\n\t\t0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,\n\t\t0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,\n\t\t0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,\n\t\t0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,\n\t\t0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,\n\t\t0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,\n\t\t0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n\t\t0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,\n\t\t0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n\t\t0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\n\t\t0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n\t\t0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,\n\t\t0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\n\t\t0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,\n\t\t0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\n\t\t0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,\n\t\t0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\n\t\t0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,\n\t\t0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\n\t\t0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,\n\t\t0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff\n\t};\n\tuint8_t val;\n\tuint8_t release = 0;\n\n\tif (sc->ram[0] & KBD_TRANSLATION) {\n\t\twhile (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) {\n\t\t\tif (val == 0xf0) {\n\t\t\t\trelease = 0x80;\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tval = translation[val] | release;\n\t\t\t}\n\t\t\tatkbdc_kbd_queue_data(sc, val);\n\t\t\tbreak;\n\t\t}\n\t} else {\n\t\twhile (sc->kbd.bcnt < FIFOSZ) {\n\t\t\tif (ps2kbd_read(sc->ps2kbd_sc, &val) != -1)\n\t\t\t\tatkbdc_kbd_queue_data(sc, val);\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (((sc->ram[0] & KBD_DISABLE_AUX_PORT) ||\n\t    ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) && sc->kbd.bcnt > 0)\n\t\tatkbdc_assert_kbd_intr(sc);\n}\n\nstatic void\natkbdc_aux_poll(struct atkbdc_softc *sc)\n{\n\tif (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0) {\n\t\tsc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;\n\t\tsc->outport |= KBDO_AUX_OUTFULL;\n\t\tatkbdc_assert_aux_intr(sc);\n\t}\n}\n\nstatic void\natkbdc_kbd_poll(struct atkbdc_softc *sc)\n{\n\tatkbdc_kbd_read(sc);\n}\n\nstatic void\natkbdc_poll(struct atkbdc_softc *sc)\n{\n\tatkbdc_aux_poll(sc);\n\tatkbdc_kbd_poll(sc);\n}\n\nstatic void\natkbdc_dequeue_data(struct atkbdc_softc *sc, uint8_t *buf)\n{\n\tif (ps2mouse_read(sc->ps2mouse_sc, buf) == 0) {\n\t\tif (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) {\n\t\t\tif (sc->kbd.bcnt == 0)\n\t\t\t\tsc->status &= ~(KBDS_AUX_BUFFER_FULL |\n\t\t\t\t                KBDS_KBD_BUFFER_FULL);\n\t\t\telse\n\t\t\t\tsc->status &= ~(KBDS_AUX_BUFFER_FULL);\n\t\t\tsc->outport &= ~KBDO_AUX_OUTFULL;\n\t\t}\n\n\t\tatkbdc_poll(sc);\n\t\treturn;\n\t}\n\n\tif (sc->kbd.bcnt > 0) {\n\t\t*buf = sc->kbd.buffer[sc->kbd.brd];\n\t\tsc->kbd.brd = (sc->kbd.brd + 1) % FIFOSZ;\n\t\tsc->kbd.bcnt--;\n\t\tif (sc->kbd.bcnt == 0) {\n\t\t\tsc->status &= ~KBDS_KBD_BUFFER_FULL;\n\t\t\tsc->outport &= ~KBDO_KBD_OUTFULL;\n\t\t}\n\n\t\tatkbdc_poll(sc);\n\t}\n\n\tif (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0 && sc->kbd.bcnt == 0) {\n\t\tsc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);\n\t}\n}\n\nstatic int\natkbdc_data_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n    uint32_t *eax, void *arg)\n{\n\tstruct atkbdc_softc *sc;\n\tuint8_t buf;\n\tint retval;\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\tsc = arg;\n\tretval = 0;\n\n\tpthread_mutex_lock(&sc->mtx);\n\tif (in) {\n\t\tsc->curcmd = 0;\n\t\tif (sc->ctrlbyte != 0) {\n\t\t\t*eax = sc->ctrlbyte & 0xff;\n\t\t\tsc->ctrlbyte = 0;\n\t\t} else {\n\t\t\t/* read device buffer; includes kbd cmd responses */\n\t\t\tatkbdc_dequeue_data(sc, &buf);\n\t\t\t*eax = buf;\n\t\t}\n\n\t\tsc->status &= ~KBDS_CTRL_FLAG;\n\t\tpthread_mutex_unlock(&sc->mtx);\n\t\treturn (retval);\n\t}\n\n\tif (sc->status & KBDS_CTRL_FLAG) {\n\t\t/*\n\t\t * Command byte for the controller.\n\t\t */\n\t\tswitch (sc->curcmd) {\n\t\tcase KBDC_SET_COMMAND_BYTE:\n\t\t\tsc->ram[0] = (uint8_t)*eax;\n\t\t\tif (sc->ram[0] & KBD_SYS_FLAG_BIT)\n\t\t\t\tsc->status |= KBDS_SYS_FLAG;\n\t\t\telse\n\t\t\t\tsc->status &= ~KBDS_SYS_FLAG;\n\t\t\tbreak;\n\t\tcase KBDC_WRITE_OUTPORT:\n\t\t\tsc->outport = (uint8_t)*eax;\n\t\t\tbreak;\n\t\tcase KBDC_WRITE_TO_AUX:\n\t\t\tps2mouse_write(sc->ps2mouse_sc, (uint8_t)*eax, 0);\n\t\t\tatkbdc_poll(sc);\n\t\t\tbreak;\n\t\tcase KBDC_WRITE_KBD_OUTBUF:\n\t\t\tatkbdc_kbd_queue_data(sc, (uint8_t)*eax);\n\t\t\tbreak;\n\t\tcase KBDC_WRITE_AUX_OUTBUF:\n\t\t\tps2mouse_write(sc->ps2mouse_sc, (uint8_t)*eax, 1);\n\t\t\tsc->status |= (KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);\n\t\t\tatkbdc_aux_poll(sc);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t/* write to particular RAM byte */\n\t\t\tif (sc->curcmd >= 0x61 && sc->curcmd <= 0x7f) {\n\t\t\t\tint byten;\n\n\t\t\t\tbyten = (sc->curcmd - 0x60) & 0x1f;\n\t\t\t\tsc->ram[byten] = *eax & 0xff;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tsc->curcmd = 0;\n\t\tsc->status &= ~KBDS_CTRL_FLAG;\n\n\t\tpthread_mutex_unlock(&sc->mtx);\n\t\treturn (retval);\n\t}\n\n\t/*\n\t * Data byte for the device.\n\t */\n\tps2kbd_write(sc->ps2kbd_sc, (uint8_t)*eax);\n\tatkbdc_poll(sc);\n\n\tpthread_mutex_unlock(&sc->mtx);\n\n\treturn (retval);\n}\n\nstatic int\natkbdc_sts_ctl_handler(UNUSED int vcpu, int in, UNUSED int port,\n    int bytes, uint32_t *eax, void *arg)\n{\n\tstruct atkbdc_softc *sc;\n\tint\terror, retval;\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tsc = arg;\n\tretval = 0;\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\tif (in) {\n\t\t/* read status register */\n\t\t*eax = sc->status;\n\t\tpthread_mutex_unlock(&sc->mtx);\n\t\treturn (retval);\n\t}\n\n\n\tsc->curcmd = 0;\n\tsc->status |= KBDS_CTRL_FLAG;\n\tsc->ctrlbyte = 0;\n\n\tswitch (*eax) {\n\tcase KBDC_GET_COMMAND_BYTE:\n\t\tsc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[0];\n\t\tbreak;\n\tcase KBDC_TEST_CTRL:\n\t\tsc->ctrlbyte = CTRL_CMD_FLAG | 0x55;\n\t\tbreak;\n\tcase KBDC_TEST_AUX_PORT:\n\tcase KBDC_TEST_KBD_PORT:\n\t\tsc->ctrlbyte = CTRL_CMD_FLAG | 0;\n\t\tbreak;\n\tcase KBDC_READ_INPORT:\n\t\tsc->ctrlbyte = CTRL_CMD_FLAG | 0;\n\t\tbreak;\n\tcase KBDC_READ_OUTPORT:\n\t\tsc->ctrlbyte = CTRL_CMD_FLAG | sc->outport;\n\t\tbreak;\n\tcase KBDC_SET_COMMAND_BYTE:\n\tcase KBDC_WRITE_OUTPORT:\n\tcase KBDC_WRITE_KBD_OUTBUF:\n\tcase KBDC_WRITE_AUX_OUTBUF:\n\t\tsc->curcmd = *eax;\n\t\tbreak;\n\tcase KBDC_DISABLE_KBD_PORT:\n\t\tsc->ram[0] |= KBD_DISABLE_KBD_PORT;\n\t\tbreak;\n\tcase KBDC_ENABLE_KBD_PORT:\n\t\tsc->ram[0] &= ~KBD_DISABLE_KBD_PORT;\n\t\tif (sc->kbd.bcnt > 0)\n\t\t\tsc->status |= KBDS_KBD_BUFFER_FULL;\n\t\tatkbdc_poll(sc);\n\t\tbreak;\n\tcase KBDC_WRITE_TO_AUX:\n\t\tsc->curcmd = *eax;\n\t\tbreak;\n\tcase KBDC_DISABLE_AUX_PORT:\n\t\tsc->ram[0] |= KBD_DISABLE_AUX_PORT;\n\t\tps2mouse_toggle(sc->ps2mouse_sc, 0);\n\t\tsc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);\n\t\tsc->outport &= ~KBDS_AUX_BUFFER_FULL;\n\t\tbreak;\n\tcase KBDC_ENABLE_AUX_PORT:\n\t\tsc->ram[0] &= ~KBD_DISABLE_AUX_PORT;\n\t\tps2mouse_toggle(sc->ps2mouse_sc, 1);\n\t\tif (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0)\n\t\t\tsc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;\n\t\tbreak;\n\tcase KBDC_RESET:\t\t/* Pulse \"reset\" line */\n\t\terror = xh_vm_suspend(VM_SUSPEND_RESET);\n\t\tassert(error == 0 || errno == EALREADY);\n\t\tbreak;\n\tdefault:\n\t\tif (*eax >= 0x21 && *eax <= 0x3f) {\n\t\t\t/* read \"byte N\" from RAM */\n\t\t\tint\tbyten;\n\n\t\t\tbyten = (*eax - 0x20) & 0x1f;\n\t\t\tsc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[byten];\n\t\t}\n\t\tbreak;\n\t}\n\n\tpthread_mutex_unlock(&sc->mtx);\n\n\tif (sc->ctrlbyte != 0) {\n\t\tsc->status |= KBDS_KBD_BUFFER_FULL;\n\t\tsc->status &= ~KBDS_AUX_BUFFER_FULL;\n\t\tatkbdc_assert_kbd_intr(sc);\n\t} else if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0 &&\n\t           (sc->ram[0] & KBD_DISABLE_AUX_PORT) == 0) {\n\t\tsc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;\n\t\tatkbdc_assert_aux_intr(sc);\n\t} else if (sc->kbd.bcnt > 0 && (sc->ram[0] & KBD_DISABLE_KBD_PORT) == 0) {\n\t\tsc->status |= KBDS_KBD_BUFFER_FULL;\n\t\tatkbdc_assert_kbd_intr(sc);\n\t}\n\n\treturn (retval);\n}\n\nvoid\natkbdc_event(struct atkbdc_softc *sc, int iskbd)\n{\n\tpthread_mutex_lock(&sc->mtx);\n\n\tif (iskbd)\n\t\tatkbdc_kbd_poll(sc);\n\telse\n\t\tatkbdc_aux_poll(sc);\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\nvoid\natkbdc_init()\n{\n\tstruct inout_port iop;\n\tstruct atkbdc_softc *sc;\n\tint error;\n\n\tsc = calloc(1, sizeof(struct atkbdc_softc));\n\n\tpthread_mutex_init(&sc->mtx, NULL);\n\n\tbzero(&iop, sizeof(struct inout_port));\n\tiop.name = \"atkdbc\";\n\tiop.port = KBD_STS_CTL_PORT;\n\tiop.size = 1;\n\tiop.flags = IOPORT_F_INOUT;\n\tiop.handler = atkbdc_sts_ctl_handler;\n\tiop.arg = sc;\n\n\terror = register_inout(&iop);\n\tassert(error == 0);\n\n\tbzero(&iop, sizeof(struct inout_port));\n\tiop.name = \"atkdbc\";\n\tiop.port = KBD_DATA_PORT;\n\tiop.size = 1;\n\tiop.flags = IOPORT_F_INOUT;\n\tiop.handler = atkbdc_data_handler;\n\tiop.arg = sc;\n\n\terror = register_inout(&iop);\n\tassert(error == 0);\n\n\tpci_irq_reserve(KBD_DEV_IRQ);\n\tsc->kbd.irq = KBD_DEV_IRQ;\n\n\tpci_irq_reserve(AUX_DEV_IRQ);\n\tsc->aux.irq = AUX_DEV_IRQ;\n\n\tsc->ps2kbd_sc = ps2kbd_init(sc);\n\tsc->ps2mouse_sc = ps2mouse_init(sc);\n}\n\nstatic void\natkbdc_dsdt(void)\n{\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (KBD)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0303\\\"))\");\n\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_indent(2);\n\tdsdt_fixed_ioport(KBD_DATA_PORT, 1);\n\tdsdt_fixed_ioport(KBD_STS_CTL_PORT, 1);\n\tdsdt_fixed_irq(1);\n\tdsdt_unindent(2);\n\tdsdt_line(\"  })\");\n\tdsdt_line(\"}\");\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (MOU)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0F13\\\"))\");\n\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_indent(2);\n\tdsdt_fixed_ioport(KBD_DATA_PORT, 1);\n\tdsdt_fixed_ioport(KBD_STS_CTL_PORT, 1);\n\tdsdt_fixed_irq(12);\n\tdsdt_unindent(2);\n\tdsdt_line(\"  })\");\n\tdsdt_line(\"}\");\n}\nLPC_DSDT(atkbdc_dsdt);\n\n"
  },
  {
    "path": "src/bhyvegc.c",
    "content": "#include <sys/cdefs.h>\n\n#include <sys/types.h>\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include <xhyve/bhyvegc.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct bhyvegc {\n\tstruct bhyvegc_image\t*gc_image;\n\tint raw;\n};\n\n#pragma clang diagnostic pop\n\nstruct bhyvegc *\nbhyvegc_init(uint16_t width, uint16_t height, void *fbaddr)\n{\n\tstruct bhyvegc *gc;\n\tstruct bhyvegc_image *gc_image;\n\n\tgc = calloc(1, sizeof (struct bhyvegc));\n\n\tgc_image = calloc(1, sizeof(struct bhyvegc_image));\n\tgc_image->width = width;\n\tgc_image->height = height;\n\tif (fbaddr) {\n\t\tgc_image->data = fbaddr;\n\t\tgc->raw = 1;\n\t} else {\n\t\tgc_image->data = calloc(width * height, sizeof (uint32_t));\n\t\tgc->raw = 0;\n\t}\n\n\tgc->gc_image = gc_image;\n\n\treturn (gc);\n}\n\nvoid\nbhyvegc_set_fbaddr(struct bhyvegc *gc, void *fbaddr)\n{\n\tgc->raw = 1;\n\tif (gc->gc_image->data && gc->gc_image->data != fbaddr)\n\t\tfree(gc->gc_image->data);\n\tgc->gc_image->data = fbaddr;\n}\n\nvoid\nbhyvegc_resize(struct bhyvegc *gc, uint16_t width, uint16_t height)\n{\n\tstruct bhyvegc_image *gc_image;\n\n\tgc_image = gc->gc_image;\n\n\tgc_image->width = width;\n\tgc_image->height = height;\n\tif (!gc->raw) {\n\t\tgc_image->data = realloc(gc_image->data, width * height * sizeof (uint32_t));\n\t\tif (gc_image->data != NULL)\n\t\t\tmemset(gc_image->data, 0, width * height *\n\t\t\t    sizeof (uint32_t));\n\t}\n}\n\nstruct bhyvegc_image *\nbhyvegc_get_image(struct bhyvegc *gc)\n{\n\tif (gc == NULL)\n\t\treturn (NULL);\n\n\treturn (gc->gc_image);\n}\n"
  },
  {
    "path": "src/block_if.c",
    "content": "/*-\n * Copyright (c) 2013  Peter Grehan <grehan@freebsd.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <sys/param.h>\n#include <sys/queue.h>\n#include <sys/errno.h>\n#include <sys/stat.h>\n#include <sys/ioctl.h>\n#include <sys/disk.h>\n\n#include <assert.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <pthread.h>\n#include <signal.h>\n#include <unistd.h>\n\n#include <xhyve/support/atomic.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/mevent.h>\n#include <xhyve/block_if.h>\n\n#define BLOCKIF_SIG 0xb109b109\n/* xhyve: FIXME\n *\n * // #define BLOCKIF_NUMTHR 8\n *\n * OS X does not support preadv/pwritev, we need to serialize reads and writes\n * for the time being until we find a better solution.\n */\n#define BLOCKIF_NUMTHR 1\n\n#define BLOCKIF_MAXREQ (64 + BLOCKIF_NUMTHR)\n\nenum blockop {\n\tBOP_READ,\n\tBOP_WRITE,\n\tBOP_FLUSH,\n\tBOP_DELETE\n};\n\nenum blockstat {\n\tBST_FREE,\n\tBST_BLOCK,\n\tBST_PEND,\n\tBST_BUSY,\n\tBST_DONE\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct blockif_elem {\n\tTAILQ_ENTRY(blockif_elem) be_link;\n\tstruct blockif_req *be_req;\n\tenum blockop be_op;\n\tenum blockstat be_status;\n\tpthread_t be_tid;\n\toff_t be_block;\n};\n\nstruct blockif_ctxt {\n\tint bc_magic;\n\tint bc_fd;\n\tint bc_ischr;\n\tint bc_isgeom;\n\tint bc_candelete;\n\tint bc_rdonly;\n\toff_t bc_size;\n\tint bc_sectsz;\n\tint bc_psectsz;\n\tint bc_psectoff;\n\tint bc_closing;\n\tpthread_t bc_btid[BLOCKIF_NUMTHR];\n\tpthread_mutex_t bc_mtx;\n\tpthread_cond_t bc_cond;\n\t/* Request elements and free/pending/busy queues */\n\tTAILQ_HEAD(, blockif_elem) bc_freeq;\n\tTAILQ_HEAD(, blockif_elem) bc_pendq;\n\tTAILQ_HEAD(, blockif_elem) bc_busyq;\n\tstruct blockif_elem\tbc_reqs[BLOCKIF_MAXREQ];\n};\n\nstatic pthread_once_t blockif_once = PTHREAD_ONCE_INIT;\n\nstruct blockif_sig_elem {\n\tpthread_mutex_t bse_mtx;\n\tpthread_cond_t bse_cond;\n\tint bse_pending;\n\tstruct blockif_sig_elem *bse_next;\n};\n\nstatic struct blockif_sig_elem *blockif_bse_head;\n\n#pragma clang diagnostic pop\n\nstatic ssize_t\n_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)\n{\n\toff_t res;\n\n\tres = lseek(fd, offset, SEEK_SET);\n\tassert(res == offset);\n\treturn readv(fd, iov, iovcnt);\n}\n\nstatic ssize_t\n_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)\n{\n\toff_t res;\n\n\tres = lseek(fd, offset, SEEK_SET);\n\tassert(res == offset);\n\treturn writev(fd, iov, iovcnt);\n}\n\nstatic int\nblockif_enqueue(struct blockif_ctxt *bc, struct blockif_req *breq,\n\t\tenum blockop op)\n{\n\tstruct blockif_elem *be, *tbe;\n\toff_t off;\n\tint i;\n\n\tbe = TAILQ_FIRST(&bc->bc_freeq);\n\tassert(be != NULL);\n\tassert(be->be_status == BST_FREE);\n\tTAILQ_REMOVE(&bc->bc_freeq, be, be_link);\n\tbe->be_req = breq;\n\tbe->be_op = op;\n\tswitch (op) {\n\tcase BOP_READ:\n\tcase BOP_WRITE:\n\tcase BOP_DELETE:\n\t\toff = breq->br_offset;\n\t\tfor (i = 0; i < breq->br_iovcnt; i++)\n\t\t\toff += breq->br_iov[i].iov_len;\n\t\tbreak;\n\tcase BOP_FLUSH:\n\t\toff = OFF_MAX;\n\t}\n\tbe->be_block = off;\n\tTAILQ_FOREACH(tbe, &bc->bc_pendq, be_link) {\n\t\tif (tbe->be_block == breq->br_offset)\n\t\t\tbreak;\n\t}\n\tif (tbe == NULL) {\n\t\tTAILQ_FOREACH(tbe, &bc->bc_busyq, be_link) {\n\t\t\tif (tbe->be_block == breq->br_offset)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tif (tbe == NULL)\n\t\tbe->be_status = BST_PEND;\n\telse\n\t\tbe->be_status = BST_BLOCK;\n\tTAILQ_INSERT_TAIL(&bc->bc_pendq, be, be_link);\n\treturn (be->be_status == BST_PEND);\n}\n\nstatic int\nblockif_dequeue(struct blockif_ctxt *bc, pthread_t t, struct blockif_elem **bep)\n{\n\tstruct blockif_elem *be;\n\n\tTAILQ_FOREACH(be, &bc->bc_pendq, be_link) {\n\t\tif (be->be_status == BST_PEND)\n\t\t\tbreak;\n\t\tassert(be->be_status == BST_BLOCK);\n\t}\n\tif (be == NULL)\n\t\treturn (0);\n\tTAILQ_REMOVE(&bc->bc_pendq, be, be_link);\n\tbe->be_status = BST_BUSY;\n\tbe->be_tid = t;\n\tTAILQ_INSERT_TAIL(&bc->bc_busyq, be, be_link);\n\t*bep = be;\n\treturn (1);\n}\n\nstatic void\nblockif_complete(struct blockif_ctxt *bc, struct blockif_elem *be)\n{\n\tstruct blockif_elem *tbe;\n\n\tif (be->be_status == BST_DONE || be->be_status == BST_BUSY)\n\t\tTAILQ_REMOVE(&bc->bc_busyq, be, be_link);\n\telse\n\t\tTAILQ_REMOVE(&bc->bc_pendq, be, be_link);\n\tTAILQ_FOREACH(tbe, &bc->bc_pendq, be_link) {\n\t\tif (tbe->be_req->br_offset == be->be_block)\n\t\t\ttbe->be_status = BST_PEND;\n\t}\n\tbe->be_tid = 0;\n\tbe->be_status = BST_FREE;\n\tbe->be_req = NULL;\n\tTAILQ_INSERT_TAIL(&bc->bc_freeq, be, be_link);\n}\n\nstatic void\nblockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be, uint8_t *buf)\n{\n\tstruct blockif_req *br;\n\t// off_t arg[2];\n\tssize_t clen, len, off, boff, voff;\n\tint i, err;\n\n\tbr = be->be_req;\n\tif (br->br_iovcnt <= 1)\n\t\tbuf = NULL;\n\terr = 0;\n\tswitch (be->be_op) {\n\tcase BOP_READ:\n\t\tif (buf == NULL) {\n\t\t\tif ((len = _preadv(bc->bc_fd, br->br_iov, br->br_iovcnt,\n\t\t\t\t   br->br_offset)) < 0)\n\t\t\t\terr = errno;\n\t\t\telse\n\t\t\t\tbr->br_resid -= len;\n\t\t\tbreak;\n\t\t}\n\t\ti = 0;\n\t\toff = voff = 0;\n\t\twhile (br->br_resid > 0) {\n\t\t\tlen = MIN(br->br_resid, MAXPHYS);\n\t\t\tif (pread(bc->bc_fd, buf, ((size_t) len), br->br_offset + off) < 0)\n\t\t\t{\n\t\t\t\terr = errno;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tboff = 0;\n\t\t\tdo {\n\t\t\t\tclen = MIN((len - boff),\n\t\t\t\t\t(((ssize_t) br->br_iov[i].iov_len) - voff));\n\t\t\t\tmemcpy(((void *) (((uintptr_t) br->br_iov[i].iov_base) +\n\t\t\t\t\t((size_t) voff))), buf + boff, clen);\n\t\t\t\tif (clen < (((ssize_t) br->br_iov[i].iov_len) - voff))\n\t\t\t\t\tvoff += clen;\n\t\t\t\telse {\n\t\t\t\t\ti++;\n\t\t\t\t\tvoff = 0;\n\t\t\t\t}\n\t\t\t\tboff += clen;\n\t\t\t} while (boff < len);\n\t\t\toff += len;\n\t\t\tbr->br_resid -= len;\n\t\t}\n\t\tbreak;\n\tcase BOP_WRITE:\n\t\tif (bc->bc_rdonly) {\n\t\t\terr = EROFS;\n\t\t\tbreak;\n\t\t}\n\t\tif (buf == NULL) {\n\t\t\tif ((len = _pwritev(bc->bc_fd, br->br_iov, br->br_iovcnt,\n\t\t\t\t    br->br_offset)) < 0)\n\t\t\t\terr = errno;\n\t\t\telse\n\t\t\t\tbr->br_resid -= len;\n\t\t\tbreak;\n\t\t}\n\t\ti = 0;\n\t\toff = voff = 0;\n\t\twhile (br->br_resid > 0) {\n\t\t\tlen = MIN(br->br_resid, MAXPHYS);\n\t\t\tboff = 0;\n\t\t\tdo {\n\t\t\t\tclen = MIN((len - boff),\n\t\t\t\t\t(((ssize_t) br->br_iov[i].iov_len) - voff));\n\t\t\t\tmemcpy((buf + boff),\n\t\t\t\t\t((void *) (((uintptr_t) br->br_iov[i].iov_base) +\n\t\t\t\t\t\t((size_t) voff))), clen);\n\t\t\t\tif (clen < (((ssize_t) br->br_iov[i].iov_len) - voff))\n\t\t\t\t\tvoff += clen;\n\t\t\t\telse {\n\t\t\t\t\ti++;\n\t\t\t\t\tvoff = 0;\n\t\t\t\t}\n\t\t\t\tboff += clen;\n\t\t\t} while (boff < len);\n\t\t\tif (pwrite(bc->bc_fd, buf, ((size_t) len), br->br_offset +\n\t\t\t    off) < 0) {\n\t\t\t\terr = errno;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\toff += len;\n\t\t\tbr->br_resid -= len;\n\t\t}\n\t\tbreak;\n\tcase BOP_FLUSH:\n\t\tif (bc->bc_ischr) {\n\t\t\tif (ioctl(bc->bc_fd, DKIOCSYNCHRONIZECACHE))\n\t\t\t\terr = errno;\n\t\t} else if (fsync(bc->bc_fd))\n\t\t\terr = errno;\n\t\tbreak;\n\tcase BOP_DELETE:\n\t\tif (!bc->bc_candelete) {\n\t\t\terr = EOPNOTSUPP;\n\t\t// } else if (bc->bc_rdonly) {\n\t\t// \terr = EROFS;\n\t\t// } else if (bc->bc_ischr) {\n\t\t// \targ[0] = br->br_offset;\n\t\t// \targ[1] = br->br_resid;\n\t\t// \tif (ioctl(bc->bc_fd, DIOCGDELETE, arg)) {\n\t\t// \t\terr = errno;\n\t\t// \t} else {\n\t\t// \t\tbr->br_resid = 0;\n\t\t// \t}\n\t\t} else {\n\t\t\terr = EOPNOTSUPP;\n\t\t}\n\t\tbreak;\n\t}\n\n\tbe->be_status = BST_DONE;\n\n\t(*br->br_callback)(br, err);\n}\n\nstatic void *\nblockif_thr(void *arg)\n{\n\tstruct blockif_ctxt *bc;\n\tstruct blockif_elem *be;\n\tpthread_t t;\n\tuint8_t *buf;\n\n\tbc = arg;\n\tif (bc->bc_isgeom)\n\t\tbuf = malloc(MAXPHYS);\n\telse\n\t\tbuf = NULL;\n\tt = pthread_self();\n\n\tpthread_mutex_lock(&bc->bc_mtx);\n\tfor (;;) {\n\t\twhile (blockif_dequeue(bc, t, &be)) {\n\t\t\tpthread_mutex_unlock(&bc->bc_mtx);\n\t\t\tblockif_proc(bc, be, buf);\n\t\t\tpthread_mutex_lock(&bc->bc_mtx);\n\t\t\tblockif_complete(bc, be);\n\t\t}\n\t\t/* Check ctxt status here to see if exit requested */\n\t\tif (bc->bc_closing)\n\t\t\tbreak;\n\t\tpthread_cond_wait(&bc->bc_cond, &bc->bc_mtx);\n\t}\n\tpthread_mutex_unlock(&bc->bc_mtx);\n\n\tif (buf)\n\t\tfree(buf);\n\tpthread_exit(NULL);\n\treturn (NULL);\n}\n\nstatic void\nblockif_sigcont_handler(UNUSED int signal, UNUSED enum ev_type type,\n\tUNUSED void *arg)\n{\n\tstruct blockif_sig_elem *bse;\n\n\tfor (;;) {\n\t\t/*\n\t\t * Process the entire list even if not intended for\n\t\t * this thread.\n\t\t */\n\t\tdo {\n\t\t\tbse = blockif_bse_head;\n\t\t\tif (bse == NULL)\n\t\t\t\treturn;\n\t\t} while (!atomic_cmpset_ptr((uintptr_t *)&blockif_bse_head,\n\t\t\t\t\t    (uintptr_t)bse,\n\t\t\t\t\t    (uintptr_t)bse->bse_next));\n\n\t\tpthread_mutex_lock(&bse->bse_mtx);\n\t\tbse->bse_pending = 0;\n\t\tpthread_cond_signal(&bse->bse_cond);\n\t\tpthread_mutex_unlock(&bse->bse_mtx);\n\t}\n}\n\nstatic void\nblockif_init(void)\n{\n\tmevent_add(SIGCONT, EVF_SIGNAL, blockif_sigcont_handler, NULL);\n\t(void) signal(SIGCONT, SIG_IGN);\n}\n\nstruct blockif_ctxt *\nblockif_open(const char *optstr, UNUSED const char *ident)\n{\n\t// char name[MAXPATHLEN];\n\tchar *nopt, *xopts, *cp;\n\tstruct blockif_ctxt *bc;\n\tstruct stat sbuf;\n\t// struct diocgattr_arg arg;\n\toff_t size, psectsz, psectoff;\n\tint extra, fd, i, sectsz;\n\tint nocache, sync, ro, candelete, geom, ssopt, pssopt;\n\n\tpthread_once(&blockif_once, blockif_init);\n\n\tfd = -1;\n\tssopt = 0;\n\tnocache = 0;\n\tsync = 0;\n\tro = 0;\n\n\tpssopt = 0;\n\t/*\n\t * The first element in the optstring is always a pathname.\n\t * Optional elements follow\n\t */\n\tnopt = xopts = strdup(optstr);\n\twhile (xopts != NULL) {\n\t\tcp = strsep(&xopts, \",\");\n\t\tif (cp == nopt)\t\t/* file or device pathname */\n\t\t\tcontinue;\n\t\telse if (!strcmp(cp, \"nocache\"))\n\t\t\tnocache = 1;\n\t\telse if (!strcmp(cp, \"sync\") || !strcmp(cp, \"direct\"))\n\t\t\tsync = 1;\n\t\telse if (!strcmp(cp, \"ro\"))\n\t\t\tro = 1;\n\t\telse if (sscanf(cp, \"sectorsize=%d/%d\", &ssopt, &pssopt) == 2)\n\t\t\t;\n\t\telse if (sscanf(cp, \"sectorsize=%d\", &ssopt) == 1)\n\t\t\tpssopt = ssopt;\n\t\telse {\n\t\t\tfprintf(stderr, \"Invalid device option \\\"%s\\\"\\n\", cp);\n\t\t\tgoto err;\n\t\t}\n\t}\n\n\textra = 0;\n\tif (nocache) {\n\t\tperror(\"xhyve: nocache support unimplemented\");\n\t\tgoto err;\n\t\t// extra |= O_DIRECT;\n\t}\n\tif (sync)\n\t\textra |= O_SYNC;\n\n\tfd = open(nopt, (ro ? O_RDONLY : O_RDWR) | extra);\n\tif (fd < 0 && !ro) {\n\t\t/* Attempt a r/w fail with a r/o open */\n\t\tfd = open(nopt, O_RDONLY | extra);\n\t\tro = 1;\n\t}\n\n\tif (fd < 0) {\n\t\tperror(\"Could not open backing file\");\n\t\tgoto err;\n\t}\n\n\tif (fstat(fd, &sbuf) < 0) {\n\t\tperror(\"Could not stat backing file\");\n\t\tgoto err;\n\t}\n\n    /*\n\t * Deal with raw devices\n\t */\n\tsize = sbuf.st_size;\n\tsectsz = DEV_BSIZE;\n\tpsectsz = psectoff = 0;\n\tcandelete = geom = 0;\n\tif (S_ISCHR(sbuf.st_mode)) {\n\t\tperror(\"xhyve: raw device support unimplemented\");\n\t\tgoto err;\t\t\n\t\t// if (ioctl(fd, DIOCGMEDIASIZE, &size) < 0 ||\n\t\t// \tioctl(fd, DIOCGSECTORSIZE, &sectsz))\n\t\t// {\n\t\t// \tperror(\"Could not fetch dev blk/sector size\");\n\t\t// \tgoto err;\n\t\t// }\n\t\t// assert(size != 0);\n\t\t// assert(sectsz != 0);\n\t\t// if (ioctl(fd, DIOCGSTRIPESIZE, &psectsz) == 0 && psectsz > 0)\n\t\t// \tioctl(fd, DIOCGSTRIPEOFFSET, &psectoff);\n\t\t// strlcpy(arg.name, \"GEOM::candelete\", sizeof(arg.name));\n\t\t// arg.len = sizeof(arg.value.i);\n\t\t// if (ioctl(fd, DIOCGATTR, &arg) == 0)\n\t\t// \tcandelete = arg.value.i;\n\t\t// if (ioctl(fd, DIOCGPROVIDERNAME, name) == 0)\n\t\t// \tgeom = 1;\n\t} else if (S_ISBLK(sbuf.st_mode)) {\n\t\tuint64_t num_blocks;\n\t\tuint32_t block_size;\n\t\tif (ioctl(fd, DKIOCGETBLOCKSIZE, (void*)&block_size) < 0) {\n\t\t\tperror(\"DKIOCGETBLOCKSIZE\");\n\t\t\tgoto err;\n\t\t}\n\t\tif (ioctl(fd, DKIOCGETBLOCKCOUNT, (void*)&num_blocks) < 0) {\n\t\t\tperror(\"DKIOCGETBLOCKCOUNT\");\n\t\t\tgoto err;\n\t\t}\n\t\tsize = (off_t) (num_blocks * block_size);\n\t\tsectsz = (int) block_size;\n\t} else {\n\t\tpsectsz = sbuf.st_blksize;\n\t}\n\n\tif (ssopt != 0) {\n\t\tif (!powerof2(ssopt) || !powerof2(pssopt) || ssopt < 512 ||\n\t\t    ssopt > pssopt) {\n\t\t\tfprintf(stderr, \"Invalid sector size %d/%d\\n\",\n\t\t\t    ssopt, pssopt);\n\t\t\tgoto err;\n\t\t}\n\n\t\t// /*\n\t\t//  * Some backend drivers (e.g. cd0, ada0) require that the I/O\n\t\t//  * size be a multiple of the device's sector size.\n\t\t//  *\n\t\t//  * Validate that the emulated sector size complies with this\n\t\t//  * requirement.\n\t\t//  */\n\t\t// if (S_ISCHR(sbuf.st_mode)) {\n\t\t// \tif (ssopt < sectsz || (ssopt % sectsz) != 0) {\n\t\t// \t\tfprintf(stderr, \"Sector size %d incompatible \"\n\t\t// \t\t    \"with underlying device sector size %d\\n\",\n\t\t// \t\t    ssopt, sectsz);\n\t\t// \t\tgoto err;\n\t\t// \t}\n\t\t// }\n\n\t\tsectsz = ssopt;\n\t\tpsectsz = pssopt;\n\t\tpsectoff = 0;\n\t}\n\n\tbc = calloc(1, sizeof(struct blockif_ctxt));\n\tif (bc == NULL) {\n\t\tperror(\"calloc\");\n\t\tgoto err;\n\t}\n\n\tbc->bc_magic = (int) BLOCKIF_SIG;\n\tbc->bc_fd = fd;\n\tbc->bc_ischr = S_ISCHR(sbuf.st_mode);\n\tbc->bc_isgeom = geom;\n\tbc->bc_candelete = candelete;\n\tbc->bc_rdonly = ro;\n\tbc->bc_size = size;\n\tbc->bc_sectsz = sectsz;\n\tbc->bc_psectsz = (int) psectsz;\n\tbc->bc_psectoff = (int) psectoff;\n\tpthread_mutex_init(&bc->bc_mtx, NULL);\n\tpthread_cond_init(&bc->bc_cond, NULL);\n\tTAILQ_INIT(&bc->bc_freeq);\n\tTAILQ_INIT(&bc->bc_pendq);\n\tTAILQ_INIT(&bc->bc_busyq);\n\tfor (i = 0; i < BLOCKIF_MAXREQ; i++) {\n\t\tbc->bc_reqs[i].be_status = BST_FREE;\n\t\tTAILQ_INSERT_HEAD(&bc->bc_freeq, &bc->bc_reqs[i], be_link);\n\t}\n\n\tfor (i = 0; i < BLOCKIF_NUMTHR; i++) {\n\t\tpthread_create(&bc->bc_btid[i], NULL, blockif_thr, bc);\n\t}\n\n\treturn (bc);\nerr:\n\tif (fd >= 0)\n\t\tclose(fd);\n\treturn (NULL);\n}\n\nstatic int\nblockif_request(struct blockif_ctxt *bc, struct blockif_req *breq,\n\t\tenum blockop op)\n{\n\tint err;\n\n\terr = 0;\n\n\tpthread_mutex_lock(&bc->bc_mtx);\n\tif (!TAILQ_EMPTY(&bc->bc_freeq)) {\n\t\t/*\n\t\t * Enqueue and inform the block i/o thread\n\t\t * that there is work available\n\t\t */\n\t\tif (blockif_enqueue(bc, breq, op))\n\t\t\tpthread_cond_signal(&bc->bc_cond);\n\t} else {\n\t\t/*\n\t\t * Callers are not allowed to enqueue more than\n\t\t * the specified blockif queue limit. Return an\n\t\t * error to indicate that the queue length has been\n\t\t * exceeded.\n\t\t */\n\t\terr = E2BIG;\n\t}\n\tpthread_mutex_unlock(&bc->bc_mtx);\n\n\treturn (err);\n}\n\nint\nblockif_read(struct blockif_ctxt *bc, struct blockif_req *breq)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (blockif_request(bc, breq, BOP_READ));\n}\n\nint\nblockif_write(struct blockif_ctxt *bc, struct blockif_req *breq)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (blockif_request(bc, breq, BOP_WRITE));\n}\n\nint\nblockif_flush(struct blockif_ctxt *bc, struct blockif_req *breq)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (blockif_request(bc, breq, BOP_FLUSH));\n}\n\nint\nblockif_delete(struct blockif_ctxt *bc, struct blockif_req *breq)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (blockif_request(bc, breq, BOP_DELETE));\n}\n\nint\nblockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq)\n{\n\tstruct blockif_elem *be;\n\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\n\tpthread_mutex_lock(&bc->bc_mtx);\n\t/*\n\t * Check pending requests.\n\t */\n\tTAILQ_FOREACH(be, &bc->bc_pendq, be_link) {\n\t\tif (be->be_req == breq)\n\t\t\tbreak;\n\t}\n\tif (be != NULL) {\n\t\t/*\n\t\t * Found it.\n\t\t */\n\t\tblockif_complete(bc, be);\n\t\tpthread_mutex_unlock(&bc->bc_mtx);\n\n\t\treturn (0);\n\t}\n\n\t/*\n\t * Check in-flight requests.\n\t */\n\tTAILQ_FOREACH(be, &bc->bc_busyq, be_link) {\n\t\tif (be->be_req == breq)\n\t\t\tbreak;\n\t}\n\tif (be == NULL) {\n\t\t/*\n\t\t * Didn't find it.\n\t\t */\n\t\tpthread_mutex_unlock(&bc->bc_mtx);\n\t\treturn (EINVAL);\n\t}\n\n\t/*\n\t * Interrupt the processing thread to force it return\n\t * prematurely via it's normal callback path.\n\t */\n\twhile (be->be_status == BST_BUSY) {\n\t\tstruct blockif_sig_elem bse, *old_head;\n\n\t\tpthread_mutex_init(&bse.bse_mtx, NULL);\n\t\tpthread_cond_init(&bse.bse_cond, NULL);\n\n\t\tbse.bse_pending = 1;\n\n\t\tdo {\n\t\t\told_head = blockif_bse_head;\n\t\t\tbse.bse_next = old_head;\n\t\t} while (!atomic_cmpset_ptr((uintptr_t *)&blockif_bse_head,\n\t\t\t\t\t    (uintptr_t)old_head,\n\t\t\t\t\t    (uintptr_t)&bse));\n\n\t\tpthread_kill(be->be_tid, SIGCONT);\n\n\t\tpthread_mutex_lock(&bse.bse_mtx);\n\t\twhile (bse.bse_pending)\n\t\t\tpthread_cond_wait(&bse.bse_cond, &bse.bse_mtx);\n\t\tpthread_mutex_unlock(&bse.bse_mtx);\n\t}\n\n\tpthread_mutex_unlock(&bc->bc_mtx);\n\n\t/*\n\t * The processing thread has been interrupted.  Since it's not\n\t * clear if the callback has been invoked yet, return EBUSY.\n\t */\n\treturn (EBUSY);\n}\n\nint\nblockif_close(struct blockif_ctxt *bc)\n{\n\tvoid *jval;\n\tint err, i;\n\n\terr = 0;\n\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\n\t/*\n\t * Stop the block i/o thread\n\t */\n\tpthread_mutex_lock(&bc->bc_mtx);\n\tbc->bc_closing = 1;\n\tpthread_mutex_unlock(&bc->bc_mtx);\n\tpthread_cond_broadcast(&bc->bc_cond);\n\tfor (i = 0; i < BLOCKIF_NUMTHR; i++)\n\t\tpthread_join(bc->bc_btid[i], &jval);\n\n\t/* XXX Cancel queued i/o's ??? */\n\n\t/*\n\t * Release resources\n\t */\n\tbc->bc_magic = 0;\n\tclose(bc->bc_fd);\n\tfree(bc);\n\n\treturn (0);\n}\n\n/*\n * Return virtual C/H/S values for a given block. Use the algorithm\n * outlined in the VHD specification to calculate values.\n */\nvoid\nblockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h, uint8_t *s)\n{\n\toff_t sectors;\t\t/* total sectors of the block dev */\n\toff_t hcyl;\t\t/* cylinders times heads */\n\tuint16_t secpt;\t\t/* sectors per track */\n\tuint8_t heads;\n\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\n\tsectors = bc->bc_size / bc->bc_sectsz;\n\n\t/* Clamp the size to the largest possible with CHS */\n\tif (sectors > 65535LL*16*255)\n\t\tsectors = 65535LL*16*255;\n\n\tif (sectors >= 65536LL*16*63) {\n\t\tsecpt = 255;\n\t\theads = 16;\n\t\thcyl = sectors / secpt;\n\t} else {\n\t\tsecpt = 17;\n\t\thcyl = sectors / secpt;\n\t\theads = (uint8_t) ((hcyl + 1023) / 1024);\n\n\t\tif (heads < 4)\n\t\t\theads = 4;\n\n\t\tif (hcyl >= (heads * 1024) || heads > 16) {\n\t\t\tsecpt = 31;\n\t\t\theads = 16;\n\t\t\thcyl = sectors / secpt;\n\t\t}\n\t\tif (hcyl >= (heads * 1024)) {\n\t\t\tsecpt = 63;\n\t\t\theads = 16;\n\t\t\thcyl = sectors / secpt;\n\t\t}\n\t}\n\n\t*c = (uint16_t) (hcyl / heads);\n\t*h = heads;\n\t*s = (uint8_t) secpt;\n}\n\n/*\n * Accessors\n */\noff_t\nblockif_size(struct blockif_ctxt *bc)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (bc->bc_size);\n}\n\nint\nblockif_sectsz(struct blockif_ctxt *bc)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (bc->bc_sectsz);\n}\n\nvoid\nblockif_psectsz(struct blockif_ctxt *bc, int *size, int *off)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\t*size = bc->bc_psectsz;\n\t*off = bc->bc_psectoff;\n}\n\nint\nblockif_queuesz(struct blockif_ctxt *bc)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (BLOCKIF_MAXREQ - 1);\n}\n\nint\nblockif_is_ro(struct blockif_ctxt *bc)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (bc->bc_rdonly);\n}\n\nint\nblockif_candelete(struct blockif_ctxt *bc)\n{\n\tassert(bc->bc_magic == ((int) BLOCKIF_SIG));\n\treturn (bc->bc_candelete);\n}\n"
  },
  {
    "path": "src/bootrom.c",
    "content": "/*-\n * Copyright (c) 2015 Neel Natu <neel@freebsd.org>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/param.h>\n\n#include <sys/types.h>\n#include <sys/mman.h>\n#include <sys/stat.h>\n\n#include <errno.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <stdbool.h>\n\n#include <xhyve/support/misc.h>\n\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/bootrom.h>\n\n#define\tMAX_BOOTROM_SIZE\t(16 * 1024 * 1024)\t/* 16 MB */\n\nint\nbootrom_init(const char *romfile)\n{\n\tstruct stat sbuf;\n\tssize_t rlen;\n\tchar *ptr;\n\tint fd, i, rv;\n\n\trv = -1;\n\tfd = open(romfile, O_RDONLY);\n\tif (fd < 0) {\n\t\tfprintf(stderr, \"Error opening bootrom \\\"%s\\\": %s\\n\",\n\t\t    romfile, strerror(errno));\n\t\tgoto done;\n\t}\n\n        if (fstat(fd, &sbuf) < 0) {\n\t\tfprintf(stderr, \"Could not fstat bootrom file \\\"%s\\\": %s\\n\",\n\t\t    romfile, strerror(errno));\n\t\tgoto done;\n        }\n\n\t/*\n\t * Limit bootrom size to 16MB so it doesn't encroach into reserved\n\t * MMIO space (e.g. APIC, HPET, MSI).\n\t */\n\tif (sbuf.st_size > MAX_BOOTROM_SIZE || sbuf.st_size < XHYVE_PAGE_SIZE) {\n\t\tfprintf(stderr, \"Invalid bootrom size %lld\\n\", sbuf.st_size);\n\t\tgoto done;\n\t}\n\n\tif (sbuf.st_size & XHYVE_PAGE_MASK) {\n\t\tfprintf(stderr, \"Bootrom size %lld is not a multiple of the \"\n\t\t    \"page size\\n\", sbuf.st_size);\n\t\tgoto done;\n\t}\n\n\t/* Map the bootrom into the guest address space */\n\tif (xh_setup_bootrom_memory((size_t)sbuf.st_size, (void **)&ptr) != 0)\n    {\n        fprintf(stderr, \"hv_setup_bootrom_memory failed\\n\");\n\t\tgoto done;\n    }\n\n\t/* Read 'romfile' into the guest address space */\n\tfor (i = 0; i < sbuf.st_size / XHYVE_PAGE_SIZE; i++) {\n\t\trlen = read(fd, ptr + i * XHYVE_PAGE_SIZE, XHYVE_PAGE_SIZE);\n\t\tif (rlen != XHYVE_PAGE_SIZE) {\n\t\t\tfprintf(stderr, \"Incomplete read of page %d of bootrom \"\n\t\t\t    \"file %s: %ld bytes\\n\", i, romfile, rlen);\n\t\t\tgoto done;\n\t\t}\n\t}\n\trv = 0;\ndone:\n\tif (fd >= 0)\n\t\tclose(fd);\n\treturn (rv);\n}\n"
  },
  {
    "path": "src/console.c",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n\n#include <xhyve/bhyvegc.h>\n#include <xhyve/console.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstatic struct {\n\tstruct bhyvegc\t\t*gc;\n\n\tfb_render_func_t\tfb_render_cb;\n\tvoid\t\t\t*fb_arg;\n\n\tkbd_event_func_t\tkbd_event_cb;\n\tvoid\t\t\t*kbd_arg;\n\tint\t\t\tkbd_priority;\n\n\tptr_event_func_t\tptr_event_cb;\n\tvoid\t\t\t*ptr_arg;\n\tint\t\t\tptr_priority;\n} console;\n\n#pragma clang diagnostic pop\n\nvoid\nconsole_init(uint16_t w, uint16_t h, void *fbaddr)\n{\n\tconsole.gc = bhyvegc_init(w, h, fbaddr);\n}\n\nvoid\nconsole_set_fbaddr(void *fbaddr)\n{\n\tbhyvegc_set_fbaddr(console.gc, fbaddr);\n}\n\nstruct bhyvegc_image *\nconsole_get_image(void)\n{\n\tstruct bhyvegc_image *bhyvegc_image;\n\n\tbhyvegc_image = bhyvegc_get_image(console.gc);\n\n\treturn (bhyvegc_image);\n}\n\nvoid\nconsole_fb_register(fb_render_func_t render_cb, void *arg)\n{\n\tconsole.fb_render_cb = render_cb;\n\tconsole.fb_arg = arg;\n}\n\nvoid\nconsole_refresh(void)\n{\n\tif (console.fb_render_cb)\n\t\t(*console.fb_render_cb)(console.gc, console.fb_arg);\n}\n\nvoid\nconsole_kbd_register(kbd_event_func_t event_cb, void *arg, int pri)\n{\n\tif (pri > console.kbd_priority) {\n\t\tconsole.kbd_event_cb = event_cb;\n\t\tconsole.kbd_arg = arg;\n\t\tconsole.kbd_priority = pri;\n\t}\n}\n\nvoid\nconsole_ptr_register(ptr_event_func_t event_cb, void *arg, int pri)\n{\n\tif (pri > console.ptr_priority) {\n\t\tconsole.ptr_event_cb = event_cb;\n\t\tconsole.ptr_arg = arg;\n\t\tconsole.ptr_priority = pri;\n\t}\n}\n\nvoid\nconsole_key_event(int down, uint32_t keysym)\n{\n\tif (console.kbd_event_cb)\n\t\t(*console.kbd_event_cb)(down, keysym, console.kbd_arg);\n}\n\nvoid\nconsole_ptr_event(uint8_t button, int x, int y)\n{\n\tif (console.ptr_event_cb)\n\t\t(*console.ptr_event_cb)(button, x, y, console.ptr_arg);\n}\n"
  },
  {
    "path": "src/consport.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <termios.h>\n#include <unistd.h>\n#include <stdbool.h>\n#include <sys/time.h>\n#include <sys/types.h>\n#include <sys/select.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/inout.h>\n#include <xhyve/pci_lpc.h>\n\n#define\tBVM_CONSOLE_PORT 0x220\n#define\tBVM_CONS_SIG ('b' << 8 | 'v')\n\nstatic struct termios tio_orig, tio_new;\n\nstatic void\nttyclose(void)\n{\n\ttcsetattr(STDIN_FILENO, TCSANOW, &tio_orig);\n}\n\nstatic void\nttyopen(void)\n{\n\ttcgetattr(STDIN_FILENO, &tio_orig);\n\n\tcfmakeraw(&tio_new);\n\ttcsetattr(STDIN_FILENO, TCSANOW, &tio_new);\t\n\n\tatexit(ttyclose);\n}\n\nstatic bool\ntty_char_available(void)\n{\n\tfd_set rfds;\n\tstruct timeval tv;\n\n\tFD_ZERO(&rfds);\n\tFD_SET(STDIN_FILENO, &rfds);\n\ttv.tv_sec = 0;\n\ttv.tv_usec = 0;\n\n\tif (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0) {\n\t\treturn (true);\n\t} else {\n\t\treturn (false);\n\t}\n}\n\nstatic int\nttyread(void)\n{\n\tchar rb;\n\n\tif (tty_char_available()) {\n\t\tread(STDIN_FILENO, &rb, 1);\n\t\treturn (rb & 0xff);\n\t} else {\n\t\treturn (-1);\n\t}\n}\n\nstatic void\nttywrite(unsigned char wb)\n{\n\t(void) write(STDOUT_FILENO, &wb, 1);\n}\n\nstatic int\nconsole_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tstatic int opened;\n\n\tif (bytes == 2 && in) {\n\t\t*eax = BVM_CONS_SIG;\n\t\treturn (0);\n\t}\n\n\t/*\n\t * Guests might probe this port to look for old ISA devices\n\t * using single-byte reads.  Return 0xff for those.\n\t */\n\tif (bytes == 1 && in) {\n\t\t*eax = 0xff;\n\t\treturn (0);\n\t}\n\n\tif (bytes != 4)\n\t\treturn (-1);\n\n\tif (!opened) {\n\t\tttyopen();\n\t\topened = 1;\n\t}\n\t\n\tif (in)\n\t\t*eax = (uint32_t) ttyread();\n\telse\n\t\tttywrite((unsigned char) *eax);\n\n\treturn (0);\n}\n\nSYSRES_IO(BVM_CONSOLE_PORT, 4);\n\nstatic struct inout_port consport = {\n\t\"bvmcons\",\n\tBVM_CONSOLE_PORT,\n\t1,\n\tIOPORT_F_INOUT,\n\tconsole_handler,\n\tNULL\n};\n\nvoid\ninit_bvmcons(void)\n{\n\tregister_inout(&consport);\n}\n"
  },
  {
    "path": "src/dbgport.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <sys/uio.h>\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/inout.h>\n#include <xhyve/dbgport.h>\n#include <xhyve/pci_lpc.h>\n\n#define\tBVM_DBG_PORT 0x224\n#define\tBVM_DBG_SIG ('B' << 8 | 'V')\n\nstatic int listen_fd, conn_fd;\n\nstatic struct sockaddr_in saddrin;\n\nstatic int\ndbg_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes, uint32_t *eax,\n\tUNUSED void *arg)\n{\n\tchar ch;\n\tint nwritten, nread, printonce;\n\n\tif (bytes == 2 && in) {\n\t\t*eax = BVM_DBG_SIG;\n\t\treturn (0);\n\t}\n\n\tif (bytes != 4)\n\t\treturn (-1);\n\nagain:\n\tprintonce = 0;\n\twhile (conn_fd < 0) {\n\t\tif (!printonce) {\n\t\t\tprintf(\"Waiting for connection from gdb\\r\\n\");\n\t\t\tprintonce = 1;\n\t\t}\n\t\tconn_fd = accept(listen_fd, NULL, NULL);\n\t\tif (conn_fd >= 0)\n\t\t\tfcntl(conn_fd, F_SETFL, O_NONBLOCK);\n\t\telse if (errno != EINTR)\n\t\t\tperror(\"accept\");\n\t}\n\n\tif (in) {\n\t\tnread = (int) read(conn_fd, &ch, 1);\n\t\tif (nread == -1 && errno == EAGAIN)\n\t\t\t*eax = (uint32_t) (-1);\n\t\telse if (nread == 1)\n\t\t\t*eax = (uint32_t) ch;\n\t\telse {\n\t\t\tclose(conn_fd);\n\t\t\tconn_fd = -1;\n\t\t\tgoto again;\n\t\t}\n\t} else {\n\t\tch = (char) *eax;\n\t\tnwritten = (int) write(conn_fd, &ch, 1);\n\t\tif (nwritten != 1) {\n\t\t\tclose(conn_fd);\n\t\t\tconn_fd = -1;\n\t\t\tgoto again;\n\t\t}\n\t}\n\treturn (0);\n}\n\nstatic struct inout_port dbgport = {\n\t\"bvmdbg\",\n\tBVM_DBG_PORT,\n\t1,\n\tIOPORT_F_INOUT,\n\tdbg_handler,\n\tNULL\n};\n\nSYSRES_IO(BVM_DBG_PORT, 4);\n\nvoid\ninit_dbgport(int sport)\n{\n\tconn_fd = -1;\n\n\tif ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {\n\t\tperror(\"socket\");\n\t\texit(1);\n\t}\n\n\tsaddrin.sin_len = sizeof(saddrin);\n\tsaddrin.sin_family = AF_INET;\n\tsaddrin.sin_addr.s_addr = htonl(INADDR_ANY);\n\tsaddrin.sin_port = htons(sport);\n\n\tif (bind(listen_fd, (struct sockaddr *)&saddrin, sizeof(saddrin)) < 0) {\n\t\tperror(\"bind\");\n\t\texit(1);\n\t}\n\n\tif (listen(listen_fd, 1) < 0) {\n\t\tperror(\"listen\");\n\t\texit(1);\n\t}\n\n\tregister_inout(&dbgport);\n}\n"
  },
  {
    "path": "src/dsdt.asl",
    "content": "/*\n * bhyve DSDT template\n */\nDefinitionBlock (\"bhyve_dsdt.aml\", \"DSDT\", 2,\"BHYVE \", \"BVDSDT  \", 0x00000001)\n{\n  Name (_S5, Package ()\n  {\n      0x05,\n      Zero,\n  })\n  Name (PICM, 0x00)\n  Method (_PIC, 1, NotSerialized)\n  {\n    Store (Arg0, PICM)\n  }\n\n  Scope (_SB)\n  {\n    Device (PC00)\n    {\n      Name (_HID, EisaId (\"PNP0A03\"))\n      Name (_ADR, Zero)\n      Method (_BBN, 0, NotSerialized)\n      {\n          Return (0x00000000)\n      }\n      Name (_CRS, ResourceTemplate ()\n      {\n        WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,\n          0x0000,             // Granularity\n          0x0000,             // Range Minimum\n          0x0000,             // Range Maximum\n          0x0000,             // Translation Offset\n          0x0001,             // Length\n          ,, )\n        IO (Decode16,\n          0x0CF8,             // Range Minimum\n          0x0CF8,             // Range Maximum\n          0x01,               // Alignment\n          0x08,               // Length\n          )\n        WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,\n          0x0000,             // Granularity\n          0x0000,             // Range Minimum\n          0x0CF7,             // Range Maximum\n          0x0000,             // Translation Offset\n          0x0CF8,             // Length\n          ,, , TypeStatic)\n        WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,\n          0x0000,             // Granularity\n          0x0D00,             // Range Minimum\n          0x1FFF,             // Range Maximum\n          0x0000,             // Translation Offset\n          0x1300,             // Length\n          ,, , TypeStatic)\n        WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,\n          0x0000,             // Granularity\n          0x0000,             // Range Minimum\n          0x0000,             // Range Maximum\n          0x0000,             // Translation Offset\n          0x0020,             // Length\n          ,, , TypeStatic)\n        DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,\n          0x00000000,         // Granularity\n          0x00000000,         // Range Minimum\n\n          0x00000000,         // Range Maximum\n\n          0x00000000,         // Translation Offset\n          0x00000000,         // Length\n\n          ,, , AddressRangeMemory, TypeStatic)\n        QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,\n          0x0000000000000000, // Granularity\n          0x0000000000000000, // Range Minimum\n\n          0x0000000000000000, // Range Maximum\n\n          0x0000000000000000, // Translation Offset\n          0x0000000000000000, // Length\n\n          ,, , AddressRangeMemory, TypeStatic)\n      })\n      Name (PPRT, Package ()\n      {\n        Package ()\n        {\n          0x1FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKA,,\n          0x00\n        },\n        Package ()\n        {\n          0x2FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKB,,\n          0x00\n        },\n        Package ()\n        {\n          0x3FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKC,,\n          0x00\n        },\n        Package ()\n        {\n          0x4FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKD,,\n          0x00\n        },\n        Package ()\n        {\n          0x5FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKE,,\n          0x00\n        },\n        Package ()\n        {\n          0x6FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKF,,\n          0x00\n        },\n        Package ()\n        {\n          0x7FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKG,,\n          0x00\n        },\n        Package ()\n        {\n          0x8FFFF,\n          0x00,\n          \\_SB.PC00.ISA.LNKH,,\n          0x00\n        },\n      })\n      Name (APRT, Package ()\n      {\n        Package ()\n        {\n          0x1FFFF,\n          0x00,\n          Zero,\n          0x10\n        },\n        Package ()\n        {\n          0x2FFFF,\n          0x00,\n          Zero,\n          0x11\n        },\n        Package ()\n        {\n          0x3FFFF,\n          0x00,\n          Zero,\n          0x12\n        },\n        Package ()\n        {\n          0x4FFFF,\n          0x00,\n          Zero,\n          0x13\n        },\n        Package ()\n        {\n          0x5FFFF,\n          0x00,\n          Zero,\n          0x14\n        },\n        Package ()\n        {\n          0x6FFFF,\n          0x00,\n          Zero,\n          0x15\n        },\n        Package ()\n        {\n          0x7FFFF,\n          0x00,\n          Zero,\n          0x16\n        },\n        Package ()\n        {\n          0x8FFFF,\n          0x00,\n          Zero,\n          0x17\n        },\n      })\n      Method (_PRT, 0, NotSerialized)\n      {\n        If (PICM)\n        {\n          Return (APRT)\n        }\n        Else\n        {\n          Return (PPRT)\n        }\n      }\n\n      Device (ISA)\n      {\n        Name (_ADR, 0x001F0000)\n        OperationRegion (LPCR, PCI_Config, 0x00, 0x100)\n        Field (LPCR, AnyAcc, NoLock, Preserve)\n        {\n          Offset (0x60),\n          PIRA,   8,\n          PIRB,   8,\n          PIRC,   8,\n          PIRD,   8,\n          Offset (0x68),\n          PIRE,   8,\n          PIRF,   8,\n          PIRG,   8,\n          PIRH,   8\n        }\n\n\n        Method (PIRV, 1, NotSerialized)\n        {\n          If (And (Arg0, 0x80))\n          {\n            Return (0x00)\n          }\n          And (Arg0, 0x0F, Local0)\n          If (LLess (Local0, 0x03))\n          {\n            Return (0x00)\n          }\n          If (LEqual (Local0, 0x08))\n          {\n            Return (0x00)\n          }\n          If (LEqual (Local0, 0x0D))\n          {\n            Return (0x00)\n          }\n          Return (0x01)\n        }\n\n        Device (LNKA)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x01)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRA))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB01, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB01, 0x01, CIRA)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRA, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRA)\n            }\n            Else\n            {\n              Store (0x00, CIRA)\n            }\n            Return (CB01)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRA)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRA)\n            FindSetRightBit (SIRA, Local0)\n            Store (Decrement (Local0), PIRA)\n          }\n        }\n\n        Device (LNKB)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x02)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRB))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB02, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB02, 0x01, CIRB)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRB, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRB)\n            }\n            Else\n            {\n              Store (0x00, CIRB)\n            }\n            Return (CB02)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRB)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRB)\n            FindSetRightBit (SIRB, Local0)\n            Store (Decrement (Local0), PIRB)\n          }\n        }\n\n        Device (LNKC)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x03)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRC))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB03, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB03, 0x01, CIRC)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRC, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRC)\n            }\n            Else\n            {\n              Store (0x00, CIRC)\n            }\n            Return (CB03)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRC)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRC)\n            FindSetRightBit (SIRC, Local0)\n            Store (Decrement (Local0), PIRC)\n          }\n        }\n\n        Device (LNKD)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x04)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRD))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB04, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB04, 0x01, CIRD)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRD, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRD)\n            }\n            Else\n            {\n              Store (0x00, CIRD)\n            }\n            Return (CB04)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRD)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRD)\n            FindSetRightBit (SIRD, Local0)\n            Store (Decrement (Local0), PIRD)\n          }\n        }\n\n        Device (LNKE)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x05)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRE))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB05, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB05, 0x01, CIRE)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRE, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRE)\n            }\n            Else\n            {\n              Store (0x00, CIRE)\n            }\n            Return (CB05)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRE)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRE)\n            FindSetRightBit (SIRE, Local0)\n            Store (Decrement (Local0), PIRE)\n          }\n        }\n\n        Device (LNKF)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x06)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRF))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB06, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB06, 0x01, CIRF)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRF, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRF)\n            }\n            Else\n            {\n              Store (0x00, CIRF)\n            }\n            Return (CB06)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRF)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRF)\n            FindSetRightBit (SIRF, Local0)\n            Store (Decrement (Local0), PIRF)\n          }\n        }\n\n        Device (LNKG)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x07)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRG))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB07, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB07, 0x01, CIRG)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRG, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRG)\n            }\n            Else\n            {\n              Store (0x00, CIRG)\n            }\n            Return (CB07)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRG)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRG)\n            FindSetRightBit (SIRG, Local0)\n            Store (Decrement (Local0), PIRG)\n          }\n        }\n\n        Device (LNKH)\n        {\n          Name (_HID, EisaId (\"PNP0C0F\"))\n          Name (_UID, 0x08)\n          Method (_STA, 0, NotSerialized)\n          {\n            If (PIRV (PIRH))\n            {\n               Return (0x0B)\n            }\n            Else\n            {\n               Return (0x09)\n            }\n          }\n          Name (_PRS, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {3,4,5,6,7,9,10,11,12,14,15}\n          })\n          Name (CB08, ResourceTemplate ()\n          {\n            IRQ (Level, ActiveLow, Shared, )\n              {}\n          })\n          CreateWordField (CB08, 0x01, CIRH)\n          Method (_CRS, 0, NotSerialized)\n          {\n            And (PIRH, 0x8F, Local0)\n            If (PIRV (Local0))\n            {\n              ShiftLeft (0x01, Local0, CIRH)\n            }\n            Else\n            {\n              Store (0x00, CIRH)\n            }\n            Return (CB08)\n          }\n          Method (_DIS, 0, NotSerialized)\n          {\n            Store (0x80, PIRH)\n          }\n          Method (_SRS, 1, NotSerialized)\n          {\n            CreateWordField (Arg0, 0x01, SIRH)\n            FindSetRightBit (SIRH, Local0)\n            Store (Decrement (Local0), PIRH)\n          }\n        }\n\n        Device (SIO)\n        {\n          Name (_HID, EisaId (\"PNP0C02\"))\n          Name (_CRS, ResourceTemplate ()\n          {\n            IO (Decode16,\n              0x0060,             // Range Minimum\n              0x0060,             // Range Maximum\n              0x01,               // Alignment\n              0x01,               // Length\n              )\n            IO (Decode16,\n              0x0064,             // Range Minimum\n              0x0064,             // Range Maximum\n              0x01,               // Alignment\n              0x01,               // Length\n              )\n            IO (Decode16,\n              0x0220,             // Range Minimum\n              0x0220,             // Range Maximum\n              0x01,               // Alignment\n              0x04,               // Length\n              )\n            IO (Decode16,\n              0x0224,             // Range Minimum\n              0x0224,             // Range Maximum\n              0x01,               // Alignment\n              0x04,               // Length\n              )\n            Memory32Fixed (ReadWrite,\n              0xE0000000,         // Address Base\n              0x10000000,         // Address Length\n              )\n            IO (Decode16,\n              0x04D0,             // Range Minimum\n              0x04D0,             // Range Maximum\n              0x01,               // Alignment\n              0x02,               // Length\n              )\n            IO (Decode16,\n              0x0061,             // Range Minimum\n              0x0061,             // Range Maximum\n              0x01,               // Alignment\n              0x01,               // Length\n              )\n            IO (Decode16,\n              0x0400,             // Range Minimum\n              0x0400,             // Range Maximum\n              0x01,               // Alignment\n              0x08,               // Length\n              )\n            IO (Decode16,\n              0x00B2,             // Range Minimum\n              0x00B2,             // Range Maximum\n              0x01,               // Alignment\n              0x01,               // Length\n              )\n            IO (Decode16,\n              0x0084,             // Range Minimum\n              0x0084,             // Range Maximum\n              0x01,               // Alignment\n              0x01,               // Length\n              )\n            IO (Decode16,\n              0x0072,             // Range Minimum\n              0x0072,             // Range Maximum\n              0x01,               // Alignment\n              0x06,               // Length\n              )\n          })\n        }\n\n        Device (COM1)\n        {\n          Name (_HID, EisaId (\"PNP0501\"))\n          Name (_UID, 1)\n          Name (_CRS, ResourceTemplate ()\n          {\n            IO (Decode16,\n              0x03F8,             // Range Minimum\n              0x03F8,             // Range Maximum\n              0x01,               // Alignment\n              0x08,               // Length\n              )\n            IRQNoFlags ()\n              {4}\n          })\n        }\n\n        Device (COM2)\n        {\n          Name (_HID, EisaId (\"PNP0501\"))\n          Name (_UID, 2)\n          Name (_CRS, ResourceTemplate ()\n          {\n            IO (Decode16,\n              0x02F8,             // Range Minimum\n              0x02F8,             // Range Maximum\n              0x01,               // Alignment\n              0x08,               // Length\n              )\n            IRQNoFlags ()\n              {3}\n          })\n        }\n\n        Device (RTC)\n        {\n          Name (_HID, EisaId (\"PNP0B00\"))\n          Name (_CRS, ResourceTemplate ()\n          {\n            IO (Decode16,\n              0x0070,             // Range Minimum\n              0x0070,             // Range Maximum\n              0x01,               // Alignment\n              0x02,               // Length\n              )\n            IRQNoFlags ()\n              {8}\n          })\n        }\n\n        Device (PIC)\n        {\n          Name (_HID, EisaId (\"PNP0000\"))\n          Name (_CRS, ResourceTemplate ()\n          {\n            IO (Decode16,\n              0x0020,             // Range Minimum\n              0x0020,             // Range Maximum\n              0x01,               // Alignment\n              0x02,               // Length\n              )\n            IO (Decode16,\n              0x00A0,             // Range Minimum\n              0x00A0,             // Range Maximum\n              0x01,               // Alignment\n              0x02,               // Length\n              )\n            IRQNoFlags ()\n              {2}\n          })\n        }\n\n        Device (TIMR)\n        {\n          Name (_HID, EisaId (\"PNP0100\"))\n          Name (_CRS, ResourceTemplate ()\n          {\n            IO (Decode16,\n              0x0040,             // Range Minimum\n              0x0040,             // Range Maximum\n              0x01,               // Alignment\n              0x04,               // Length\n              )\n            IRQNoFlags ()\n              {0}\n          })\n        }\n      }\n    }\n  }\n\n  Scope (_SB.PC00)\n  {\n    Device (HPET)\n    {\n      Name (_HID, EISAID(\"PNP0103\"))\n      Name (_UID, 0)\n      Name (_CRS, ResourceTemplate ()\n      {\n        Memory32Fixed (ReadWrite,\n          0xFED00000,         // Address Base\n          0x00000400,         // Address Length\n          )\n      })\n    }\n  }\n}\n"
  },
  {
    "path": "src/firmware/fbsd.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*-\n * Copyright (c) 2011 Google, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <dirent.h>\n#include <dlfcn.h>\n#include <errno.h>\n#include <err.h>\n#include <fcntl.h>\n#include <getopt.h>\n#include <libgen.h>\n#include <limits.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <setjmp.h>\n#include <string.h>\n#include <sysexits.h>\n#include <termios.h>\n#include <unistd.h>\n#include <assert.h>\n#include <sys/ioctl.h>\n#include <sys/stat.h>\n#include <sys/disk.h>\n#include <sys/queue.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/segments.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/firmware/fbsd.h>\n\n#define\tI386_TSS_SIZE 104\n\n#define\tDESC_PRESENT 0x00000080\n#define\tDESC_DEF32 0x00004000\n#define\tDESC_GRAN 0x00008000\n#define\tDESC_UNUSABLE 0x00010000\n\n#define\tGUEST_CODE_SEL 1\n#define\tGUEST_DATA_SEL 2\n#define\tGUEST_TSS_SEL 3\n#define\tGUEST_GDTR_LIMIT64 (3 * 8 - 1)\n\n#define\tBSP 0\n#define\tNDISKS 32\n\nstatic struct {\n\tchar *userboot;\n\tchar *bootvolume;\n\tchar *kernelenv;\n\tchar *cons;\n} config;\n\nstatic char *host_base;\nstatic struct termios term, oldterm;\nstatic int disk_fd[NDISKS];\nstatic int ndisks;\nstatic int consin_fd, consout_fd;\nstatic jmp_buf exec_done;\n\nstatic uint64_t vcpu_gdt_base, vcpu_cr3, vcpu_rsp, vcpu_rip;\n\ntypedef void (*func_t)(struct loader_callbacks *, void *, int, int);\n\nstatic void cb_exit(void);\n\nstatic struct segment_descriptor i386_gdt[] = {\n\t{ .sd_lolimit = 0, .sd_type = 0, /* NULL */\n\t  .sd_p = 0, .sd_hilimit = 0, .sd_def32 = 0, .sd_gran = 0},\n\n\t{ .sd_lolimit = 0xffff, .sd_type = SDT_MEMER, /* CODE */\n\t  .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 }, \n\n\t{ .sd_lolimit = 0xffff, .sd_type = SDT_MEMRW, /* DATA */\n\t  .sd_p = 1, .sd_hilimit = 0xf, .sd_def32 = 1, .sd_gran = 1 },\n\n\t{ .sd_lolimit = I386_TSS_SIZE - 1, /* TSS */\n\t  .sd_type = SDT_SYS386TSS, .sd_p = 1 }\n};\n\nstatic int\nfbsd_set_regs_i386(uint32_t eip, uint32_t gdt_base, uint32_t esp)\n{\n\tuint64_t cr0, rflags, desc_base;\n\tuint32_t desc_access, desc_limit, tss_base;\n\tuint16_t gsel;\n\tstruct segment_descriptor *gdt;\n\tint error;\n\n\tcr0 = CR0_PE | CR0_NE;\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CR0, cr0)) != 0)\n\t\tgoto done;\n\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CR4, 0)) != 0)\n\t\tgoto done;\n\n\t/*\n\t * Forcing EFER to 0 causes bhyve to clear the \"IA-32e guest\n\t * mode\" entry control.\n\t */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_EFER, 0)))\n\t\tgoto done;\n\n\tgdt = xh_vm_map_gpa(gdt_base, 0x1000);\n\tif (gdt == NULL)\n\t\treturn (EFAULT);\n\tmemcpy(gdt, i386_gdt, sizeof(i386_gdt));\n\tdesc_base = gdt_base;\n\tdesc_limit = sizeof(i386_gdt) - 1;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_GDTR, desc_base, desc_limit, 0);\n\tif (error != 0)\n\t\tgoto done;\n\n\t/* Place the TSS one page above the GDT. */\n\ttss_base = gdt_base + 0x1000;\n\tgdt[3].sd_lobase = tss_base;\t\n\n\trflags = 0x2;\n\terror = xh_vm_set_register(BSP, VM_REG_GUEST_RFLAGS, rflags);\n\tif (error)\n\t\tgoto done;\n\n\tdesc_base = 0;\n\tdesc_limit = 0xffffffff;\n\tdesc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMERA;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_CS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tdesc_access = DESC_GRAN | DESC_DEF32 | DESC_PRESENT | SDT_MEMRWA;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_DS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_ES, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_FS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_GS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_SS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\tdesc_base = tss_base;\n\tdesc_limit = I386_TSS_SIZE - 1;\n\tdesc_access = DESC_PRESENT | SDT_SYS386BSY;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_TR, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\t\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_LDTR, 0, 0, DESC_UNUSABLE);\n\tif (error)\n\t\tgoto done;\n\n\tgsel = GSEL(GUEST_CODE_SEL, SEL_KPL);\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tgsel = GSEL(GUEST_DATA_SEL, SEL_KPL);\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_DS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_ES, gsel)) != 0)\n\t\tgoto done;\n\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_FS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_GS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_SS, gsel)) != 0)\n\t\tgoto done;\n\n\tgsel = GSEL(GUEST_TSS_SEL, SEL_KPL);\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_TR, gsel)) != 0)\n\t\tgoto done;\n\n\t/* LDTR is pointing to the null selector */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_LDTR, 0)) != 0)\n\t\tgoto done;\n\n\t/* entry point */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_RIP, eip)) != 0)\n\t\tgoto done;\n\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_RSP, esp)) != 0)\n\t\tgoto done;\n\n\terror = 0;\ndone:\n\treturn (error);\n}\n\nstatic int\nfbsd_set_regs(uint64_t rip, uint64_t cr3, uint64_t gdt_base, uint64_t rsp)\n{\n\tint error;\n\tuint64_t cr0, cr4, efer, rflags, desc_base;\n\tuint32_t desc_access, desc_limit;\n\tuint16_t gsel;\n\n\tcr0 = CR0_PE | CR0_PG | CR0_NE;\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CR0, cr0)) != 0)\n\t\tgoto done;\n\n\tcr4 = CR4_PAE;\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CR4, cr4)) != 0)\n\t\tgoto done;\n\n\tefer = EFER_LME | EFER_LMA;\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_EFER, efer)))\n\t\tgoto done;\n\n\trflags = 0x2;\n\terror = xh_vm_set_register(BSP, VM_REG_GUEST_RFLAGS, rflags);\n\tif (error)\n\t\tgoto done;\n\n\tdesc_base = 0;\n\tdesc_limit = 0;\n\tdesc_access = 0x0000209B;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_CS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\tdesc_access = 0x00000093;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_DS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_ES, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_FS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_GS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_SS, desc_base, desc_limit,\n\t\tdesc_access);\n\n\tif (error)\n\t\tgoto done;\n\n\t/*\n\t * XXX TR is pointing to null selector even though we set the\n\t * TSS segment to be usable with a base address and limit of 0.\n\t */\n\tdesc_access = 0x0000008b;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_TR, 0, 0, desc_access);\n\tif (error)\n\t\tgoto done;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_LDTR, 0, 0, DESC_UNUSABLE);\n\tif (error)\n\t\tgoto done;\n\n\tgsel = GSEL(GUEST_CODE_SEL, SEL_KPL);\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tgsel = GSEL(GUEST_DATA_SEL, SEL_KPL);\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_DS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_ES, gsel)) != 0)\n\t\tgoto done;\n\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_FS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_GS, gsel)) != 0)\n\t\tgoto done;\n\t\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_SS, gsel)) != 0)\n\t\tgoto done;\n\n\t/* XXX TR is pointing to the null selector */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_TR, 0)) != 0)\n\t\tgoto done;\n\n\t/* LDTR is pointing to the null selector */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_LDTR, 0)) != 0)\n\t\tgoto done;\n\n\t/* entry point */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_RIP, rip)) != 0)\n\t\tgoto done;\n\n\t/* page table base */\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_CR3, cr3)) != 0)\n\t\tgoto done;\n\n\tdesc_base = gdt_base;\n\tdesc_limit = GUEST_GDTR_LIMIT64;\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_GDTR, desc_base, desc_limit, 0);\n\tif (error != 0)\n\t\tgoto done;\n\n\tif ((error = xh_vm_set_register(BSP, VM_REG_GUEST_RSP, rsp)) != 0)\n\t\tgoto done;\n\n\terror = 0;\ndone:\n\treturn (error);\n}\n\n/*\n * Console i/o callbacks\n */\n\nstatic void\ncb_putc(UNUSED void *arg, int ch)\n{\n\tchar c = (char) ch;\n\n\t(void) write(consout_fd, &c, 1);\n}\n\nstatic int\ncb_getc(UNUSED void *arg)\n{\n\tchar c;\n\n\tif (read(consin_fd, &c, 1) == 1)\n\t\treturn (c);\n\treturn (-1);\n}\n\nstatic int\ncb_poll(UNUSED void *arg)\n{\n\tint n;\n\n\tif (ioctl(consin_fd, FIONREAD, &n) >= 0)\n\t\treturn (n > 0);\n\treturn (0);\n}\n\n/*\n * Host filesystem i/o callbacks\n */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct cb_file {\n\tint cf_isdir;\n\tsize_t cf_size;\n\tstruct stat cf_stat;\n\tunion {\n\t\tint fd;\n\t\tDIR *dir;\n\t} cf_u;\n};\n#pragma clang diagnostic pop\n\nstatic int\ncb_open(UNUSED void *arg, const char *filename, void **hp)\n{\n\tstruct stat st;\n\tstruct cb_file *cf;\n\tchar path[PATH_MAX];\n\n\tif (!host_base)\n\t\treturn (ENOENT);\n\n\tstrlcpy(path, host_base, PATH_MAX);\n\tif (path[strlen(path) - 1] == '/')\n\t\tpath[strlen(path) - 1] = 0;\n\tstrlcat(path, filename, PATH_MAX);\n\tcf = malloc(sizeof(struct cb_file));\n\tif (stat(path, &cf->cf_stat) < 0) {\n\t\tfree(cf);\n\t\treturn (errno);\n\t}\n\n\tcf->cf_size = (size_t) st.st_size;\n\tif (S_ISDIR(cf->cf_stat.st_mode)) {\n\t\tcf->cf_isdir = 1;\n\t\tcf->cf_u.dir = opendir(path);\n\t\tif (!cf->cf_u.dir)\n\t\t\tgoto out;\n\t\t*hp = cf;\n\t\treturn (0);\n\t}\n\tif (S_ISREG(cf->cf_stat.st_mode)) {\n\t\tcf->cf_isdir = 0;\n\t\tcf->cf_u.fd = open(path, O_RDONLY);\n\t\tif (cf->cf_u.fd < 0)\n\t\t\tgoto out;\n\t\t*hp = cf;\n\t\treturn (0);\n\t}\n\nout:\n\tfree(cf);\n\treturn (EINVAL);\n}\n\n// static int\n// cb_close(UNUSED void *arg, void *h)\n// {\n// \tstruct cb_file *cf = h;\n//\n// \tif (cf->cf_isdir)\n// \t\tclosedir(cf->cf_u.dir);\n// \telse\n// \t\tclose(cf->cf_u.fd);\n// \tfree(cf);\n//\n// \treturn (0);\n// }\n\n// static int\n// cb_isdir(UNUSED void *arg, void *h)\n// {\n// \tstruct cb_file *cf = h;\n//\n// \treturn (cf->cf_isdir);\n// }\n\n// static int\n// cb_read(UNUSED void *arg, void *h, void *buf, size_t size, size_t *resid)\n// {\n// \tstruct cb_file *cf = h;\n// \tssize_t sz;\n//\n// \tif (cf->cf_isdir)\n// \t\treturn (EINVAL);\n// \tsz = read(cf->cf_u.fd, buf, size);\n// \tif (sz < 0)\n// \t\treturn (EINVAL);\n// \t*resid = size - ((size_t) sz);\n// \treturn (0);\n// }\n\n//static int\n//cb_readdir(UNUSED void *arg, void *h, uint32_t *fileno_return,\n//\tuint8_t *type_return, size_t *namelen_return, char *name)\n//{\n//\tstruct cb_file *cf = h;\n//\tstruct dirent *dp;\n//\n//\tif (!cf->cf_isdir)\n//\t\treturn (EINVAL);\n//\n//\tdp = readdir(cf->cf_u.dir);\n//\tif (!dp)\n//\t\treturn (ENOENT);\n//\n//\t/*\n//\t * Note: d_namlen is in the range 0..255 and therefore less\n//\t * than PATH_MAX so we don't need to test before copying.\n//\t */\n//\t*fileno_return = dp->d_fileno;\n//\t*type_return = dp->d_type;\n//\t*namelen_return = dp->d_namlen;\n//\tmemcpy(name, dp->d_name, dp->d_namlen);\n//\tname[dp->d_namlen] = 0;\n//\n//\treturn (0);\n//}\n\n// static int\n// cb_seek(UNUSED void *arg, void *h, uint64_t offset, int whence)\n// {\n// \tstruct cb_file *cf = h;\n//\n// \tif (cf->cf_isdir)\n// \t\treturn (EINVAL);\n// \tif (lseek(cf->cf_u.fd, ((off_t) offset), whence) < 0)\n// \t\treturn (errno);\n// \treturn (0);\n// }\n\n// static int\n// cb_stat(UNUSED void *arg, void *h, int *mode, int *uid, int *gid,\n// \tuint64_t *size)\n// {\n// \tstruct cb_file *cf = h;\n//\n// \t*mode = cf->cf_stat.st_mode;\n// \t*uid = (int) cf->cf_stat.st_uid;\n// \t*gid = (int) cf->cf_stat.st_gid;\n// \t*size = (uint64_t) cf->cf_stat.st_size;\n// \treturn (0);\n// }\n\n/*\n * Disk image i/o callbacks\n */\n\nstatic int\ncb_diskread(UNUSED void *arg, int unit, uint64_t from, void *to, size_t size,\n\tsize_t *resid)\n{\n\tssize_t n;\n\n\tif (unit < 0 || unit >= ndisks )\n\t\treturn (EIO);\n\tn = pread(disk_fd[unit], to, size, ((off_t) from));\n\tif (n < 0)\n\t\treturn (errno);\n\t*resid = size - ((size_t) n);\n\treturn (0);\n}\n\n#define DIOCGSECTORSIZE _IOR('d', 128, u_int)\n#define DIOCGMEDIASIZE  _IOR('d', 129, off_t)\n\nstatic int\ncb_diskioctl(UNUSED void *arg, int unit, u_long cmd, void *data)\n{\n\tstruct stat sb;\n\n\tif (unit < 0 || unit >= ndisks)\n\t\treturn (EBADF);\n\n\tswitch (cmd) {\n\tcase DIOCGSECTORSIZE:\n\t\t*(u_int *)data = 512;\n\t\tbreak;\n\tcase DIOCGMEDIASIZE:\n\t\tif (fstat(disk_fd[unit], &sb) == 0)\n\t\t\t*(off_t *)data = sb.st_size;\n\t\telse\n\t\t\treturn (ENOTTY);\n\t\tbreak;\n\tdefault:\n\t\tabort();\n\t\treturn (ENOTTY);\n\t}\n\n\treturn (0);\n}\n\n/*\n * Guest virtual machine i/o callbacks\n */\nstatic int\ncb_copyin(UNUSED void *arg, const void *from, uint64_t to, size_t size)\n{\n\tchar *ptr;\n\n\tto &= 0x7fffffff;\n\n\tptr = xh_vm_map_gpa(to, size);\n\tif (ptr == NULL)\n\t\treturn (EFAULT);\n\n\tmemcpy(ptr, from, size);\n\treturn (0);\n}\n\nstatic int\ncb_copyout(UNUSED void *arg, uint64_t from, void *to, size_t size)\n{\n\tchar *ptr;\n\n\tfrom &= 0x7fffffff;\n\n\tptr = xh_vm_map_gpa(from, size);\n\tif (ptr == NULL)\n\t\treturn (EFAULT);\n\n\tmemcpy(to, ptr, size);\n\treturn (0);\n}\n\nstatic void\ncb_setreg(UNUSED void *arg, int r, uint64_t v)\n{\n\tint error;\n\tenum vm_reg_name vmreg;\n\t\n\tvmreg = VM_REG_LAST;\n\n\tswitch (r) {\n\tcase 4:\n\t\tvmreg = VM_REG_GUEST_RSP;\n\t\tvcpu_rsp = v;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (vmreg == VM_REG_LAST) {\n\t\tabort();\n\t}\n\n\terror = xh_vm_set_register(BSP, (int) vmreg, v);\n\tif (error) {\n\t\tperror(\"xh_vm_set_register\");\n\t\tcb_exit();\n\t}\n}\n\nstatic void\ncb_setmsr(UNUSED void *arg, u_int r, uint64_t v)\n{\n\tint error;\n\tenum vm_reg_name vmreg;\n\t\n\tvmreg = VM_REG_LAST;\n\n\tswitch (r) {\n\tcase MSR_EFER:\n\t\tvmreg = VM_REG_GUEST_EFER;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (vmreg == VM_REG_LAST) {\n\t\tabort();\n\t}\n\n\terror = xh_vm_set_register(BSP, (int) vmreg, v);\n\tif (error) {\n\t\tperror(\"xh_vm_set_msr\");\n\t\tcb_exit();\n\t}\n}\n\nstatic void\ncb_setcr(UNUSED void *arg, int r, uint64_t v)\n{\n\tint error;\n\tenum vm_reg_name vmreg;\n\t\n\tvmreg = VM_REG_LAST;\n\n\tswitch (r) {\n\tcase 0:\n\t\tvmreg = VM_REG_GUEST_CR0;\n\t\tbreak;\n\tcase 3:\n\t\tvmreg = VM_REG_GUEST_CR3;\n\t\tvcpu_cr3 = v;\n\t\tbreak;\n\tcase 4:\n\t\tvmreg = VM_REG_GUEST_CR4;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (vmreg == VM_REG_LAST) {\n\t\tfprintf(stderr, \"test_setcr(%d): not implemented\\n\", r);\n\t\tcb_exit();\n\t}\n\n\terror = xh_vm_set_register(BSP, (int) vmreg, v);\n\tif (error) {\n\t\tperror(\"vm_set_cr\");\n\t\tcb_exit();\n\t}\n}\n\nstatic void\ncb_setgdt(UNUSED void *arg, uint64_t base, size_t size)\n{\n\tint error;\n\n\terror = xh_vm_set_desc(BSP, VM_REG_GUEST_GDTR, base,\n\t\t((uint32_t) (size - 1)), 0);\n\n\tif (error != 0) {\n\t\tperror(\"vm_set_desc(gdt)\");\n\t\tcb_exit();\n\t}\n\n\tvcpu_gdt_base = base;\n}\n\n__attribute__ ((noreturn)) static void\ncb_exec(UNUSED void *arg, uint64_t rip)\n{\n\tint error;\n\n\tif (vcpu_cr3 == 0) {\n\t\terror = fbsd_set_regs_i386(((uint32_t) rip), ((uint32_t) vcpu_gdt_base),\n\t\t\t((uint32_t) vcpu_rsp));\n\t} else {\n\t\terror = fbsd_set_regs(rip, vcpu_cr3, vcpu_gdt_base, vcpu_rsp);\n\t}\n\n\tif (error) {\n\t\tperror(\"fbsd_set_regs\");\n\t\tcb_exit();\n\t}\n\n\tvcpu_rip = rip;\n\n\tlongjmp(exec_done, 1);\n}\n\n/*\n * Misc\n */\n\nstatic void\ncb_delay(UNUSED void *arg, int usec)\n{\n\tusleep((useconds_t) usec);\n}\n\n__attribute__ ((noreturn)) static void\ncb_exit(void)\n{\n\ttcsetattr(consout_fd, TCSAFLUSH, &oldterm);\n\tfprintf(stderr, \"fbsd: error\\n\");\n\texit(-1);\n}\n\nstatic void\ncb_getmem(UNUSED void *arg, uint64_t *ret_lowmem, uint64_t *ret_highmem)\n{\n\t*ret_lowmem = xh_vm_get_lowmem_size();\n\t*ret_highmem = xh_vm_get_highmem_size();\n}\n\nstruct env {\n\tconst char *str; /* name=value */\n\tSLIST_ENTRY(env) next;\n};\n\nstatic SLIST_HEAD(envhead, env) envhead;\n\nstatic void\naddenv(const char *str)\n{\n\tstruct env *env;\n\n\tenv = malloc(sizeof(struct env));\n\tenv->str = str;\n\tSLIST_INSERT_HEAD(&envhead, env, next);\n}\n\nstatic const char *\ncb_getenv(UNUSED void *arg, int num)\n{\n\tint i;\n\tstruct env *env;\n\n\ti = 0;\n\tSLIST_FOREACH(env, &envhead, next) {\n\t\tif (i == num)\n\t\t\treturn (env->str);\n\t\ti++;\n\t}\n\n\treturn (NULL);\n}\n\nstatic struct loader_callbacks cb = {\n\t.getc = cb_getc,\n\t.putc = cb_putc,\n\t.poll = cb_poll,\n\n\t// .open = cb_open,\n\t// .close = cb_close,\n\t// .isdir = cb_isdir,\n\t// .read = cb_read,\n\t// .readdir = cb_readdir,\n\t// .seek = cb_seek,\n\t// .stat = cb_stat,\n\n\t.open = cb_open,\n\t.close = NULL,\n\t.isdir = NULL,\n\t.read = NULL,\n\t.readdir = NULL,\n\t.seek = NULL,\n\t.stat = NULL,\n\n\t.diskread = cb_diskread,\n\t.diskioctl = cb_diskioctl,\n\n\t.copyin = cb_copyin,\n\t.copyout = cb_copyout,\n\t.setreg = cb_setreg,\n\t.setmsr = cb_setmsr,\n\t.setcr = cb_setcr,\n\t.setgdt = cb_setgdt,\n\t.exec = cb_exec,\n\n\t.delay = cb_delay,\n\t.exit = cb_exit,\n\t.getmem = cb_getmem,\n\n\t.getenv = cb_getenv,\n};\n\nstatic int\naltcons_open(char *path)\n{\n\tstruct stat sb;\n\tint err;\n\tint fd;\n\n\t/*\n\t * Allow stdio to be passed in so that the same string\n\t * can be used for the bhyveload console and bhyve com-port\n\t * parameters\n\t */\n\tif (!strcmp(path, \"stdio\"))\n\t\treturn (0);\n\n\terr = stat(path, &sb);\n\tif (err == 0) {\n\t\tif (!S_ISCHR(sb.st_mode))\n\t\t\terr = ENOTSUP;\n\t\telse {\n\t\t\tfd = open(path, O_RDWR | O_NONBLOCK);\n\t\t\tif (fd < 0)\n\t\t\t\terr = errno;\n\t\t\telse\n\t\t\t\tconsin_fd = consout_fd = fd;\n\t\t}\n\t}\n\n\treturn (err);\n}\n\nstatic int\ndisk_open(char *path)\n{\n\tint err, fd;\n\n\tif (ndisks >= NDISKS)\n\t\treturn (ERANGE);\n\n\terr = 0;\n\tfd = open(path, O_RDONLY);\n\n\tif (fd > 0) {\n\t\tdisk_fd[ndisks] = fd;\n\t\tndisks++;\n\t} else \n\t\terr = errno;\n\n\treturn (err);\n}\n\nvoid\nfbsd_init(char *userboot_path, char *bootvolume_path, char *kernelenv,\n\tchar *cons)\n{\n\tconfig.userboot = userboot_path;\n\tconfig.bootvolume = bootvolume_path;\n\tconfig.kernelenv = kernelenv;\n\tconfig.cons = cons;\n}\n\nuint64_t\nfbsd_load(void)\n{\n\tvoid *h;\n\tint i;\n\tfunc_t func;\n\n\thost_base = NULL;\n\tconsin_fd = STDIN_FILENO;\n\tconsout_fd = STDOUT_FILENO;\n\n\tif (config.cons) {\n\t\taltcons_open(config.cons);\n\t}\n\n\tif (config.bootvolume) {\n\t\tdisk_open(config.bootvolume);\n\t} else {\n\t\tfprintf(stderr, \"fbsd: no boot volume\\n\");\n\t\texit(-1);\n\t}\n\n\tif (config.kernelenv) {\n\t\taddenv(config.kernelenv);\n\t}\n\n\t//host_base = optarg h\n\n\ttcgetattr(consout_fd, &term);\n\toldterm = term;\n\tcfmakeraw(&term);\n\tterm.c_cflag |= CLOCAL;\n\t\n\ttcsetattr(consout_fd, TCSAFLUSH, &term);\n\n\th = dlopen(config.userboot, RTLD_LOCAL);\n\tif (!h) {\n\t\tfprintf(stderr, \"%s\\n\", dlerror());\n\t\texit(-1);\n\t}\n\n\tfunc = (func_t) dlsym(h, \"loader_main\");\n\tif (!func) {\n\t\tfprintf(stderr, \"%s\\n\", dlerror());\n\t\texit(-1);\n\t}\n\n\taddenv(\"smbios.bios.vendor=BHYVE\");\n\taddenv(\"boot_serial=1\");\n\n\tif (!setjmp(exec_done)) {\n\t\tfunc(&cb, NULL, USERBOOT_VERSION_3, ndisks);\n\t}\n\n\tfor (i = 0; i < ndisks; i++) {\n\t\tclose(disk_fd[i]);\n\t}\n\n\tif (config.cons) {\n\t\tassert(consin_fd == consout_fd);\n\t\tclose(consin_fd);\n\t}\n\n\treturn vcpu_rip;\n}\n"
  },
  {
    "path": "src/firmware/kexec.c",
    "content": "/*-\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY ???, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/firmware/kexec.h>\n\n#ifndef ALIGNUP\n#define ALIGNUP(x, a) (((x - 1) & ~(a - 1)) + a)\n#endif\n\n#ifndef ALIGNDOWN\n#define ALIGNDOWN(x, a) (-(a) & (x))\n#endif\n\n#define BASE_GDT 0x2000ull\n#define BASE_ZEROPAGE 0x3000ull\n#define BASE_CMDLINE 0x4000ull\n#define BASE_KERNEL 0x100000ull\n#define HDRS 0x53726448 /* SrdH */\n\nstatic struct {\n\tuintptr_t base;\n\tsize_t size;\n} lowmem, kernel, ramdisk;\n\nstatic struct {\n\tchar *kernel;\n\tchar *initrd;\n\tchar *cmdline;\n} config;\n\nstatic int\nkexec_load_kernel(char *path, char *cmdline) {\n\tuint64_t kernel_offset, kernel_size, kernel_init_size, kernel_start, mem_k;\n\tsize_t sz, cmdline_len;\n\tvolatile struct zero_page *zp;\n\tFILE *f;\n\n\tif ((lowmem.size < (BASE_ZEROPAGE + sizeof(struct zero_page))) ||\n\t\t((BASE_ZEROPAGE + sizeof(struct zero_page)) > BASE_CMDLINE))\n\t{\n\t\treturn -1;\n\t}\n\n\tzp = ((struct zero_page *) (lowmem.base + ((off_t) BASE_ZEROPAGE)));\n\n\tmemset(((void *) ((uintptr_t) zp)), 0, sizeof(struct zero_page));\n\n\tif (!(f = fopen(path, \"r\"))) {\n\t\treturn -1;\n\t}\n\t\n\tfseek(f, 0L, SEEK_END);\n\tsz = (size_t) ftell(f);\n\t\n\tif (sz < (0x01f1 + sizeof(struct setup_header))) {\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\tfseek(f, 0x01f1, SEEK_SET);\n\n\tif (!fread(((void *) ((uintptr_t) &zp->setup_header)), 1,\n\t\tsizeof(zp->setup_header), f))\n\t{\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\tif ((zp->setup_header.setup_sects == 0) ||    /* way way too old */\n\t\t(zp->setup_header.boot_flag != 0xaa55) || /* no boot magic */\n\t\t(zp->setup_header.header != HDRS) ||      /* way too old */\n\t\t(zp->setup_header.version < 0x020a) ||    /* too old */\n\t\t(!(zp->setup_header.loadflags & 1)) ||    /* no bzImage */\n\t\t(sz < (((zp->setup_header.setup_sects + 1) * 512) +\n\t\t(zp->setup_header.syssize * 16))))        /* too small */\n\t{\n\t\t/* we can't boot this kernel */\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\tkernel_offset = ((zp->setup_header.setup_sects + 1) * 512);\n\tkernel_size = (sz - kernel_offset);\n\tkernel_init_size = ALIGNUP(zp->setup_header.init_size, 0x1000ull);\n\tkernel_start = (zp->setup_header.relocatable_kernel) ?\n\t\tALIGNUP(BASE_KERNEL, zp->setup_header.kernel_alignment) :\n\t\tzp->setup_header.pref_address;\n\n\tif ((kernel_start < BASE_KERNEL) ||\n\t\t (kernel_size > kernel_init_size) || /* XXX: always true? */\n\t\t ((kernel_start + kernel_init_size) > lowmem.size)) /* oom */\n\t{\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\t/* copy kernel */\n\tfseek(f, ((long) kernel_offset), SEEK_SET);\n\tif (!fread(((void *) (lowmem.base + kernel_start)), 1, kernel_size, f)) {\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\tfclose(f);\n\n\t/* copy cmdline */\n\tcmdline_len = strlen(cmdline);\n\tif (((cmdline_len + 1)> zp->setup_header.cmdline_size) ||\n\t\t((BASE_CMDLINE + (cmdline_len + 1)) > kernel_start))\n\t{\n\t\treturn -1;   \n\t}\n\n\tmemcpy(((void *) (lowmem.base + BASE_CMDLINE)), cmdline, cmdline_len);\n\tmemset(((void *) (lowmem.base + BASE_CMDLINE + cmdline_len)), '\\0', 1);\n\tzp->setup_header.cmd_line_ptr = ((uint32_t) BASE_CMDLINE);\n\tzp->ext_cmd_line_ptr = ((uint32_t) (BASE_CMDLINE >> 32));\n\n\tzp->setup_header.hardware_subarch = 0; /* PC */\n\tzp->setup_header.type_of_loader = 0xd; /* kexec */\n\n\tmem_k = (lowmem.size - 0x100000) >> 10; /* assume lowmem base is at 0 */\n\tzp->alt_mem_k = (mem_k > 0xffffffff) ? 0xffffffff : ((uint32_t) mem_k);\n\n\tzp->e820_map[0].addr = 0x0000000000000000;\n\tzp->e820_map[0].size = 0x000000000009fc00;\n\tzp->e820_map[0].type = 1;\n\tzp->e820_map[1].addr = 0x0000000000100000;\n\tzp->e820_map[1].size = (lowmem.size - 0x0000000000100000);\n\tzp->e820_map[1].type = 1;\n\tif (xh_vm_get_highmem_size() == 0) {\n\t\tzp->e820_entries = 2;\n\t} else {\n\t\tzp->e820_map[2].addr = 0x0000000100000000;\n\t\tzp->e820_map[2].size = xh_vm_get_highmem_size();\n\t\tzp->e820_map[2].type = 1;\n\t\tzp->e820_entries = 3;\n\t}\n\n\tkernel.base = kernel_start;\n\tkernel.size = kernel_init_size;\n\n\treturn 0;\n}\n\nstatic int\nkexec_load_ramdisk(char *path) {\n\tuint64_t ramdisk_start;\n\tuint32_t initrd_max;\n\tvolatile struct zero_page *zp;\n\tsize_t sz;\n\tFILE *f;\n\n\tzp = ((struct zero_page *) (lowmem.base + BASE_ZEROPAGE));\n\n\tif (!(f = fopen(path, \"r\"))) {;\n\t\treturn -1;\n\t}\n\t\n\tfseek(f, 0L, SEEK_END);\n\tsz = (size_t) ftell(f);\n\tfseek(f, 0, SEEK_SET);\n\n\t/* highest address for loading the initrd */\n\tif (zp->setup_header.version >= 0x203) {\n\t\tinitrd_max = zp->setup_header.initrd_addr_max;\n\t} else {\n\t\tinitrd_max = 0x37ffffff; /* Hardcoded value for older kernels */\n\t}\n\n\tif (initrd_max >= lowmem.size) {\n\t\tinitrd_max = ((uint32_t) lowmem.size - 1);\n\t}\n\n\tramdisk_start = ALIGNDOWN(initrd_max - sz, 0x1000ull);\n\n\tif ((ramdisk_start + sz) > lowmem.size) {\n\t\t/* not enough lowmem */\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\t/* copy ramdisk */\n\tif (!fread(((void *) (lowmem.base + ramdisk_start)), 1, sz, f)) {\n\t\tfclose(f);\n\t\treturn -1;\n\t}\n\n\tfclose(f);\n\n\tzp->setup_header.ramdisk_image = ((uint32_t) ramdisk_start);\n\tzp->ext_ramdisk_image = ((uint32_t) (ramdisk_start >> 32));\n\tzp->setup_header.ramdisk_size = ((uint32_t) sz);\n\tzp->ext_ramdisk_size = ((uint32_t) (sz >> 32));\n\n\tramdisk.base = ramdisk_start;\n\tramdisk.size = sz;\n\n\treturn 0;\n}\n\nvoid\nkexec_init(char *kernel_path, char *initrd_path, char *cmdline) {\n\tconfig.kernel = kernel_path;\n\tconfig.initrd = initrd_path;\n\tconfig.cmdline = cmdline;\n}\n\nuint64_t\nkexec(void)\n{\n\tuint64_t *gdt_entry;\n\tvoid *gpa_map;\n\n\tgpa_map = xh_vm_map_gpa(0, xh_vm_get_lowmem_size());\n\tlowmem.base = (uintptr_t) gpa_map;\n\tlowmem.size = xh_vm_get_lowmem_size();\n\n\tif (kexec_load_kernel(config.kernel,\n\t\tconfig.cmdline ? config.cmdline : \"auto\"))\n\t{\n\t\tfprintf(stderr, \"kexec: failed to load kernel %s\\n\", config.kernel);\n\t\tabort();\n\t}\n\n\tif (config.initrd && kexec_load_ramdisk(config.initrd)) {\n\t\tfprintf(stderr, \"kexec: failed to load initrd %s\\n\", config.initrd);\n\t\tabort();\n\t}\n\n\tgdt_entry = ((uint64_t *) (lowmem.base + BASE_GDT));\n\tgdt_entry[0] = 0x0000000000000000; /* null */\n\tgdt_entry[1] = 0x0000000000000000; /* null */\n\tgdt_entry[2] = 0x00cf9a000000ffff; /* code */\n\tgdt_entry[3] = 0x00cf92000000ffff; /* data */\n\n\txh_vcpu_reset(0);\n\n\txh_vm_set_desc(0, VM_REG_GUEST_GDTR, BASE_GDT, 0x1f, 0);\n\txh_vm_set_desc(0, VM_REG_GUEST_CS, 0, 0xffffffff, 0xc09b);\n\txh_vm_set_desc(0, VM_REG_GUEST_DS, 0, 0xffffffff, 0xc093);\n\txh_vm_set_desc(0, VM_REG_GUEST_ES, 0, 0xffffffff, 0xc093);\n\txh_vm_set_desc(0, VM_REG_GUEST_SS, 0, 0xffffffff, 0xc093);\n\txh_vm_set_register(0, VM_REG_GUEST_CS, 0x10);\n\txh_vm_set_register(0, VM_REG_GUEST_DS, 0x18);\n\txh_vm_set_register(0, VM_REG_GUEST_ES, 0x18);\n\txh_vm_set_register(0, VM_REG_GUEST_SS, 0x18);\n\txh_vm_set_register(0, VM_REG_GUEST_CR0, 0x21); /* enable protected mode */\n\txh_vm_set_register(0, VM_REG_GUEST_RBP, 0);\n\txh_vm_set_register(0, VM_REG_GUEST_RDI, 0);\n\txh_vm_set_register(0, VM_REG_GUEST_RBX, 0);\n\txh_vm_set_register(0, VM_REG_GUEST_RFLAGS, 0x2);\n\txh_vm_set_register(0, VM_REG_GUEST_RSI, BASE_ZEROPAGE);\n\txh_vm_set_register(0, VM_REG_GUEST_RIP, kernel.base);\n\n\treturn kernel.base;\n}\n"
  },
  {
    "path": "src/inout.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdio.h>\n#include <string.h>\n#include <errno.h>\n#include <assert.h>\n#include <sys/uio.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/linker_set.h>\n#include <xhyve/support/psl.h>\n#include <xhyve/support/segments.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/inout.h>\n\nSET_DECLARE(inout_port_set, struct inout_port);\n\n#define\tMAX_IOPORTS\t(1 << 16)\n\n#define\tVERIFY_IOPORT(port, size) \\\n\tassert((port) >= 0 && (size) > 0 && ((port) + (size)) <= MAX_IOPORTS)\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstatic struct {\n\tconst char *name;\n\tint flags;\n\tinout_func_t handler;\n\tvoid *arg;\n} inout_handlers[MAX_IOPORTS];\n#pragma clang diagnostic pop\n\nstatic int\ndefault_inout(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tif (in) {\n\t\tswitch (bytes) {\n\t\tcase 4:\n\t\t\t*eax = 0xffffffff;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\t*eax = 0xffff;\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\t*eax = 0xff;\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\treturn (0);\n}\n\nstatic void \nregister_default_iohandler(int start, int size)\n{\n\tstruct inout_port iop;\n\t\n\tVERIFY_IOPORT(start, size);\n\n\tbzero(&iop, sizeof(iop));\n\tiop.name = \"default\";\n\tiop.port = start;\n\tiop.size = size;\n\tiop.flags = (int) (IOPORT_F_INOUT | IOPORT_F_DEFAULT);\n\tiop.handler = default_inout;\n\n\tregister_inout(&iop);\n}\n\nstatic int\nupdate_register(int vcpuid, enum vm_reg_name reg,\n\tuint64_t val, int size)\n{\n\tint error;\n\tuint64_t origval;\n\n\tswitch (size) {\n\tcase 1:\n\tcase 2:\n\t\terror = xh_vm_get_register(vcpuid, (int) reg, &origval);\n\t\tif (error)\n\t\t\treturn (error);\n\t\tval &= vie_size2mask(size);\n\t\tval |= origval & ~vie_size2mask(size);\n\t\tbreak;\n\tcase 4:\n\t\tval &= 0xffffffffUL;\n\t\tbreak;\n\tcase 8:\n\t\tbreak;\n\tdefault:\n\t\treturn (EINVAL);\n\t}\n\n\treturn xh_vm_set_register(vcpuid, (int) reg, val);\n}\n\nint\nemulate_inout(int vcpu, struct vm_exit *vmexit, int strict)\n{\n\tint addrsize, bytes, flags, in, port, prot, rep;\n\tuint32_t eax, val;\n\tinout_func_t handler;\n\tvoid *arg;\n\tint error, fault, retval;\n\tenum vm_reg_name idxreg;\n\tuint64_t gla, index, iterations, count;\n\tstruct vm_inout_str *vis;\n\tstruct iovec iov[2];\n\n\tbytes = vmexit->u.inout.bytes;\n\tin = vmexit->u.inout.in;\n\tport = vmexit->u.inout.port;\n\n\tassert(port < MAX_IOPORTS);\n\tassert(bytes == 1 || bytes == 2 || bytes == 4);\n\n\thandler = inout_handlers[port].handler;\n\n\tif (strict && handler == default_inout)\n\t\treturn (-1);\n\n\tflags = inout_handlers[port].flags;\n\targ = inout_handlers[port].arg;\n\n\tif (in) {\n\t\tif (!(flags & IOPORT_F_IN))\n\t\t\treturn (-1);\n\t} else {\n\t\tif (!(flags & IOPORT_F_OUT))\n\t\t\treturn (-1);\n\t}\n\n\tretval = 0;\n\tif (vmexit->u.inout.string) {\n\t\tvis = &vmexit->u.inout_str;\n\t\trep = vis->inout.rep;\n\t\taddrsize = vis->addrsize;\n\t\tprot = in ? XHYVE_PROT_WRITE : XHYVE_PROT_READ;\n\t\tassert(addrsize == 2 || addrsize == 4 || addrsize == 8);\n\n\t\t/* Index register */\n\t\tidxreg = in ? VM_REG_GUEST_RDI : VM_REG_GUEST_RSI;\n\t\tindex = vis->index & vie_size2mask(addrsize);\n\n\t\t/* Count register */\n\t\tcount = vis->count & vie_size2mask(addrsize);\n\n\t\t/* Limit number of back-to-back in/out emulations to 16 */\n\t\titerations = min(count, 16);\n\t\twhile (iterations > 0) {\n\t\t\tassert(retval == 0);\n\t\t\tif (vie_calculate_gla(vis->paging.cpu_mode,\n\t\t\t    vis->seg_name, &vis->seg_desc, index, bytes,\n\t\t\t    addrsize, prot, &gla)) {\n\t\t\t\tvm_inject_gp(vcpu);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\terror = xh_vm_copy_setup(vcpu, &vis->paging, gla,\n\t\t\t    ((size_t) bytes), prot, iov, nitems(iov), &fault);\n\t\t\tif (error) {\n\t\t\t\tretval = -1;  /* Unrecoverable error */\n\t\t\t\tbreak;\n\t\t\t} else if (fault) {\n\t\t\t\tretval = 0;  /* Resume guest to handle fault */\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (vie_alignment_check(vis->paging.cpl, bytes,\n\t\t\t    vis->cr0, vis->rflags, gla)) {\n\t\t\t\tvm_inject_ac(vcpu, 0);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tval = 0;\n\t\t\tif (!in)\n\t\t\t\txh_vm_copyin(iov, &val, ((size_t) bytes));\n\n\t\t\tretval = handler(vcpu, in, port, bytes, &val, arg);\n\t\t\tif (retval != 0)\n\t\t\t\tbreak;\n\n\t\t\tif (in)\n\t\t\t\txh_vm_copyout(&val, iov, ((size_t) bytes));\n\n\t\t\t/* Update index */\n\t\t\tif (vis->rflags & PSL_D)\n\t\t\t\tindex -= ((uint64_t) bytes);\n\t\t\telse\n\t\t\t\tindex += ((uint64_t) bytes);\n\n\t\t\tcount--;\n\t\t\titerations--;\n\t\t}\n\n\t\t/* Update index register */\n\t\terror = update_register(vcpu, idxreg, index, addrsize);\n\t\tassert(error == 0);\n\n\t\t/*\n\t\t * Update count register only if the instruction had a repeat\n\t\t * prefix.\n\t\t */\n\t\tif (rep) {\n\t\t\terror = update_register(vcpu, VM_REG_GUEST_RCX, count, addrsize);\n\t\t\tassert(error == 0);\n\t\t}\n\n\t\t/* Restart the instruction if more iterations remain */\n\t\tif (retval == 0 && count != 0) {\n\t\t\terror = xh_vm_restart_instruction(vcpu);\n\t\t\tassert(error == 0);\n\t\t}\n\t} else {\n\t\teax = vmexit->u.inout.eax;\n\t\tval = eax & vie_size2mask(bytes);\n\t\tretval = handler(vcpu, in, port, bytes, &val, arg);\n\t\tif (retval == 0 && in) {\n\t\t\teax &= ~vie_size2mask(bytes);\n\t\t\teax |= val & vie_size2mask(bytes);\n\t\t\terror = xh_vm_set_register(vcpu, VM_REG_GUEST_RAX, eax);\n\t\t\tassert(error == 0);\n\t\t}\n\t}\n\treturn (retval);\n}\n\nvoid\ninit_inout(void)\n{\n\tstruct inout_port **iopp, *iop;\n\n\t/*\n\t * Set up the default handler for all ports\n\t */\n\tregister_default_iohandler(0, MAX_IOPORTS);\n\n\t/*\n\t * Overwrite with specified handlers\n\t */\n\tSET_FOREACH(iopp, inout_port_set) {\n\t\tiop = *iopp;\n\t\tassert(iop->port < MAX_IOPORTS);\n\t\tinout_handlers[iop->port].name = iop->name;\n\t\tinout_handlers[iop->port].flags = iop->flags;\n\t\tinout_handlers[iop->port].handler = iop->handler;\n\t\tinout_handlers[iop->port].arg = NULL;\n\t}\n}\n\nint\nregister_inout(struct inout_port *iop)\n{\n\tint i;\n\n\tVERIFY_IOPORT(iop->port, iop->size);\n\n\t/*\n\t * Verify that the new registration is not overwriting an already\n\t * allocated i/o range.\n\t */\n\tif ((((unsigned) iop->flags) & IOPORT_F_DEFAULT) == 0) {\n\t\tfor (i = iop->port; i < iop->port + iop->size; i++) {\n\t\t\tif ((((unsigned) inout_handlers[i].flags) & IOPORT_F_DEFAULT) == 0)\n\t\t\t\treturn (-1);\n\t\t}\n\t}\n\n\tfor (i = iop->port; i < iop->port + iop->size; i++) {\n\t\tinout_handlers[i].name = iop->name;\n\t\tinout_handlers[i].flags = iop->flags;\n\t\tinout_handlers[i].handler = iop->handler;\n\t\tinout_handlers[i].arg = iop->arg;\n\t}\n\n\treturn (0);\n}\n\nint\nunregister_inout(struct inout_port *iop)\n{\n\n\tVERIFY_IOPORT(iop->port, iop->size);\n\tassert(inout_handlers[iop->port].name == iop->name);\n\n\tregister_default_iohandler(iop->port, iop->size);\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/ioapic.c",
    "content": "/*-\n * Copyright (c) 2014 Hudson River Trading LLC\n * Written by: John H. Baldwin <jhb@FreeBSD.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/ioapic.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/pci_lpc.h>\n\n/*\n * Assign PCI INTx interrupts to I/O APIC pins in a round-robin\n * fashion.  Note that we have no idea what the HPET is using, but the\n * HPET is also programmable whereas this is intended for hardwired\n * PCI interrupts.\n *\n * This assumes a single I/O APIC where pins >= 16 are permitted for\n * PCI devices.\n */\nstatic int pci_pins;\n\nvoid\nioapic_init(void)\n{\n\n\tif (xh_vm_ioapic_pincount(&pci_pins) < 0) {\n\t\tpci_pins = 0;\n\t\treturn;\n\t}\n\n\t/* Ignore the first 16 pins. */\n\tif (pci_pins <= 16) {\n\t\tpci_pins = 0;\n\t\treturn;\n\t}\n\tpci_pins -= 16;\n}\n\nint\nioapic_pci_alloc_irq(struct pci_devinst *pi)\n{\n\tstatic int last_pin;\n\n\tif (pci_pins == 0)\n\t\treturn (-1);\n    if (lpc_bootrom()) {\n        /* For external bootrom use fixed mapping. */\n        return (16 + (4 + pi->pi_slot + pi->pi_lintr.pin) % 8);\n    }\n\treturn (16 + (last_pin++ % pci_pins));\n}\n"
  },
  {
    "path": "src/mem.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * Memory ranges are represented with an RB tree. On insertion, the range\n * is checked for overlaps. On lookup, the key has the same base and limit\n * so it can be searched within the range.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <pthread.h>\n#include <errno.h>\n#include <assert.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/tree.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/mem.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct mmio_rb_range {\n\tRB_ENTRY(mmio_rb_range) mr_link; /* RB tree links */\n\tstruct mem_range mr_param;\n\tuint64_t mr_base;\n\tuint64_t mr_end;\n};\n#pragma clang diagnostic pop\n\nstruct mmio_rb_tree;\nRB_PROTOTYPE(mmio_rb_tree, mmio_rb_range, mr_link, mmio_rb_range_compare);\n\nstatic RB_HEAD(mmio_rb_tree, mmio_rb_range) mmio_rb_root, mmio_rb_fallback;\n\n/*\n * Per-vCPU cache. Since most accesses from a vCPU will be to\n * consecutive addresses in a range, it makes sense to cache the\n * result of a lookup.\n */\nstatic struct mmio_rb_range\t*mmio_hint[VM_MAXCPU];\n\nstatic pthread_rwlock_t mmio_rwlock;\n\nstatic int\nmmio_rb_range_compare(struct mmio_rb_range *a, struct mmio_rb_range *b)\n{\n\tif (a->mr_end < b->mr_base)\n\t\treturn (-1);\n\telse if (a->mr_base > b->mr_end)\n\t\treturn (1);\n\treturn (0);\n}\n\nstatic int\nmmio_rb_lookup(struct mmio_rb_tree *rbt, uint64_t addr,\n    struct mmio_rb_range **entry)\n{\n\tstruct mmio_rb_range find, *res;\n\n\tfind.mr_base = find.mr_end = addr;\n\n\tres = RB_FIND(mmio_rb_tree, rbt, &find);\n\n\tif (res != NULL) {\n\t\t*entry = res;\n\t\treturn (0);\n\t}\n\t\n\treturn (ENOENT);\n}\n\nstatic int\nmmio_rb_add(struct mmio_rb_tree *rbt, struct mmio_rb_range *new)\n{\n\tstruct mmio_rb_range *overlap;\n\n\toverlap = RB_INSERT(mmio_rb_tree, rbt, new);\n\n\tif (overlap != NULL) {\n#ifdef RB_DEBUG\n\t\tprintf(\"overlap detected: new %lx:%lx, tree %lx:%lx\\n\",\n\t\t       new->mr_base, new->mr_end,\n\t\t       overlap->mr_base, overlap->mr_end);\n#endif\n\n\t\treturn (EEXIST);\n\t}\n\n\treturn (0);\n}\n\n#if 0\nstatic void\nmmio_rb_dump(struct mmio_rb_tree *rbt)\n{\n\tstruct mmio_rb_range *np;\n\n\tpthread_rwlock_rdlock(&mmio_rwlock);\n\tRB_FOREACH(np, mmio_rb_tree, rbt) {\n\t\tprintf(\" %lx:%lx, %s\\n\", np->mr_base, np->mr_end,\n\t\t       np->mr_param.name);\n\t}\n\tpthread_rwlock_unlock(&mmio_rwlock);\n}\n#endif\n\nRB_GENERATE(mmio_rb_tree, mmio_rb_range, mr_link, mmio_rb_range_compare)\n\nstatic int\nmem_read(UNUSED void *unused, int vcpu, uint64_t gpa, uint64_t *rval, int size,\n\tvoid *arg)\n{\n\tint error;\n\tstruct mem_range *mr = arg;\n\n\terror = (*mr->handler)(vcpu, MEM_F_READ, gpa, size, rval, mr->arg1,\n\t\tmr->arg2);\n\treturn (error);\n}\n\nstatic int\nmem_write(UNUSED void* unused, int vcpu, uint64_t gpa, uint64_t wval, int size,\n\tvoid *arg)\n{\n\tint error;\n\tstruct mem_range *mr = arg;\n\n\terror = (*mr->handler)(vcpu, MEM_F_WRITE, gpa, size, &wval, mr->arg1,\n\t\tmr->arg2);\n\treturn (error);\n}\n\nint\nemulate_mem(int vcpu, uint64_t paddr, struct vie *vie,\n\tstruct vm_guest_paging *paging)\n\n{\n\tstruct mmio_rb_range *entry;\n\tint err, immutable;\n\n\tpthread_rwlock_rdlock(&mmio_rwlock);\n\t/*\n\t * First check the per-vCPU cache\n\t */\n\tif (mmio_hint[vcpu] &&\n\t    paddr >= mmio_hint[vcpu]->mr_base &&\n\t    paddr <= mmio_hint[vcpu]->mr_end) {\n\t\tentry = mmio_hint[vcpu];\n\t} else\n\t\tentry = NULL;\n\n\tif (entry == NULL) {\n\t\tif (mmio_rb_lookup(&mmio_rb_root, paddr, &entry) == 0) {\n\t\t\t/* Update the per-vCPU cache */\n\t\t\tmmio_hint[vcpu] = entry;\t\t\t\n\t\t} else if (mmio_rb_lookup(&mmio_rb_fallback, paddr, &entry)) {\n\t\t\tpthread_rwlock_unlock(&mmio_rwlock);\n\t\t\treturn (ESRCH);\n\t\t}\n\t}\n\n\tassert(entry != NULL);\n\n\t/*\n\t * An 'immutable' memory range is guaranteed to be never removed\n\t * so there is no need to hold 'mmio_rwlock' while calling the\n\t * handler.\n\t *\n\t * XXX writes to the PCIR_COMMAND register can cause register_mem()\n\t * to be called. If the guest is using PCI extended config space\n\t * to modify the PCIR_COMMAND register then register_mem() can\n\t * deadlock on 'mmio_rwlock'. However by registering the extended\n\t * config space window as 'immutable' the deadlock can be avoided.\n\t */\n\timmutable = (entry->mr_param.flags & MEM_F_IMMUTABLE);\n\tif (immutable)\n\t\tpthread_rwlock_unlock(&mmio_rwlock);\n\n\terr = xh_vm_emulate_instruction(vcpu, paddr, vie, paging, mem_read,\n\t\tmem_write, &entry->mr_param);\n\n\tif (!immutable)\n\t\tpthread_rwlock_unlock(&mmio_rwlock);\n\n\treturn (err);\n}\n\nstatic int\nregister_mem_int(struct mmio_rb_tree *rbt, struct mem_range *memp)\n{\n\tstruct mmio_rb_range *entry, *mrp;\n\tint\t\terr;\n\n\terr = 0;\n\n\tmrp = malloc(sizeof(struct mmio_rb_range));\n\t\n\tif (mrp != NULL) {\n\t\tmrp->mr_param = *memp;\n\t\tmrp->mr_base = memp->base;\n\t\tmrp->mr_end = memp->base + memp->size - 1;\n\t\tpthread_rwlock_wrlock(&mmio_rwlock);\n\t\tif (mmio_rb_lookup(rbt, memp->base, &entry) != 0)\n\t\t\terr = mmio_rb_add(rbt, mrp);\n\t\tpthread_rwlock_unlock(&mmio_rwlock);\n\t\tif (err)\n\t\t\tfree(mrp);\n\t} else\n\t\terr = ENOMEM;\n\n\treturn (err);\n}\n\nint\nregister_mem(struct mem_range *memp)\n{\n\n\treturn (register_mem_int(&mmio_rb_root, memp));\n}\n\nint\nregister_mem_fallback(struct mem_range *memp)\n{\n\n\treturn (register_mem_int(&mmio_rb_fallback, memp));\n}\n\nint \nunregister_mem(struct mem_range *memp)\n{\n\tstruct mem_range *mr;\n\tstruct mmio_rb_range *entry = NULL;\n\tint err, i;\n\t\n\tpthread_rwlock_wrlock(&mmio_rwlock);\n\terr = mmio_rb_lookup(&mmio_rb_root, memp->base, &entry);\n\tif (err == 0) {\n\t\tmr = &entry->mr_param;\n\t\tassert(mr->name == memp->name);\n\t\tassert(mr->base == memp->base && mr->size == memp->size); \n\t\tassert((mr->flags & MEM_F_IMMUTABLE) == 0);\n\t\tRB_REMOVE(mmio_rb_tree, &mmio_rb_root, entry);\n\n\t\t/* flush Per-vCPU cache */\t\n\t\tfor (i=0; i < VM_MAXCPU; i++) {\n\t\t\tif (mmio_hint[i] == entry)\n\t\t\t\tmmio_hint[i] = NULL;\n\t\t}\n\t}\n\tpthread_rwlock_unlock(&mmio_rwlock);\n\n\tif (entry)\n\t\tfree(entry);\n\t\n\treturn (err);\n}\n\nvoid\ninit_mem(void)\n{\n\n\tRB_INIT(&mmio_rb_root);\n\tRB_INIT(&mmio_rb_fallback);\n\tpthread_rwlock_init(&mmio_rwlock, NULL);\n}\n"
  },
  {
    "path": "src/mevent.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * Micro event library for FreeBSD, designed for a single i/o thread \n * using kqueue, and having events be persistent by default.\n */\n\n#include <assert.h>\n#include <errno.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <pthread.h>\n#include <sys/types.h>\n#include <sys/event.h>\n#include <sys/time.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/mevent.h>\n\n#define\tMEVENT_MAX\t64\n\n#define\tMEV_ADD\t\t1\n#define\tMEV_ENABLE\t2\n#define\tMEV_DISABLE\t3\n#define\tMEV_DEL_PENDING\t4\n\nextern char *vmname;\n\nstatic pthread_t mevent_tid;\nstatic int mevent_timid = 43;\nstatic int mevent_pipefd[2];\nstatic pthread_mutex_t mevent_lmutex = PTHREAD_MUTEX_INITIALIZER;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct mevent {\n\tvoid (*me_func)(int, enum ev_type, void *);\n#define me_msecs me_fd\n\tint me_fd;\n\tint me_timid;\n\tenum ev_type me_type;\n\tvoid *me_param;\n\tint me_cq;\n\tint me_state;\n\tint me_closefd;\n\tLIST_ENTRY(mevent) me_list;\n};\n#pragma clang diagnostic pop\n\nstatic LIST_HEAD(listhead, mevent) global_head, change_head;\n\nstatic void\nmevent_qlock(void)\n{\n\tpthread_mutex_lock(&mevent_lmutex);\n}\n\nstatic void\nmevent_qunlock(void)\n{\n\tpthread_mutex_unlock(&mevent_lmutex);\n}\n\nstatic void\nmevent_pipe_read(int fd, UNUSED enum ev_type type, UNUSED void *param)\n{\n\tchar buf[MEVENT_MAX];\n\tssize_t status;\n\n\t/*\n\t * Drain the pipe read side. The fd is non-blocking so this is\n\t * safe to do.\n\t */\n\tdo {\n\t\tstatus = read(fd, buf, sizeof(buf));\n\t} while (status == MEVENT_MAX);\n}\n\nstatic void\nmevent_notify(void)\n{\n\tchar c;\n\t\n\t/*\n\t * If calling from outside the i/o thread, write a byte on the\n\t * pipe to force the i/o thread to exit the blocking kevent call.\n\t */\n\tif (mevent_pipefd[1] != 0 && pthread_self() != mevent_tid) {\n\t\twrite(mevent_pipefd[1], &c, 1);\n\t}\n}\n\nstatic int\nmevent_kq_filter(struct mevent *mevp)\n{\n\tint retval;\n\n\tretval = 0;\n\n\tif (mevp->me_type == EVF_READ)\n\t\tretval = EVFILT_READ;\n\n\tif (mevp->me_type == EVF_WRITE)\n\t\tretval = EVFILT_WRITE;\n\n\tif (mevp->me_type == EVF_TIMER)\n\t\tretval = EVFILT_TIMER;\n\n\tif (mevp->me_type == EVF_SIGNAL)\n\t\tretval = EVFILT_SIGNAL;\n\n\treturn (retval);\n}\n\nstatic int\nmevent_kq_flags(struct mevent *mevp)\n{\n\tint ret;\n\n\tswitch (mevp->me_state) {\n\tcase MEV_ADD:\n\t\tret = EV_ADD;\t\t/* implicitly enabled */\n\t\tbreak;\n\tcase MEV_ENABLE:\n\t\tret = EV_ENABLE;\n\t\tbreak;\n\tcase MEV_DISABLE:\n\t\tret = EV_DISABLE;\n\t\tbreak;\n\tcase MEV_DEL_PENDING:\n\t\tret = EV_DELETE;\n\t\tbreak;\n\tdefault:\n\t\tassert(0);\n\t\tbreak;\n\t}\n\n\treturn (ret);\n}\n\nstatic int\nmevent_kq_fflags(UNUSED struct mevent *mevp)\n{\n\t/* XXX nothing yet, perhaps EV_EOF for reads ? */\n\treturn (0);\n}\n\nstatic int\nmevent_build(UNUSED int mfd, struct kevent *kev)\n{\n\tstruct mevent *mevp, *tmpp;\n\tint i;\n\n\ti = 0;\n\n\tmevent_qlock();\n\n\tLIST_FOREACH_SAFE(mevp, &change_head, me_list, tmpp) {\n\t\tif (mevp->me_closefd) {\n\t\t\t/*\n\t\t\t * A close of the file descriptor will remove the\n\t\t\t * event\n\t\t\t */\n\t\t\tclose(mevp->me_fd);\n\t\t} else {\n\t\t\tif (mevp->me_type == EVF_TIMER) {\n\t\t\t\tkev[i].ident = (uintptr_t) mevp->me_timid;\n\t\t\t\tkev[i].data = mevp->me_msecs;\n\t\t\t} else {\n\t\t\t\tkev[i].ident = (uintptr_t) mevp->me_fd;\n\t\t\t\tkev[i].data = 0;\n\t\t\t}\n\t\t\tkev[i].filter = (int16_t) mevent_kq_filter(mevp);\n\t\t\tkev[i].flags = (uint16_t) mevent_kq_flags(mevp);\n\t\t\tkev[i].fflags = (uint32_t) mevent_kq_fflags(mevp);\n\t\t\tkev[i].udata = mevp;\n\t\t\ti++;\n\t\t}\n\n\t\tmevp->me_cq = 0;\n\t\tLIST_REMOVE(mevp, me_list);\n\n\t\tif (mevp->me_state == MEV_DEL_PENDING) {\n\t\t\tfree(mevp);\n\t\t} else {\n\t\t\tLIST_INSERT_HEAD(&global_head, mevp, me_list);\n\t\t}\n\n\t\tassert(i < MEVENT_MAX);\n\t}\n\n\tmevent_qunlock();\n\n\treturn (i);\n}\n\nstatic void\nmevent_handle(struct kevent *kev, int numev)\n{\n\tstruct mevent *mevp;\n\tint i;\n\n\tfor (i = 0; i < numev; i++) {\n\t\tmevp = kev[i].udata;\n\n\t\t/* XXX check for EV_ERROR ? */\n\n\t\t(*mevp->me_func)(mevp->me_fd, mevp->me_type, mevp->me_param);\n\t}\n}\n\nstruct mevent *\nmevent_add(int tfd, enum ev_type type,\n\t   void (*func)(int, enum ev_type, void *), void *param)\n{\n\tstruct mevent *lp, *mevp;\n\n\tif (tfd < 0 || func == NULL) {\n\t\treturn (NULL);\n\t}\n\n\tmevp = NULL;\n\n\tmevent_qlock();\n\n\t/*\n\t * Verify that the fd/type tuple is not present in any list\n\t */\n\tLIST_FOREACH(lp, &global_head, me_list) {\n\t\tif (type != EVF_TIMER && lp->me_fd == tfd &&\n\t\t    lp->me_type == type) {\n\t\t\tgoto exit;\n\t\t}\n\t}\n\n\tLIST_FOREACH(lp, &change_head, me_list) {\n\t\tif (type != EVF_TIMER && lp->me_fd == tfd &&\n\t\t    lp->me_type == type) {\n\t\t\tgoto exit;\n\t\t}\n\t}\n\n\t/*\n\t * Allocate an entry, populate it, and add it to the change list.\n\t */\n\tmevp = calloc(1, sizeof(struct mevent));\n\tif (mevp == NULL) {\n\t\tgoto exit;\n\t}\n\n\tif (type == EVF_TIMER) {\n\t\tmevp->me_msecs = tfd;\n\t\tmevp->me_timid = mevent_timid++;\n\t} else\n\t\tmevp->me_fd = tfd;\n\tmevp->me_type = type;\n\tmevp->me_func = func;\n\tmevp->me_param = param;\n\n\tLIST_INSERT_HEAD(&change_head, mevp, me_list);\n\tmevp->me_cq = 1;\n\tmevp->me_state = MEV_ADD;\n\tmevent_notify();\n\nexit:\n\tmevent_qunlock();\n\n\treturn (mevp);\n}\n\nstatic int\nmevent_update(struct mevent *evp, int newstate)\n{\n\t/*\n\t * It's not possible to enable/disable a deleted event\n\t */\n\tif (evp->me_state == MEV_DEL_PENDING)\n\t\treturn (EINVAL);\n\n\t/*\n\t * No update needed if state isn't changing\n\t */\n\tif (evp->me_state == newstate)\n\t\treturn (0);\n\t\n\tmevent_qlock();\n\n\tevp->me_state = newstate;\n\n\t/*\n\t * Place the entry onto the changed list if not already there.\n\t */\n\tif (evp->me_cq == 0) {\n\t\tevp->me_cq = 1;\n\t\tLIST_REMOVE(evp, me_list);\n\t\tLIST_INSERT_HEAD(&change_head, evp, me_list);\n\t\tmevent_notify();\n\t}\n\n\tmevent_qunlock();\n\n\treturn (0);\n}\n\nint\nmevent_enable(struct mevent *evp)\n{\n\n\treturn (mevent_update(evp, MEV_ENABLE));\n}\n\nint\nmevent_disable(struct mevent *evp)\n{\n\n\treturn (mevent_update(evp, MEV_DISABLE));\n}\n\nstatic int\nmevent_delete_event(struct mevent *evp, int closefd)\n{\n\tmevent_qlock();\n\n\t/*\n         * Place the entry onto the changed list if not already there, and\n\t * mark as to be deleted.\n         */\n        if (evp->me_cq == 0) {\n\t\tevp->me_cq = 1;\n\t\tLIST_REMOVE(evp, me_list);\n\t\tLIST_INSERT_HEAD(&change_head, evp, me_list);\n\t\tmevent_notify();\n        }\n\tevp->me_state = MEV_DEL_PENDING;\n\n\tif (closefd)\n\t\tevp->me_closefd = 1;\n\n\tmevent_qunlock();\n\n\treturn (0);\n}\n\nint\nmevent_delete(struct mevent *evp)\n{\n\n\treturn (mevent_delete_event(evp, 0));\n}\n\nint\nmevent_delete_close(struct mevent *evp)\n{\n\n\treturn (mevent_delete_event(evp, 1));\n}\n\nstatic void\nmevent_set_name(void)\n{\n}\n\n__attribute__ ((noreturn)) void\nmevent_dispatch(void)\n{\n\tstruct kevent changelist[MEVENT_MAX];\n\tstruct kevent eventlist[MEVENT_MAX];\n\tstruct mevent *pipev;\n\tint mfd;\n\tint numev;\n\tint ret;\n\n\tmevent_tid = pthread_self();\n\tmevent_set_name();\n\n\tmfd = kqueue();\n\tassert(mfd > 0);\n\n\t/*\n\t * Open the pipe that will be used for other threads to force\n\t * the blocking kqueue call to exit by writing to it. Set the\n\t * descriptor to non-blocking.\n\t */\n\tret = pipe(mevent_pipefd);\n\tif (ret < 0) {\n\t\tperror(\"pipe\");\n\t\texit(0);\n\t}\n\n\t/*\n\t * Add internal event handler for the pipe write fd\n\t */\n\tpipev = mevent_add(mevent_pipefd[0], EVF_READ, mevent_pipe_read, NULL);\n\tassert(pipev != NULL);\n\n\tfor (;;) {\n\t\t/*\n\t\t * Build changelist if required.\n\t\t * XXX the changelist can be put into the blocking call\n\t\t * to eliminate the extra syscall. Currently better for\n\t\t * debug.\n\t\t */\n\t\tnumev = mevent_build(mfd, changelist);\n\t\tif (numev) {\n\t\t\tret = kevent(mfd, changelist, numev, NULL, 0, NULL);\n\t\t\tif (ret == -1) {\n\t\t\t\tperror(\"Error return from kevent change\");\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Block awaiting events\n\t\t */\n\t\tret = kevent(mfd, NULL, 0, eventlist, MEVENT_MAX, NULL);\n\t\tif (ret == -1 && errno != EINTR) {\n\t\t\tperror(\"Error return from kevent monitor\");\n\t\t}\n\t\t\n\t\t/*\n\t\t * Handle reported events\n\t\t */\n\t\tmevent_handle(eventlist, ret);\n\t}\t\t\t\n}\n"
  },
  {
    "path": "src/mevent_test.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n * Test program for the micro event library. Set up a simple TCP echo\n * service.\n *\n *  cc mevent_test.c mevent.c -lpthread\n */\n\n#include <stdint.h>\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <pthread.h>\n#include <unistd.h>\n\n#include <xhyve/mevent.h>\n\n#define TEST_PORT\t4321\n\nstatic pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;\nstatic pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER;\n\nstatic struct mevent *tevp;\n\nchar *vmname = \"test vm\";\n\n\n#define MEVENT_ECHO\n\n/* Number of timer events to capture */\n#define TEVSZ\t4096\nuint64_t tevbuf[TEVSZ];\n\nstatic __inline uint64_t rdtsc(void)\n{\n\tunsigned a, d;\n\t__asm__ __volatile__ (\"cpuid\");\n\t__asm__ __volatile__ (\"rdtsc\" : \"=a\" (a), \"=d\" (d));\n\n\treturn (((uint64_t) a) | (((uint64_t) d) << 32));\n}\n\nstatic void\ntimer_print(void)\n{\n\tuint64_t min, max, diff, sum, tsc_freq;\n\tsize_t len;\n\tint j;\n\n\tmin = UINT64_MAX;\n\tmax = 0;\n\tsum = 0;\n\n\tlen = sizeof(tsc_freq);\n\tsysctlbyname(\"machdep.tsc_freq\", &tsc_freq, &len, NULL, 0);\n\n\tfor (j = 1; j < TEVSZ; j++) {\n\t\t/* Convert a tsc diff into microseconds */\n\t\tdiff = (tevbuf[j] - tevbuf[j-1]) * 1000000 / tsc_freq;\n\t\tsum += diff;\n\t\tif (min > diff)\n\t\t\tmin = diff;\n\t\tif (max < diff)\n\t\t\tmax = diff;\n\t}\n\n\tprintf(\"timers done: usecs, min %llu, max %llu, mean %llu\\n\", min, max,\n\t    sum/(TEVSZ - 1));\n}\n\nstatic void\ntimer_callback(int fd, enum ev_type type, void *param)\n{\n\tstatic int i;\n\n\tif (i >= TEVSZ)\n\t\tabort();\n\n\ttevbuf[i++] = rdtsc();\n\n\tif (i == TEVSZ) {\n\t\tmevent_delete(tevp);\n\t\ttimer_print();\n\t}\n}\n\n\n#ifdef MEVENT_ECHO\nstruct esync {\n\tpthread_mutex_t\te_mt;\n\tpthread_cond_t\te_cond;       \n};\n\nstatic void\nechoer_callback(int fd, enum ev_type type, void *param)\n{\n\tstruct esync *sync = param;\n\n\tpthread_mutex_lock(&sync->e_mt);\n\tpthread_cond_signal(&sync->e_cond);\n\tpthread_mutex_unlock(&sync->e_mt);\n}\n\nstatic void *\nechoer(void *param)\n{\n\tstruct esync sync;\n\tstruct mevent *mev;\n\tchar buf[128];\n\tint fd = (int)(uintptr_t) param;\n\tint len;\n\n\tpthread_mutex_init(&sync.e_mt, NULL);\n\tpthread_cond_init(&sync.e_cond, NULL);\n\n\tpthread_mutex_lock(&sync.e_mt);\n\n\tmev = mevent_add(fd, EVF_READ, echoer_callback, &sync);\n\tif (mev == NULL) {\n\t\tprintf(\"Could not allocate echoer event\\n\");\n\t\texit(1);\n\t}\n\n\twhile (!pthread_cond_wait(&sync.e_cond, &sync.e_mt)) {\n\t\tlen = read(fd, buf, sizeof(buf));\n\t\tif (len > 0) {\n\t\t\twrite(fd, buf, len);\n\t\t\twrite(0, buf, len);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tmevent_delete_close(mev);\n\n\tpthread_mutex_unlock(&sync.e_mt);\n\tpthread_mutex_destroy(&sync.e_mt);\n\tpthread_cond_destroy(&sync.e_cond);\n\n\treturn (NULL);\n}\n\n#else\n\nstatic void *\nechoer(void *param)\n{\n\tchar buf[128];\n\tint fd = (int)(uintptr_t) param;\n\tint len;\n\n\twhile ((len = read(fd, buf, sizeof(buf))) > 0) {\n\t\twrite(1, buf, len);\n\t}\n\n\treturn (NULL);\n}\n#endif /* MEVENT_ECHO */\n\nstatic void\nacceptor_callback(int fd, enum ev_type type, void *param)\n{\n\tpthread_mutex_lock(&accept_mutex);\n\tpthread_cond_signal(&accept_condvar);\n\tpthread_mutex_unlock(&accept_mutex);\n}\n\nstatic void *\nacceptor(void *param)\n{\n\tstruct sockaddr_in sin;\n\tpthread_t tid;\n\tint news;\n\tint s;\n\tstatic int first;\n\n        if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {\n                perror(\"socket\");\n                exit(1);\n        }\n\n        sin.sin_len = sizeof(sin);\n        sin.sin_family = AF_INET;\n        sin.sin_addr.s_addr = htonl(INADDR_ANY);\n        sin.sin_port = htons(TEST_PORT);\n\n        if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {\n                perror(\"bind\");\n                exit(1);\n        }\n\n        if (listen(s, 1) < 0) {\n                perror(\"listen\");\n                exit(1);\n        }\n\n\t(void) mevent_add(s, EVF_READ, acceptor_callback, NULL);\n\n\tpthread_mutex_lock(&accept_mutex);\n\n\twhile (!pthread_cond_wait(&accept_condvar, &accept_mutex)) {\n\t\tnews = accept(s, NULL, NULL);\n\t\tif (news < 0) {\n\t\t\tperror(\"accept error\");\n\t\t} else {\n\t\t\tstatic int first = 1;\n\n\t\t\tif (first) {\n\t\t\t\t/*\n\t\t\t\t * Start a timer\n\t\t\t\t */\n\t\t\t\tfirst = 0;\n\t\t\t\ttevp = mevent_add(1, EVF_TIMER, timer_callback,\n\t\t\t\t\t\t  NULL);\n\t\t\t}\n\n\t\t\tprintf(\"incoming connection, spawning thread\\n\");\n\t\t\tpthread_create(&tid, NULL, echoer,\n\t\t\t\t       (void *)(uintptr_t)news);\n\t\t}\n\t}\n\n\treturn (NULL);\n}\n\nint\nmain(void)\n{\n\tpthread_t tid;\n\n\tpthread_create(&tid, NULL, acceptor, NULL);\n\n\tmevent_dispatch();\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/mptbl.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n// #include <x86/mptable.h>\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <sys/types.h>\n#include <sys/errno.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/mptable.h>\n#include <xhyve/acpi.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/mptbl.h>\n#include <xhyve/pci_emul.h>\n\n#define MPTABLE_BASE\t\t0xF0000\n\n/* floating pointer length + maximum length of configuration table */\n#define\tMPTABLE_MAX_LENGTH\t(65536 + 16)\n\n#define LAPIC_PADDR\t\t0xFEE00000\n#define LAPIC_VERSION \t\t16\n\n#define IOAPIC_PADDR\t\t0xFEC00000\n#define IOAPIC_VERSION\t\t0x11\n\n#define MP_SPECREV\t\t4\n#define MPFP_SIG\t\t\"_MP_\"\n\n/* Configuration header defines */\n#define MPCH_SIG\t\t\"PCMP\"\n#define MPCH_OEMID\t\t\"BHyVe   \"\n#define MPCH_OEMID_LEN          8\n#define MPCH_PRODID             \"Hypervisor  \"\n#define MPCH_PRODID_LEN         12\n\n/* Processor entry defines */\n#define MPEP_SIG_FAMILY\t\t6\t/* XXX bhyve should supply this */\n#define MPEP_SIG_MODEL\t\t26\n#define MPEP_SIG_STEPPING\t5\n#define MPEP_SIG\t\t\\\n\t((MPEP_SIG_FAMILY << 8) | \\\n\t (MPEP_SIG_MODEL << 4)\t| \\\n\t (MPEP_SIG_STEPPING))\n\n#define MPEP_FEATURES           (0xBFEBFBFF) /* XXX Intel i7 */\n\n/* Number of local intr entries */\n#define\tMPEII_NUM_LOCAL_IRQ\t2\n\n/* Bus entry defines */\n#define MPE_NUM_BUSES\t\t2\n#define MPE_BUSNAME_LEN\t\t6\n#define MPE_BUSNAME_ISA\t\t\"ISA   \"\n#define MPE_BUSNAME_PCI\t\t\"PCI   \"\n\nstatic void *oem_tbl_start;\nstatic int oem_tbl_size;\n\nstatic uint8_t\nmpt_compute_checksum(void *base, size_t len)\n{\n\tuint8_t\t*bytes;\n\tuint8_t\tsum;\n\n\tfor(bytes = base, sum = 0; len > 0; len--) {\n\t\tsum += *bytes++;\n\t}\n\n\treturn ((uint8_t) (256 - sum));\n}\n\nstatic void\nmpt_build_mpfp(mpfps_t mpfp, uint64_t gpa)\n{\n\tmemset(mpfp, 0, sizeof(*mpfp));\n\tmemcpy(mpfp->signature, MPFP_SIG, 4);\n\tmpfp->pap = (uint32_t) (gpa + sizeof(*mpfp));\n\tmpfp->length = 1;\n\tmpfp->spec_rev = MP_SPECREV;\n\tmpfp->checksum = mpt_compute_checksum(mpfp, sizeof(*mpfp));\n}\n\nstatic void\nmpt_build_mpch(mpcth_t mpch)\n{\n\n\tmemset(mpch, 0, sizeof(*mpch));\n\tmemcpy(mpch->signature, MPCH_SIG, 4);\n\tmpch->spec_rev = MP_SPECREV;\n\tmemcpy(mpch->oem_id, MPCH_OEMID, MPCH_OEMID_LEN);\n\tmemcpy(mpch->product_id, MPCH_PRODID, MPCH_PRODID_LEN);\n\tmpch->apic_address = LAPIC_PADDR;\n}\n\nstatic void\nmpt_build_proc_entries(proc_entry_ptr mpep, int ncpu)\n{\n\tint i;\n\n\tfor (i = 0; i < ncpu; i++) {\n\t\tmemset(mpep, 0, sizeof(*mpep));\n\t\tmpep->type = MPCT_ENTRY_PROCESSOR;\n\t\tmpep->apic_id = (uint8_t) i; // XXX\n\t\tmpep->apic_version = LAPIC_VERSION;\n\t\tmpep->cpu_flags = PROCENTRY_FLAG_EN;\n\t\tif (i == 0)\n\t\t\tmpep->cpu_flags |= PROCENTRY_FLAG_BP;\n\t\tmpep->cpu_signature = MPEP_SIG;\n\t\tmpep->feature_flags = MPEP_FEATURES;\n\t\tmpep++;\n\t}\n}\n\nstatic void\nmpt_build_localint_entries(int_entry_ptr mpie)\n{\n\n\t/* Hardcode LINT0 as ExtINT on all CPUs. */\n\tmemset(mpie, 0, sizeof(*mpie));\n\tmpie->type = MPCT_ENTRY_LOCAL_INT;\n\tmpie->int_type = INTENTRY_TYPE_EXTINT;\n\tmpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |\n\t    INTENTRY_FLAGS_TRIGGER_CONFORM;\n\tmpie->dst_apic_id = 0xff;\n\tmpie->dst_apic_int = 0;\n\tmpie++;\n\n\t/* Hardcode LINT1 as NMI on all CPUs. */\n\tmemset(mpie, 0, sizeof(*mpie));\n\tmpie->type = MPCT_ENTRY_LOCAL_INT;\n\tmpie->int_type = INTENTRY_TYPE_NMI;\n\tmpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |\n\t    INTENTRY_FLAGS_TRIGGER_CONFORM;\n\tmpie->dst_apic_id = 0xff;\n\tmpie->dst_apic_int = 1;\n}\n\nstatic void\nmpt_build_bus_entries(bus_entry_ptr mpeb)\n{\n\n\tmemset(mpeb, 0, sizeof(*mpeb));\n\tmpeb->type = MPCT_ENTRY_BUS;\n\tmpeb->bus_id = 0;\n\tmemcpy(mpeb->bus_type, MPE_BUSNAME_PCI, MPE_BUSNAME_LEN);\n\tmpeb++;\n\n\tmemset(mpeb, 0, sizeof(*mpeb));\n\tmpeb->type = MPCT_ENTRY_BUS;\n\tmpeb->bus_id = 1;\t\n\tmemcpy(mpeb->bus_type, MPE_BUSNAME_ISA, MPE_BUSNAME_LEN);\n}\n\nstatic void\nmpt_build_ioapic_entries(io_apic_entry_ptr mpei, int id)\n{\n\n\tmemset(mpei, 0, sizeof(*mpei));\n\tmpei->type = MPCT_ENTRY_IOAPIC;\n\tmpei->apic_id = (uint8_t) id;\n\tmpei->apic_version = IOAPIC_VERSION;\n\tmpei->apic_flags = IOAPICENTRY_FLAG_EN;\n\tmpei->apic_address = IOAPIC_PADDR;\n}\n\nstatic int\nmpt_count_ioint_entries(void)\n{\n\tint bus, count;\n\n\tcount = 0;\n\tfor (bus = 0; bus <= PCI_BUSMAX; bus++)\n\t\tcount += pci_count_lintr(bus);\n\n\t/*\n\t * Always include entries for the first 16 pins along with a entry\n\t * for each active PCI INTx pin.\n\t */\n\treturn (16 + count);\n}\n\nstatic void\nmpt_generate_pci_int(int bus, int slot, int pin, UNUSED int pirq_pin,\n\tint ioapic_irq, void *arg)\n{\n\tint_entry_ptr *mpiep, mpie;\n\n\tmpiep = arg;\n\tmpie = *mpiep;\n\tmemset(mpie, 0, sizeof(*mpie));\n\n\t/*\n\t * This is always after another I/O interrupt entry, so cheat\n\t * and fetch the I/O APIC ID from the prior entry.\n\t */\n\tmpie->type = MPCT_ENTRY_INT;\n\tmpie->int_type = INTENTRY_TYPE_INT;\n\tmpie->src_bus_id = (uint8_t) bus;\n\tmpie->src_bus_irq = (uint8_t) (slot << 2 | (pin - 1));\n\tmpie->dst_apic_id = mpie[-1].dst_apic_id;\n\tmpie->dst_apic_int = (uint8_t) ioapic_irq;\n\n\t*mpiep = mpie + 1;\n}\n\nstatic void\nmpt_build_ioint_entries(int_entry_ptr mpie, int id)\n{\n\tint pin, bus;\n\n\t/*\n\t * The following config is taken from kernel mptable.c\n\t * mptable_parse_default_config_ints(...), for now \n\t * just use the default config, tweek later if needed.\n\t */\n\n\t/* First, generate the first 16 pins. */\n\tfor (pin = 0; pin < 16; pin++) {\n\t\tmemset(mpie, 0, sizeof(*mpie));\n\t\tmpie->type = MPCT_ENTRY_INT;\n\t\tmpie->src_bus_id = 1;\n\t\tmpie->dst_apic_id = (uint8_t) id;\n\n\t\t/*\n\t\t * All default configs route IRQs from bus 0 to the first 16\n\t\t * pins of the first I/O APIC with an APIC ID of 2.\n\t\t */\n\t\tmpie->dst_apic_int = (uint8_t) pin;\n\t\tswitch (pin) {\n\t\tcase 0:\n\t\t\t/* Pin 0 is an ExtINT pin. */\n\t\t\tmpie->int_type = INTENTRY_TYPE_EXTINT;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\t/* IRQ 0 is routed to pin 2. */\n\t\t\tmpie->int_type = INTENTRY_TYPE_INT;\n\t\t\tmpie->src_bus_irq = 0;\n\t\t\tbreak;\n\t\tcase SCI_INT:\n\t\t\t/* ACPI SCI is level triggered and active-lo. */\n\t\t\tmpie->int_flags = INTENTRY_FLAGS_POLARITY_ACTIVELO |\n\t\t\t    INTENTRY_FLAGS_TRIGGER_LEVEL;\n\t\t\tmpie->int_type = INTENTRY_TYPE_INT;\n\t\t\tmpie->src_bus_irq = SCI_INT;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t/* All other pins are identity mapped. */\n\t\t\tmpie->int_type = INTENTRY_TYPE_INT;\n\t\t\tmpie->src_bus_irq = (uint8_t) pin;\n\t\t\tbreak;\n\t\t}\n\t\tmpie++;\n\t}\n\n\t/* Next, generate entries for any PCI INTx interrupts. */\n\tfor (bus = 0; bus <= PCI_BUSMAX; bus++)\n\t\tpci_walk_lintr(bus, mpt_generate_pci_int, &mpie); \n}\n\nvoid\nmptable_add_oemtbl(void *tbl, int tblsz)\n{\n\n\toem_tbl_start = tbl;\n\toem_tbl_size = tblsz;\n}\n\nint\nmptable_build(int ncpu)\n{\n\tmpcth_t\t\t\tmpch;\n\tbus_entry_ptr\t\tmpeb;\n\tio_apic_entry_ptr\tmpei;\n\tproc_entry_ptr\t\tmpep;\n\tmpfps_t\t\t\tmpfp;\n\tint_entry_ptr\t\tmpie;\n\tint\t\t\tioints, bus;\n\tchar \t\t\t*curraddr;\n\tchar \t\t\t*startaddr;\n\n\tstartaddr = paddr_guest2host(MPTABLE_BASE, MPTABLE_MAX_LENGTH);\n\tif (startaddr == NULL) {\n\t\tfprintf(stderr, \"mptable requires mapped mem\\n\");\n\t\treturn (ENOMEM);\n\t}\n\n\t/*\n\t * There is no way to advertise multiple PCI hierarchies via MPtable\n\t * so require that there is no PCI hierarchy with a non-zero bus\n\t * number.\n\t */\n\tfor (bus = 1; bus <= PCI_BUSMAX; bus++) {\n\t\tif (pci_bus_configured(bus)) {\n\t\t\tfprintf(stderr, \"MPtable is incompatible with \"\n\t\t\t    \"multiple PCI hierarchies.\\r\\n\");\n\t\t\tfprintf(stderr, \"MPtable generation can be disabled \"\n\t\t\t    \"by passing the -Y option to bhyve(8).\\r\\n\");\n\t\t\treturn (EINVAL);\n\t\t}\n\t}\n\n\tcurraddr = startaddr;\n\tmpfp = (mpfps_t)curraddr;\n\tmpt_build_mpfp(mpfp, MPTABLE_BASE);\n\tcurraddr += sizeof(*mpfp);\n\n\tmpch = (mpcth_t)curraddr;\n\tmpt_build_mpch(mpch);\n\tcurraddr += sizeof(*mpch);\n\n\tmpep = (proc_entry_ptr)curraddr;\n\tmpt_build_proc_entries(mpep, ncpu);\n\tcurraddr += sizeof(*mpep) * ((uint64_t) ncpu);\n\tmpch->entry_count += ncpu;\n\n\tmpeb = (bus_entry_ptr) curraddr;\n\tmpt_build_bus_entries(mpeb);\n\tcurraddr += sizeof(*mpeb) * MPE_NUM_BUSES;\n\tmpch->entry_count += MPE_NUM_BUSES;\n\n\tmpei = (io_apic_entry_ptr)curraddr;\n\tmpt_build_ioapic_entries(mpei, 0);\n\tcurraddr += sizeof(*mpei);\n\tmpch->entry_count++;\n\n\tmpie = (int_entry_ptr) curraddr;\n\tioints = mpt_count_ioint_entries();\n\tmpt_build_ioint_entries(mpie, 0);\n\tcurraddr += sizeof(*mpie) * ((uint64_t) ioints);\n\tmpch->entry_count += ioints;\n\n\tmpie = (int_entry_ptr)curraddr;\n\tmpt_build_localint_entries(mpie);\n\tcurraddr += sizeof(*mpie) * MPEII_NUM_LOCAL_IRQ;\n\tmpch->entry_count += MPEII_NUM_LOCAL_IRQ;\n\n\tif (oem_tbl_start) {\n\t\tmpch->oem_table_pointer =\n\t\t\t(uint32_t) (curraddr - startaddr + MPTABLE_BASE);\n\t\tmpch->oem_table_size = (uint16_t) oem_tbl_size;\n\t\tmemcpy(curraddr, oem_tbl_start, oem_tbl_size);\n\t}\n\n\tmpch->base_table_length = (uint16_t) (curraddr - (char *)mpch);\n\tmpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length);\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/pci_ahci.c",
    "content": "/*-\n * Copyright (c) 2013  Zhixiang Yu <zcore@freebsd.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <inttypes.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <strings.h>\n#include <pthread.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <assert.h>\n#include <sys/param.h>\n#include <sys/stat.h>\n#include <sys/uio.h>\n#include <sys/ioctl.h>\n#include <sys/disk.h>\n#include <sys/queue.h>\n// #include <sys/endian.h>\n\n#include <CommonCrypto/CommonDigest.h>\n\n#include <xhyve/support/misc.h>\n#include <xhyve/support/ata.h>\n#include <xhyve/support/linker_set.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/block_if.h>\n#include <xhyve/ahci.h>\n\n#define\tMAX_PORTS\t6\t/* Intel ICH8 AHCI supports 6 ports */\n\n#define\tPxSIG_ATA\t0x00000101 /* ATA drive */\n#define\tPxSIG_ATAPI\t0xeb140101 /* ATAPI drive */\n\nenum sata_fis_type {\n\tFIS_TYPE_REGH2D\t\t= 0x27,\t/* Register FIS - host to device */\n\tFIS_TYPE_REGD2H\t\t= 0x34,\t/* Register FIS - device to host */\n\tFIS_TYPE_DMAACT\t\t= 0x39,\t/* DMA activate FIS - device to host */\n\tFIS_TYPE_DMASETUP\t= 0x41,\t/* DMA setup FIS - bidirectional */\n\tFIS_TYPE_DATA\t\t= 0x46,\t/* Data FIS - bidirectional */\n\tFIS_TYPE_BIST\t\t= 0x58,\t/* BIST activate FIS - bidirectional */\n\tFIS_TYPE_PIOSETUP\t= 0x5F,\t/* PIO setup FIS - device to host */\n\tFIS_TYPE_SETDEVBITS\t= 0xA1,\t/* Set dev bits FIS - device to host */\n};\n\n/*\n * SCSI opcodes\n */\n#define\tTEST_UNIT_READY\t\t0x00\n#define\tREQUEST_SENSE\t\t0x03\n#define\tINQUIRY\t\t\t0x12\n#define\tSTART_STOP_UNIT\t\t0x1B\n#define\tPREVENT_ALLOW\t\t0x1E\n#define\tREAD_CAPACITY\t\t0x25\n#define\tREAD_10\t\t\t0x28\n// #define\tPOSITION_TO_ELEMENT\t0x2B\n#define\tREAD_TOC\t\t0x43\n#define\tGET_EVENT_STATUS_NOTIFICATION 0x4A\n#define\tMODE_SENSE_10\t\t0x5A\n#define\tREPORT_LUNS\t\t0xA0\n#define\tREAD_12\t\t\t0xA8\n// #define\tREAD_CD\t\t\t0xBE\n\n/*\n * SCSI mode page codes\n */\n#define\tMODEPAGE_RW_ERROR_RECOVERY\t0x01\n#define\tMODEPAGE_CD_CAPABILITIES\t0x2A\n\n/*\n * ATA commands\n */\n#define\tATA_SF_ENAB_SATA_SF\t\t0x10\n#define\t\tATA_SATA_SF_AN\t\t0x05\n// #define\tATA_SF_DIS_SATA_SF\t\t0x90\n\n/*\n * Debug printf\n */\n#ifdef AHCI_DEBUG\nstatic FILE *dbg;\n#define DPRINTF(format, ...) \\\n\tdo { \\\n\t\tfprintf(dbg, format, __VA_ARGS__); \\\n\t\tfflush(dbg); \\\n\t} while(0)\n#else\n#define DPRINTF(format, ...)\n#endif\n#define WPRINTF(format, ...) printf(format, __VA_ARGS__)\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct ahci_ioreq {\n\tstruct blockif_req io_req;\n\tstruct ahci_port *io_pr;\n\tSTAILQ_ENTRY(ahci_ioreq) io_flist;\n\tTAILQ_ENTRY(ahci_ioreq) io_blist;\n\tuint8_t *cfis;\n\tuint32_t len;\n\tuint32_t done;\n\tint slot;\n\tint more;\n};\n\n#define AHCI_PORT_IDENT 20 + 1\nstruct ahci_port {\n\tstruct blockif_ctxt *bctx;\n\tstruct pci_ahci_softc *pr_sc;\n\tuint8_t *cmd_lst;\n\tuint8_t *rfis;\n\tchar ident[AHCI_PORT_IDENT];\n\tint atapi;\n\tint reset;\n\tint waitforclear;\n\tint mult_sectors;\n\tuint8_t xfermode;\n\tuint8_t err_cfis[20];\n\tuint8_t sense_key;\n\tuint8_t asc;\n\tu_int ccs;\n\tuint32_t pending;\n\n\tuint32_t clb;\n\tuint32_t clbu;\n\tuint32_t fb;\n\tuint32_t fbu;\n\tuint32_t is;\n\tuint32_t ie;\n\tuint32_t cmd;\n\tuint32_t unused0;\n\tuint32_t tfd;\n\tuint32_t sig;\n\tuint32_t ssts;\n\tuint32_t sctl;\n\tuint32_t serr;\n\tuint32_t sact;\n\tuint32_t ci;\n\tuint32_t sntf;\n\tuint32_t fbs;\n\n\t/*\n\t * i/o request info\n\t */\n\tstruct ahci_ioreq *ioreq;\n\tint ioqsz;\n\tSTAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd;\n\tTAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd;\n};\n\nstruct ahci_cmd_hdr {\n\tuint16_t flags;\n\tuint16_t prdtl;\n\tuint32_t prdbc;\n\tuint64_t ctba;\n\tuint32_t reserved[4];\n};\n\nstruct ahci_prdt_entry {\n\tuint64_t dba;\n\tuint32_t reserved;\n#define\tDBCMASK\t\t0x3fffff\n\tuint32_t dbc;\n};\n\nstruct pci_ahci_softc {\n\tstruct pci_devinst *asc_pi;\n\tpthread_mutex_t\tmtx;\n\tint ports;\n\tuint32_t cap;\n\tuint32_t ghc;\n\tuint32_t is;\n\tuint32_t pi;\n\tuint32_t vs;\n\tuint32_t ccc_ctl;\n\tuint32_t ccc_pts;\n\tuint32_t em_loc;\n\tuint32_t em_ctl;\n\tuint32_t cap2;\n\tuint32_t bohc;\n\tuint32_t lintr;\n\tstruct ahci_port port[MAX_PORTS];\n};\n\n#pragma clang diagnostic pop\n\nstatic void ahci_handle_port(struct ahci_port *p);\n\nstatic inline void lba_to_msf(uint8_t *buf, int lba)\n{\n\tlba += 150;\n\tbuf[0] = (uint8_t) ((lba / 75) / 60);\n\tbuf[1] = (uint8_t) (lba / 75) % 60;\n\tbuf[2] = (uint8_t) (lba % 75);\n}\n\n/*\n * generate HBA intr depending on whether or not ports within\n * the controller have an interrupt pending.\n */\nstatic void\nahci_generate_intr(struct pci_ahci_softc *sc)\n{\n\tstruct pci_devinst *pi;\n\tint i;\n\n\tpi = sc->asc_pi;\n\n\tfor (i = 0; i < sc->ports; i++) {\n\t\tstruct ahci_port *pr;\n\t\tpr = &sc->port[i];\n\t\tif (pr->is & pr->ie)\n\t\t\tsc->is |= (1 << i);\n\t}\n\n\tDPRINTF(\"%s %x\\n\", __func__, sc->is);\n\n\tif (sc->is && (sc->ghc & AHCI_GHC_IE)) {\t\t\n\t\tif (pci_msi_enabled(pi)) {\n\t\t\t/*\n\t\t\t * Generate an MSI interrupt on every edge\n\t\t\t */\n\t\t\tpci_generate_msi(pi, 0);\n\t\t} else if (!sc->lintr) {\n\t\t\t/*\n\t\t\t * Only generate a pin-based interrupt if one wasn't\n\t\t\t * in progress\n\t\t\t */\n\t\t\tsc->lintr = 1;\n\t\t\tpci_lintr_assert(pi);\n\t\t}\n\t} else if (sc->lintr) {\n\t\t/*\n\t\t * No interrupts: deassert pin-based signal if it had\n\t\t * been asserted\n\t\t */\n\t\tpci_lintr_deassert(pi);\n\t\tsc->lintr = 0;\n\t}\n}\n\nstatic void\nahci_write_fis(struct ahci_port *p, enum sata_fis_type ft, uint8_t *fis)\n{\n\tint offset, len, irq;\n\n\tif (p->rfis == NULL || !(p->cmd & AHCI_P_CMD_FRE))\n\t\treturn;\n\n\tswitch (ft) {\n\tcase FIS_TYPE_REGD2H:\n\t\toffset = 0x40;\n\t\tlen = 20;\n\t\tirq = (fis[1] & (1 << 6)) ? AHCI_P_IX_DHR : 0;\n\t\tbreak;\n\tcase FIS_TYPE_SETDEVBITS:\n\t\toffset = 0x58;\n\t\tlen = 8;\n\t\tirq = (fis[1] & (1 << 6)) ? AHCI_P_IX_SDB : 0;\n\t\tbreak;\n\tcase FIS_TYPE_PIOSETUP:\n\t\toffset = 0x20;\n\t\tlen = 20;\n\t\tirq = (fis[1] & (1 << 6)) ? AHCI_P_IX_PS : 0;\n\t\tbreak;\n\tcase FIS_TYPE_REGH2D:\n\tcase FIS_TYPE_DMAACT:\n\tcase FIS_TYPE_DMASETUP:\n\tcase FIS_TYPE_DATA:\n\tcase FIS_TYPE_BIST:\n\t\tWPRINTF(\"unsupported fis type %d\\n\", ft);\n\t\treturn;\n\t}\n\tif (fis[2] & ATA_S_ERROR) {\n\t\tp->waitforclear = 1;\n\t\tirq |= AHCI_P_IX_TFE;\n\t}\n\tmemcpy(p->rfis + offset, fis, len);\n\tif (irq) {\n\t\tp->is |= ((unsigned) irq);\n\t\tahci_generate_intr(p->pr_sc);\n\t}\n}\n\nstatic void\nahci_write_fis_piosetup(struct ahci_port *p)\n{\n\tuint8_t fis[20];\n\n\tmemset(fis, 0, sizeof(fis));\n\tfis[0] = FIS_TYPE_PIOSETUP;\n\tahci_write_fis(p, FIS_TYPE_PIOSETUP, fis);\n}\n\nstatic void\nahci_write_fis_sdb(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)\n{\n\tuint8_t fis[8];\n\tuint8_t error;\n\n\terror = (tfd >> 8) & 0xff;\n\ttfd &= 0x77;\n\tmemset(fis, 0, sizeof(fis));\n\tfis[0] = FIS_TYPE_SETDEVBITS;\n\tfis[1] = (1 << 6);\n\tfis[2] = (uint8_t) tfd;\n\tfis[3] = error;\n\tif (fis[2] & ATA_S_ERROR) {\n\t\tp->err_cfis[0] = (uint8_t) slot;\n\t\tp->err_cfis[2] = (uint8_t) tfd;\n\t\tp->err_cfis[3] = error;\n\t\tmemcpy(&p->err_cfis[4], cfis + 4, 16);\n\t} else {\n\t\t*(uint32_t *)((void *) (fis + 4)) = (1 << slot);\n\t\tp->sact &= ~(1 << slot);\n\t}\n\tp->tfd &= ~((unsigned) 0x77);\n\tp->tfd |= tfd;\n\tahci_write_fis(p, FIS_TYPE_SETDEVBITS, fis);\n}\n\nstatic void\nahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)\n{\n\tuint8_t fis[20];\n\tuint8_t error;\n\n\terror = (tfd >> 8) & 0xff;\n\tmemset(fis, 0, sizeof(fis));\n\tfis[0] = FIS_TYPE_REGD2H;\n\tfis[1] = (1 << 6);\n\tfis[2] = tfd & 0xff;\n\tfis[3] = error;\n\tfis[4] = cfis[4];\n\tfis[5] = cfis[5];\n\tfis[6] = cfis[6];\n\tfis[7] = cfis[7];\n\tfis[8] = cfis[8];\n\tfis[9] = cfis[9];\n\tfis[10] = cfis[10];\n\tfis[11] = cfis[11];\n\tfis[12] = cfis[12];\n\tfis[13] = cfis[13];\n\tif (fis[2] & ATA_S_ERROR) {\n\t\tp->err_cfis[0] = 0x80;\n\t\tp->err_cfis[2] = tfd & 0xff;\n\t\tp->err_cfis[3] = error;\n\t\tmemcpy(&p->err_cfis[4], cfis + 4, 16);\n\t} else\n\t\tp->ci &= ~(1 << slot);\n\tp->tfd = tfd;\n\tahci_write_fis(p, FIS_TYPE_REGD2H, fis);\n}\n\nstatic void\nahci_write_fis_d2h_ncq(struct ahci_port *p, int slot)\n{\n\tuint8_t fis[20];\n\n\tp->tfd = ATA_S_READY | ATA_S_DSC;\n\tmemset(fis, 0, sizeof(fis));\n\tfis[0] = FIS_TYPE_REGD2H;\n\tfis[1] = 0; /* No interrupt */\n\tfis[2] = (uint8_t) p->tfd; /* Status */\n\tfis[3] = 0; /* No error */\n\tp->ci &= ~(1 << slot);\n\tahci_write_fis(p, FIS_TYPE_REGD2H, fis);\n}\n\nstatic void\nahci_write_reset_fis_d2h(struct ahci_port *p)\n{\n\tuint8_t fis[20];\n\n\tmemset(fis, 0, sizeof(fis));\n\tfis[0] = FIS_TYPE_REGD2H;\n\tfis[3] = 1;\n\tfis[4] = 1;\n\tif (p->atapi) {\n\t\tfis[5] = 0x14;\n\t\tfis[6] = 0xeb;\n\t}\n\tfis[12] = 1;\n\tahci_write_fis(p, FIS_TYPE_REGD2H, fis);\n}\n\nstatic void\nahci_check_stopped(struct ahci_port *p)\n{\n\t/*\n\t * If we are no longer processing the command list and nothing\n\t * is in-flight, clear the running bit, the current command\n\t * slot, the command issue and active bits.\n\t */\n\tif (!(p->cmd & AHCI_P_CMD_ST)) {\n\t\tif (p->pending == 0) {\n\t\t\tp->ccs = 0;\n\t\t\tp->cmd &= ~((unsigned) (AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK));\n\t\t\tp->ci = 0;\n\t\t\tp->sact = 0;\n\t\t\tp->waitforclear = 0;\n\t\t}\n\t}\n}\n\nstatic void\nahci_port_stop(struct ahci_port *p)\n{\n\tstruct ahci_ioreq *aior;\n\tuint8_t *cfis;\n\tint slot;\n\tint ncq;\n\tint error;\n\n\tncq = 0;\n\n\tTAILQ_FOREACH(aior, &p->iobhd, io_blist) {\n\t\t/*\n\t\t * Try to cancel the outstanding blockif request.\n\t\t */\n\t\terror = blockif_cancel(p->bctx, &aior->io_req);\n\t\tif (error != 0)\n\t\t\tcontinue;\n\n\t\tslot = aior->slot;\n\t\tcfis = aior->cfis;\n\t\tif (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||\n\t\t    cfis[2] == ATA_READ_FPDMA_QUEUED ||\n\t\t    cfis[2] == ATA_SEND_FPDMA_QUEUED)\n\t\t{\n\t\t\tncq = 1;\n\t\t}\n\n\t\tif (ncq)\n\t\t\tp->sact &= ~(1 << slot);\n\t\telse\n\t\t\tp->ci &= ~(1 << slot);\n\n\t\t/*\n\t\t * This command is now done.\n\t\t */\n\t\tp->pending &= ~(1 << slot);\n\n\t\t/*\n\t\t * Delete the blockif request from the busy list\n\t\t */\n\t\tTAILQ_REMOVE(&p->iobhd, aior, io_blist);\n\n\t\t/*\n\t\t * Move the blockif request back to the free list\n\t\t */\n\t\tSTAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);\n\t}\n\n\tahci_check_stopped(p);\n}\n\nstatic void\nahci_port_reset(struct ahci_port *pr)\n{\n\tpr->serr = 0;\n\tpr->sact = 0;\n\tpr->xfermode = ATA_UDMA6;\n\tpr->mult_sectors = 128;\n\n\tif (!pr->bctx) {\n\t\tpr->ssts = ATA_SS_DET_NO_DEVICE;\n\t\tpr->sig = 0xFFFFFFFF;\n\t\tpr->tfd = 0x7F;\n\t\treturn;\n\t}\n\tpr->ssts = ATA_SS_DET_PHY_ONLINE | ATA_SS_IPM_ACTIVE;\n\tif (pr->sctl & ATA_SC_SPD_MASK)\n\t\tpr->ssts |= (pr->sctl & ATA_SC_SPD_MASK);\n\telse\n\t\tpr->ssts |= ATA_SS_SPD_GEN3;\n\tpr->tfd = (1 << 8) | ATA_S_DSC | ATA_S_DMA;\n\tif (!pr->atapi) {\n\t\tpr->sig = PxSIG_ATA;\n\t\tpr->tfd |= ATA_S_READY;\n\t} else\n\t\tpr->sig = PxSIG_ATAPI;\n\tahci_write_reset_fis_d2h(pr);\n}\n\nstatic void\nahci_reset(struct pci_ahci_softc *sc)\n{\n\tint i;\n\n\tsc->ghc = AHCI_GHC_AE;\n\tsc->is = 0;\n\n\tif (sc->lintr) {\n\t\tpci_lintr_deassert(sc->asc_pi);\n\t\tsc->lintr = 0;\n\t}\n\n\tfor (i = 0; i < sc->ports; i++) {\n\t\tsc->port[i].ie = 0;\n\t\tsc->port[i].is = 0;\n\t\tsc->port[i].cmd = (AHCI_P_CMD_SUD | AHCI_P_CMD_POD);\n\t\tif (sc->port[i].bctx)\n\t\t\tsc->port[i].cmd |= AHCI_P_CMD_CPS;\n\t\tsc->port[i].sctl = 0;\n\t\tahci_port_reset(&sc->port[i]);\n\t}\n}\n\nstatic void\nata_string(uint8_t *dest, const char *src, int len)\n{\n\tint i;\n\n\tfor (i = 0; i < len; i++) {\n\t\tif (*src)\n\t\t\tdest[i ^ 1] = (uint8_t) *src++;\n\t\telse\n\t\t\tdest[i ^ 1] = ' ';\n\t}\n}\n\nstatic void\natapi_string(uint8_t *dest, const char *src, int len)\n{\n\tint i;\n\n\tfor (i = 0; i < len; i++) {\n\t\tif (*src)\n\t\t\tdest[i] = (uint8_t) *src++;\n\t\telse\n\t\t\tdest[i] = ' ';\n\t}\n}\n\n/*\n * Build up the iovec based on the PRDT, 'done' and 'len'.\n */\nstatic void\nahci_build_iov(struct ahci_port *p, struct ahci_ioreq *aior,\n    struct ahci_prdt_entry *prdt, uint16_t prdtl)\n{\n\tstruct blockif_req *breq = &aior->io_req;\n\tint i, j, skip, todo, left, extra;\n\tuint32_t dbcsz;\n\n\t/* Copy part of PRDT between 'done' and 'len' bytes into the iov. */\n\tskip = (int) aior->done;\n\tleft = (int) (aior->len - aior->done);\n\ttodo = 0;\n\tfor (i = 0, j = 0; i < prdtl && j < BLOCKIF_IOV_MAX && left > 0;\n\t    i++, prdt++) {\n\t\tdbcsz = (prdt->dbc & DBCMASK) + 1;\n\t\t/* Skip already done part of the PRDT */\n\t\tif (dbcsz <= ((uint32_t) skip)) {\n\t\t\tskip -= dbcsz;\n\t\t\tcontinue;\n\t\t}\n\t\tdbcsz -= ((unsigned) skip);\n\t\tif (dbcsz > ((uint32_t) left)) {\n\t\t\tdbcsz = ((uint32_t) left);\n\t\t}\n\t\tbreq->br_iov[j].iov_base =\n\t\t\tpaddr_guest2host((prdt->dba + ((uint64_t) skip)), dbcsz);\n\t\tbreq->br_iov[j].iov_len = dbcsz;\n\t\ttodo += dbcsz;\n\t\tleft -= dbcsz;\n\t\tskip = 0;\n\t\tj++;\n\t}\n\n\t/* If we got limited by IOV length, round I/O down to sector size. */\n\tif (j == BLOCKIF_IOV_MAX) {\n\t\textra = todo % blockif_sectsz(p->bctx);\n\t\ttodo -= extra;\n\t\tassert(todo > 0);\n\t\twhile (extra > 0) {\n\t\t\tif (breq->br_iov[j - 1].iov_len > ((size_t) extra)) {\n\t\t\t\tbreq->br_iov[j - 1].iov_len -= ((size_t) extra);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\textra -= breq->br_iov[j - 1].iov_len;\n\t\t\tj--;\n\t\t}\n\t}\n\n\tbreq->br_iovcnt = j;\n\tbreq->br_resid = todo;\n\taior->done += ((unsigned) todo);\n\taior->more = (aior->done < aior->len && i < prdtl);\n}\n\nstatic void\nahci_handle_rw(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)\n{\n\tstruct ahci_ioreq *aior;\n\tstruct blockif_req *breq;\n\tstruct ahci_prdt_entry *prdt;\n\tstruct ahci_cmd_hdr *hdr;\n\tuint64_t lba;\n\tuint32_t len;\n\tint err, first, ncq, readop;\n\n\tprdt = (struct ahci_prdt_entry *)((void *) (cfis + 0x80));\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tncq = 0;\n\treadop = 1;\n\tfirst = (done == 0);\n\n\tif (cfis[2] == ATA_WRITE || cfis[2] == ATA_WRITE48 ||\n\t    cfis[2] == ATA_WRITE_MUL || cfis[2] == ATA_WRITE_MUL48 ||\n\t    cfis[2] == ATA_WRITE_DMA || cfis[2] == ATA_WRITE_DMA48 ||\n\t    cfis[2] == ATA_WRITE_FPDMA_QUEUED)\n\t\treadop = 0;\n\n\tif (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||\n\t    cfis[2] == ATA_READ_FPDMA_QUEUED) {\n\t\tlba = ((uint64_t)cfis[10] << 40) |\n\t\t\t((uint64_t)cfis[9] << 32) |\n\t\t\t((uint64_t)cfis[8] << 24) |\n\t\t\t((uint64_t)cfis[6] << 16) |\n\t\t\t((uint64_t)cfis[5] << 8) |\n\t\t\tcfis[4];\n\t\tlen = (uint32_t) (cfis[11] << 8 | cfis[3]);\n\t\tif (!len)\n\t\t\tlen = 65536;\n\t\tncq = 1;\n\t} else if (cfis[2] == ATA_READ48 || cfis[2] == ATA_WRITE48 ||\n\t    cfis[2] == ATA_READ_MUL48 || cfis[2] == ATA_WRITE_MUL48 ||\n\t    cfis[2] == ATA_READ_DMA48 || cfis[2] == ATA_WRITE_DMA48) {\n\t\tlba = ((uint64_t)cfis[10] << 40) |\n\t\t\t((uint64_t)cfis[9] << 32) |\n\t\t\t((uint64_t)cfis[8] << 24) |\n\t\t\t((uint64_t)cfis[6] << 16) |\n\t\t\t((uint64_t)cfis[5] << 8) |\n\t\t\tcfis[4];\n\t\tlen = (uint32_t) (cfis[13] << 8 | cfis[12]);\n\t\tif (!len)\n\t\t\tlen = 65536;\n\t} else {\n\t\tlba = (uint64_t) (((cfis[7] & 0xf) << 24) | (cfis[6] << 16) |\n\t\t\t(cfis[5] << 8) | cfis[4]);\n\t\tlen = cfis[12];\n\t\tif (!len)\n\t\t\tlen = 256;\n\t}\n\tlba *= (uint64_t) blockif_sectsz(p->bctx);\n\tlen *= (uint32_t) blockif_sectsz(p->bctx);\n\n\t/* Pull request off free list */\n\taior = STAILQ_FIRST(&p->iofhd);\n\tassert(aior != NULL);\n\tSTAILQ_REMOVE_HEAD(&p->iofhd, io_flist);\n\n\taior->cfis = cfis;\n\taior->slot = slot;\n\taior->len = len;\n\taior->done = done;\n\tbreq = &aior->io_req;\n\tbreq->br_offset = (off_t) (lba + done);\n\tahci_build_iov(p, aior, prdt, hdr->prdtl);\n\n\t/* Mark this command in-flight. */\n\tp->pending |= 1 << slot;\n\n\t/* Stuff request onto busy list. */\n\tTAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);\n\n\tif (ncq && first)\n\t\tahci_write_fis_d2h_ncq(p, slot);\n\n\tif (readop)\n\t\terr = blockif_read(p->bctx, breq);\n\telse\n\t\terr = blockif_write(p->bctx, breq);\n\tassert(err == 0);\n}\n\nstatic void\nahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tstruct ahci_ioreq *aior;\n\tstruct blockif_req *breq;\n\tint err;\n\n\t/*\n\t * Pull request off free list\n\t */\n\taior = STAILQ_FIRST(&p->iofhd);\n\tassert(aior != NULL);\n\tSTAILQ_REMOVE_HEAD(&p->iofhd, io_flist);\n\taior->cfis = cfis;\n\taior->slot = slot;\n\taior->len = 0;\n\taior->done = 0;\n\taior->more = 0;\n\tbreq = &aior->io_req;\n\n\t/*\n\t * Mark this command in-flight.\n\t */\n\tp->pending |= 1 << slot;\n\n\t/*\n\t * Stuff request onto busy list\n\t */\n\tTAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);\n\n\terr = blockif_flush(p->bctx, breq);\n\tassert(err == 0);\n}\n\nstatic inline void\nread_prdt(struct ahci_port *p, int slot, uint8_t *cfis,\n\t\tvoid *buf, int size)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\tstruct ahci_prdt_entry *prdt;\n\tvoid *to;\n\tint i, len;\n\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tlen = size;\n\tto = buf;\n\tprdt = (struct ahci_prdt_entry *)((void *) (cfis + 0x80));\n\tfor (i = 0; i < hdr->prdtl && len; i++) {\n\t\tuint8_t *ptr;\n\t\tuint32_t dbcsz;\n\t\tint sublen;\n\n\t\tdbcsz = (prdt->dbc & DBCMASK) + 1;\n\t\tptr = paddr_guest2host(prdt->dba, dbcsz);\n\t\tsublen = ((len < ((int) dbcsz)) ? len : ((int) dbcsz));\n\t\tmemcpy(to, ptr, sublen);\n\t\tlen -= sublen;\n\t\tto = (uint8_t *) (((uintptr_t) to) + ((uintptr_t) sublen));\n\t\tprdt++;\n\t}\n}\n\nstatic void\nahci_handle_dsm_trim(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)\n{\n\tstruct ahci_ioreq *aior;\n\tstruct blockif_req *breq;\n\tuint8_t *entry;\n\tuint64_t elba;\n\tuint32_t len, elen;\n\tint err, first, ncq;\n\tuint8_t buf[512];\n\n\tfirst = (done == 0);\n\tif (cfis[2] == ATA_DATA_SET_MANAGEMENT) {\n\t\tlen = (uint32_t) ((((uint16_t) cfis[13]) << 8) | cfis[12]);\n\t\tlen *= 512;\n\t\tncq = 0;\n\t} else { /* ATA_SEND_FPDMA_QUEUED */\n\t\tlen = (uint32_t) ((((uint16_t) cfis[11]) << 8) | cfis[3]);\n\t\tlen *= 512;\n\t\tncq = 1;\n\t}\n\tread_prdt(p, slot, cfis, buf, sizeof(buf));\n\nnext:\n\tentry = &buf[done];\n\telba = ((uint64_t)entry[5] << 40) |\n\t\t((uint64_t)entry[4] << 32) |\n\t\t((uint64_t)entry[3] << 24) |\n\t\t((uint64_t)entry[2] << 16) |\n\t\t((uint64_t)entry[1] << 8) |\n\t\tentry[0];\n\telen = (uint32_t) ((((uint16_t) entry[7]) << 8) | entry[6]);\n\tdone += 8;\n\tif (elen == 0) {\n\t\tif (done >= len) {\n\t\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\t\tp->pending &= ~(1 << slot);\n\t\t\tahci_check_stopped(p);\n\t\t\tif (!first)\n\t\t\t\tahci_handle_port(p);\n\t\t\treturn;\n\t\t}\n\t\tgoto next;\n\t}\n\n\t/*\n\t * Pull request off free list\n\t */\n\taior = STAILQ_FIRST(&p->iofhd);\n\tassert(aior != NULL);\n\tSTAILQ_REMOVE_HEAD(&p->iofhd, io_flist);\n\taior->cfis = cfis;\n\taior->slot = slot;\n\taior->len = len;\n\taior->done = done;\n\taior->more = (len != done);\n\n\tbreq = &aior->io_req;\n\tbreq->br_offset = (off_t) (elba * ((uint64_t) blockif_sectsz(p->bctx)));\n\tbreq->br_resid = elen * ((unsigned) blockif_sectsz(p->bctx));\n\n\t/*\n\t * Mark this command in-flight.\n\t */\n\tp->pending |= 1 << slot;\n\n\t/*\n\t * Stuff request onto busy list\n\t */\n\tTAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);\n\n\tif (ncq && first)\n\t\tahci_write_fis_d2h_ncq(p, slot);\n\n\terr = blockif_delete(p->bctx, breq);\n\tassert(err == 0);\n}\n\nstatic inline void\nwrite_prdt(struct ahci_port *p, int slot, uint8_t *cfis,\n\t\tvoid *buf, int size)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\tstruct ahci_prdt_entry *prdt;\n\tvoid *from;\n\tint i, len;\n\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tlen = size;\n\tfrom = buf;\n\tprdt = (struct ahci_prdt_entry *)((void *) (cfis + 0x80));\n\tfor (i = 0; i < hdr->prdtl && len; i++) {\n\t\tuint8_t *ptr;\n\t\tuint32_t dbcsz;\n\t\tint sublen;\n\n\t\tdbcsz = (prdt->dbc & DBCMASK) + 1;\n\t\tptr = paddr_guest2host(prdt->dba, dbcsz);\n\t\tsublen = (len < ((int) dbcsz)) ? len : ((int) dbcsz);\n\t\tmemcpy(ptr, from, sublen);\n\t\tlen -= sublen;\n\t\tfrom = (void *) (((uintptr_t) from) + ((uintptr_t) sublen));\n\t\tprdt++;\n\t}\n\thdr->prdbc = (uint32_t) (size - len);\n}\n\nstatic void\nahci_checksum(uint8_t *buf, int size)\n{\n\tint i;\n\tuint8_t sum = 0;\n\n\tfor (i = 0; i < size - 1; i++)\n\t\tsum += buf[i];\n\tbuf[size - 1] = (uint8_t) (0x100 - sum);\n}\n\nstatic void\nahci_handle_read_log(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\tuint8_t buf[512];\n\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tif (p->atapi || hdr->prdtl == 0 || cfis[4] != 0x10 ||\n\t    cfis[5] != 0 || cfis[9] != 0 || cfis[12] != 1 || cfis[13] != 0) {\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t\treturn;\n\t}\n\n\tmemset(buf, 0, sizeof(buf));\n\tmemcpy(buf, p->err_cfis, sizeof(p->err_cfis));\n\tahci_checksum(buf, sizeof(buf));\n\n\tif (cfis[2] == ATA_READ_LOG_EXT)\n\t\tahci_write_fis_piosetup(p);\n\twrite_prdt(p, slot, cfis, (void *)buf, sizeof(buf));\n\tahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);\n}\n\nstatic void\nhandle_identify(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tif (p->atapi || hdr->prdtl == 0) {\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t} else {\n\t\tuint16_t buf[256];\n\t\tuint64_t sectors;\n\t\tint sectsz, psectsz, psectoff, candelete, ro;\n\t\tuint16_t cyl;\n\t\tuint8_t sech, heads;\n\n\t\tro = blockif_is_ro(p->bctx);\n\t\tcandelete = blockif_candelete(p->bctx);\n\t\tsectsz = blockif_sectsz(p->bctx);\n\t\tsectors = (uint64_t) (blockif_size(p->bctx) / sectsz);\n\t\tblockif_chs(p->bctx, &cyl, &heads, &sech);\n\t\tblockif_psectsz(p->bctx, &psectsz, &psectoff);\n\t\tmemset(buf, 0, sizeof(buf));\n\t\tbuf[0] = 0x0040;\n\t\tbuf[1] = cyl;\n\t\tbuf[3] = heads;\n\t\tbuf[6] = sech;\n\t\tata_string((uint8_t *)(buf+10), p->ident, 20);\n\t\tata_string((uint8_t *)(buf+23), \"001\", 8);\n\t\tata_string((uint8_t *)(buf+27), \"BHYVE SATA DISK\", 40);\n\t\tbuf[47] = (0x8000 | 128);\n\t\tbuf[48] = 0x1;\n\t\tbuf[49] = (1 << 8 | 1 << 9 | 1 << 11);\n\t\tbuf[50] = (1 << 14);\n\t\tbuf[53] = (1 << 1 | 1 << 2);\n\t\tif (p->mult_sectors)\n\t\t\tbuf[59] = (uint16_t) (0x100 | p->mult_sectors);\n\t\tif (sectors <= 0x0fffffff) {\n\t\t\tbuf[60] = (uint16_t) sectors;\n\t\t\tbuf[61] = (uint16_t)(sectors >> 16);\n\t\t} else {\n\t\t\tbuf[60] = 0xffff;\n\t\t\tbuf[61] = 0x0fff;\n\t\t}\n\t\tbuf[63] = 0x7;\n\t\tif (p->xfermode & ATA_WDMA0)\n\t\t\tbuf[63] |= (1 << ((p->xfermode & 7) + 8));\n\t\tbuf[64] = 0x3;\n\t\tbuf[65] = 120;\n\t\tbuf[66] = 120;\n\t\tbuf[67] = 120;\n\t\tbuf[68] = 120;\n\t\tbuf[69] = 0;\n\t\tbuf[75] = 31;\n\t\tbuf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3 |\n\t\t\t   ATA_SUPPORT_NCQ);\n\t\tbuf[77] = (ATA_SUPPORT_RCVSND_FPDMA_QUEUED |\n\t\t\t   (p->ssts & ATA_SS_SPD_MASK) >> 3);\n\t\tbuf[80] = 0x3f0;\n\t\tbuf[81] = 0x28;\n\t\tbuf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE|\n\t\t\t   ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP);\n\t\tbuf[83] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE |\n\t\t\t   ATA_SUPPORT_FLUSHCACHE48 | 1 << 14);\n\t\tbuf[84] = (1 << 14);\n\t\tbuf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_WRITECACHE|\n\t\t\t   ATA_SUPPORT_LOOKAHEAD | ATA_SUPPORT_NOP);\n\t\tbuf[86] = (ATA_SUPPORT_ADDRESS48 | ATA_SUPPORT_FLUSHCACHE |\n\t\t\t   ATA_SUPPORT_FLUSHCACHE48 | 1 << 15);\n\t\tbuf[87] = (1 << 14);\n\t\tbuf[88] = 0x7f;\n\t\tif (p->xfermode & ATA_UDMA0)\n\t\t\tbuf[88] |= (1 << ((p->xfermode & 7) + 8));\n\t\tbuf[100] = (uint16_t) sectors;\n\t\tbuf[101] = (uint16_t) (sectors >> 16);\n\t\tbuf[102] = (uint16_t) (sectors >> 32);\n\t\tbuf[103] = (sectors >> 48);\n\t\tif (candelete && !ro) {\n\t\t\tbuf[69] |= ATA_SUPPORT_RZAT | ATA_SUPPORT_DRAT;\n\t\t\tbuf[105] = 1;\n\t\t\tbuf[169] = ATA_SUPPORT_DSM_TRIM;\n\t\t}\n\t\tbuf[106] = 0x4000;\n\t\tbuf[209] = 0x4000;\n\t\tif (psectsz > sectsz) {\n\t\t\tbuf[106] |= 0x2000;\n\t\t\tbuf[106] |= ffsl(psectsz / sectsz) - 1;\n\t\t\tbuf[209] |= (psectoff / sectsz);\n\t\t}\n\t\tif (sectsz > 512) {\n\t\t\tbuf[106] |= 0x1000;\n\t\t\tbuf[117] = (uint16_t) (sectsz / 2);\n\t\t\tbuf[118] = (uint16_t) ((sectsz / 2) >> 16);\n\t\t}\n\t\tbuf[119] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14);\n\t\tbuf[120] = (ATA_SUPPORT_RWLOGDMAEXT | 1 << 14);\n\t\tbuf[222] = 0x1020;\n\t\tbuf[255] = 0x00a5;\n\t\tahci_checksum((uint8_t *)buf, sizeof(buf));\n\t\tahci_write_fis_piosetup(p);\n\t\twrite_prdt(p, slot, cfis, (void *)buf, sizeof(buf));\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);\n\t}\n}\n\nstatic void\nhandle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tif (!p->atapi) {\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t} else {\n\t\tuint16_t buf[256];\n\n\t\tmemset(buf, 0, sizeof(buf));\n\t\tbuf[0] = (2 << 14 | 5 << 8 | 1 << 7 | 2 << 5);\n\t\tata_string((uint8_t *)(buf+10), p->ident, 20);\n\t\tata_string((uint8_t *)(buf+23), \"001\", 8);\n\t\tata_string((uint8_t *)(buf+27), \"BHYVE SATA DVD ROM\", 40);\n\t\tbuf[49] = (1 << 9 | 1 << 8);\n\t\tbuf[50] = (1 << 14 | 1);\n\t\tbuf[53] = (1 << 2 | 1 << 1);\n\t\tbuf[62] = 0x3f;\n\t\tbuf[63] = 7;\n\t\tif (p->xfermode & ATA_WDMA0)\n\t\t\tbuf[63] |= (1 << ((p->xfermode & 7) + 8));\n\t\tbuf[64] = 3;\n\t\tbuf[65] = 120;\n\t\tbuf[66] = 120;\n\t\tbuf[67] = 120;\n\t\tbuf[68] = 120;\n\t\tbuf[76] = (ATA_SATA_GEN1 | ATA_SATA_GEN2 | ATA_SATA_GEN3);\n\t\tbuf[77] = ((p->ssts & ATA_SS_SPD_MASK) >> 3);\n\t\tbuf[78] = (1 << 5);\n\t\tbuf[80] = 0x3f0;\n\t\tbuf[82] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET |\n\t\t\t   ATA_SUPPORT_RESET | ATA_SUPPORT_NOP);\n\t\tbuf[83] = (1 << 14);\n\t\tbuf[84] = (1 << 14);\n\t\tbuf[85] = (ATA_SUPPORT_POWERMGT | ATA_SUPPORT_PACKET |\n\t\t\t   ATA_SUPPORT_RESET | ATA_SUPPORT_NOP);\n\t\tbuf[87] = (1 << 14);\n\t\tbuf[88] = 0x7f;\n\t\tif (p->xfermode & ATA_UDMA0)\n\t\t\tbuf[88] |= (1 << ((p->xfermode & 7) + 8));\n\t\tbuf[222] = 0x1020;\n\t\tbuf[255] = 0x00a5;\n\t\tahci_checksum((uint8_t *)buf, sizeof(buf));\n\t\tahci_write_fis_piosetup(p);\n\t\twrite_prdt(p, slot, cfis, (void *)buf, sizeof(buf));\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_DSC | ATA_S_READY);\n\t}\n}\n\nstatic void\natapi_inquiry(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t buf[36];\n\tuint8_t *acmd;\n\tint len;\n\tuint32_t tfd;\n\n\tacmd = cfis + 0x40;\n\n\tif (acmd[1] & 1) {\t\t/* VPD */\n\t\tif (acmd[2] == 0) {\t/* Supported VPD pages */\n\t\t\tbuf[0] = 0x05;\n\t\t\tbuf[1] = 0;\n\t\t\tbuf[2] = 0;\n\t\t\tbuf[3] = 1;\n\t\t\tbuf[4] = 0;\n\t\t\tlen = 4 + buf[3];\n\t\t} else {\n\t\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\t\tp->asc = 0x24;\n\t\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\t\tahci_write_fis_d2h(p, slot, cfis, tfd);\n\t\t\treturn;\n\t\t}\n\t} else {\n\t\tbuf[0] = 0x05;\n\t\tbuf[1] = 0x80;\n\t\tbuf[2] = 0x00;\n\t\tbuf[3] = 0x21;\n\t\tbuf[4] = 31;\n\t\tbuf[5] = 0;\n\t\tbuf[6] = 0;\n\t\tbuf[7] = 0;\n\t\tatapi_string(buf + 8, \"BHYVE\", 8);\n\t\tatapi_string(buf + 16, \"BHYVE DVD-ROM\", 16);\n\t\tatapi_string(buf + 32, \"001\", 4);\n\t\tlen = sizeof(buf);\n\t}\n\n\tif (len > acmd[4])\n\t\tlen = acmd[4];\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\twrite_prdt(p, slot, cfis, buf, len);\n\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n}\n\nstatic __inline void\nbe16enc(void *pp, uint16_t u)\n{\n\tunsigned char *p = (unsigned char *)pp;\n\n\tp[0] = (u >> 8) & 0xff;\n\tp[1] = u & 0xff;\n}\n\nstatic __inline uint16_t\nbe16dec(const void *pp)\n{\n\tunsigned char const *p = (unsigned char const *)pp;\n\n\treturn ((uint16_t) ((((uint32_t) p[0]) << 8) | ((uint32_t) p[1])));\n}\n\nstatic __inline void\nbe32enc(void *pp, uint32_t u)\n{\n\tunsigned char *p = (unsigned char *)pp;\n\n\tp[0] = (u >> 24) & 0xff;\n\tp[1] = (u >> 16) & 0xff;\n\tp[2] = (u >> 8) & 0xff;\n\tp[3] = u & 0xff;\n}\n\nstatic __inline uint32_t\nbe32dec(const void *pp)\n{\n\tunsigned char const *p = (unsigned char const *)pp;\n\n\treturn (uint32_t) ((((uint64_t) p[0]) << 24) | \n\t\t(((uint64_t) p[1]) << 16) | (((uint64_t) p[2]) << 8) |\n\t\t\t((uint64_t) p[3]));\n}\n\nstatic void\natapi_read_capacity(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t buf[8];\n\tuint64_t sectors;\n\n\tsectors = (uint64_t) (blockif_size(p->bctx) / 2048);\n\tbe32enc(buf, ((uint32_t) (sectors - 1)));\n\tbe32enc(buf + 4, 2048);\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\twrite_prdt(p, slot, cfis, buf, sizeof(buf));\n\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n}\n\nstatic void\natapi_read_toc(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t *acmd;\n\tuint8_t format;\n\tint len;\n\n\tacmd = cfis + 0x40;\n\n\tlen = be16dec(acmd + 7);\n\tformat = acmd[9] >> 6;\n\tswitch (format) {\n\tcase 0:\n\t{\n\t\tint msf, size;\n\t\tuint64_t sectors;\n\t\tuint8_t start_track, buf[20], *bp;\n\n\t\tmsf = (acmd[1] >> 1) & 1;\n\t\tstart_track = acmd[6];\n\t\tif (start_track > 1 && start_track != 0xaa) {\n\t\t\tuint32_t tfd;\n\t\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\t\tp->asc = 0x24;\n\t\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\t\tahci_write_fis_d2h(p, slot, cfis, tfd);\n\t\t\treturn;\n\t\t}\n\t\tbp = buf + 2;\n\t\t*bp++ = 1;\n\t\t*bp++ = 1;\n\t\tif (start_track <= 1) {\n\t\t\t*bp++ = 0;\n\t\t\t*bp++ = 0x14;\n\t\t\t*bp++ = 1;\n\t\t\t*bp++ = 0;\n\t\t\tif (msf) {\n\t\t\t\t*bp++ = 0;\n\t\t\t\tlba_to_msf(bp, 0);\n\t\t\t\tbp += 3;\n\t\t\t} else {\n\t\t\t\t*bp++ = 0;\n\t\t\t\t*bp++ = 0;\n\t\t\t\t*bp++ = 0;\n\t\t\t\t*bp++ = 0;\n\t\t\t}\n\t\t}\n\t\t*bp++ = 0;\n\t\t*bp++ = 0x14;\n\t\t*bp++ = 0xaa;\n\t\t*bp++ = 0;\n\t\tsectors = (uint64_t) (blockif_size(p->bctx) / blockif_sectsz(p->bctx));\n\t\tsectors >>= 2;\n\t\tif (msf) {\n\t\t\t*bp++ = 0;\n\t\t\tlba_to_msf(bp, ((int) sectors));\n\t\t\tbp += 3;\n\t\t} else {\n\t\t\tbe32enc(bp, ((uint32_t) sectors));\n\t\t\tbp += 4;\n\t\t}\n\t\tsize = (int) (bp - buf);\n\t\tbe16enc(buf, ((uint16_t) (size - 2)));\n\t\tif (len > size)\n\t\t\tlen = size;\n\t\twrite_prdt(p, slot, cfis, buf, len);\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\tbreak;\n\t}\n\tcase 1:\n\t{\n\t\tuint8_t buf[12];\n\n\t\tmemset(buf, 0, sizeof(buf));\n\t\tbuf[1] = 0xa;\n\t\tbuf[2] = 0x1;\n\t\tbuf[3] = 0x1;\n\t\tif (((size_t) len) > sizeof(buf))\n\t\t\tlen = sizeof(buf);\n\t\twrite_prdt(p, slot, cfis, buf, len);\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\tbreak;\n\t}\n\tcase 2:\n\t{\n\t\tint msf, size;\n\t\tuint64_t sectors;\n\t\tuint8_t start_track, *bp, buf[50];\n\n\t\tmsf = (acmd[1] >> 1) & 1;\n\t\tstart_track = acmd[6];\n\t\tbp = buf + 2;\n\t\t*bp++ = 1;\n\t\t*bp++ = 1;\n\n\t\t*bp++ = 1;\n\t\t*bp++ = 0x14;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0xa0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 1;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\n\t\t*bp++ = 1;\n\t\t*bp++ = 0x14;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0xa1;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 1;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\n\t\t*bp++ = 1;\n\t\t*bp++ = 0x14;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0xa2;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\tsectors = (uint64_t) (blockif_size(p->bctx) / blockif_sectsz(p->bctx));\n\t\tsectors >>= 2;\n\t\tif (msf) {\n\t\t\t*bp++ = 0;\n\t\t\tlba_to_msf(bp, ((int) sectors));\n\t\t\tbp += 3;\n\t\t} else {\n\t\t\tbe32enc(bp, ((uint32_t) sectors));\n\t\t\tbp += 4;\n\t\t}\n\n\t\t*bp++ = 1;\n\t\t*bp++ = 0x14;\n\t\t*bp++ = 0;\n\t\t*bp++ = 1;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\t*bp++ = 0;\n\t\tif (msf) {\n\t\t\t*bp++ = 0;\n\t\t\tlba_to_msf(bp, 0);\n\t\t\tbp += 3;\n\t\t} else {\n\t\t\t*bp++ = 0;\n\t\t\t*bp++ = 0;\n\t\t\t*bp++ = 0;\n\t\t\t*bp++ = 0;\n\t\t}\n\n\t\tsize = (int) (bp - buf);\n\t\tbe16enc(buf, ((uint16_t) (size - 2)));\n\t\tif (len > size)\n\t\t\tlen = size;\n\t\twrite_prdt(p, slot, cfis, buf, len);\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\tbreak;\n\t}\n\tdefault:\n\t{\n\t\tuint32_t tfd;\n\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x24;\n\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, tfd);\n\t\tbreak;\n\t}\n\t}\n}\n\nstatic void\natapi_report_luns(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t buf[16];\n\n\tmemset(buf, 0, sizeof(buf));\n\tbuf[3] = 8;\n\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\twrite_prdt(p, slot, cfis, buf, sizeof(buf));\n\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n}\n\nstatic void\natapi_read(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done)\n{\n\tstruct ahci_ioreq *aior;\n\tstruct ahci_cmd_hdr *hdr;\n\tstruct ahci_prdt_entry *prdt;\n\tstruct blockif_req *breq;\n\tstruct pci_ahci_softc *sc;\n\tuint8_t *acmd;\n\tuint64_t lba;\n\tuint32_t len;\n\tint err;\n\n\tsc = p->pr_sc;\n\tacmd = cfis + 0x40;\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tprdt = (struct ahci_prdt_entry *)((void *) (cfis + 0x80));\n\n\tlba = be32dec(acmd + 2);\n\tif (acmd[0] == READ_10)\n\t\tlen = be16dec(acmd + 7);\n\telse\n\t\tlen = be32dec(acmd + 6);\n\tif (len == 0) {\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t}\n\tlba *= 2048;\n\tlen *= 2048;\n\n\t/*\n\t * Pull request off free list\n\t */\n\taior = STAILQ_FIRST(&p->iofhd);\n\tassert(aior != NULL);\n\tSTAILQ_REMOVE_HEAD(&p->iofhd, io_flist);\n\taior->cfis = cfis;\n\taior->slot = slot;\n\taior->len = len;\n\taior->done = done;\n\tbreq = &aior->io_req;\n\tbreq->br_offset = (off_t) (lba + ((uint64_t) done));\n\tahci_build_iov(p, aior, prdt, hdr->prdtl);\n\n\t/* Mark this command in-flight. */\n\tp->pending |= 1 << slot;\n\n\t/* Stuff request onto busy list. */\n\tTAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);\n\n\terr = blockif_read(p->bctx, breq);\n\tassert(err == 0);\n}\n\nstatic void\natapi_request_sense(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t buf[64];\n\tuint8_t *acmd;\n\tint len;\n\n\tacmd = cfis + 0x40;\n\tlen = acmd[4];\n\tif (((size_t) len) > sizeof(buf))\n\t\tlen = sizeof(buf);\n\tmemset(buf, 0, len);\n\tbuf[0] = 0x70 | (1 << 7);\n\tbuf[2] = p->sense_key;\n\tbuf[7] = 10;\n\tbuf[12] = p->asc;\n\twrite_prdt(p, slot, cfis, buf, len);\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n}\n\nstatic void\natapi_start_stop_unit(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t *acmd = cfis + 0x40;\n\tuint32_t tfd;\n\n\ttfd = 0;\n\n\tswitch (acmd[4] & 3) {\n\tcase 0:\n\tcase 1:\n\tcase 3:\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\ttfd = ATA_S_READY | ATA_S_DSC;\n\t\tbreak;\n\tcase 2:\n\t\t/* TODO eject media */\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x53;\n\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\n\t}\n\tahci_write_fis_d2h(p, slot, cfis, tfd);\n}\n\nstatic void\natapi_mode_sense(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t *acmd;\n\tuint32_t tfd;\n\tuint8_t pc, code;\n\tint len;\n\n\ttfd = 0;\n\n\tacmd = cfis + 0x40;\n\tlen = be16dec(acmd + 7);\n\tpc = acmd[2] >> 6;\n\tcode = acmd[2] & 0x3f;\n\n\tswitch (pc) {\n\tcase 0:\n\t\tswitch (code) {\n\t\tcase MODEPAGE_RW_ERROR_RECOVERY:\n\t\t{\n\t\t\tuint8_t buf[16];\n\n\t\t\tif (((size_t) len) > sizeof(buf)) {\n\t\t\t\tlen = sizeof(buf);\n\t\t\t}\n\n\t\t\tmemset(buf, 0, sizeof(buf));\n\t\t\tbe16enc(buf, 16 - 2);\n\t\t\tbuf[2] = 0x70;\n\t\t\tbuf[8] = 0x01;\n\t\t\tbuf[9] = 16 - 10;\n\t\t\tbuf[11] = 0x05;\n\t\t\twrite_prdt(p, slot, cfis, buf, len);\n\t\t\ttfd = ATA_S_READY | ATA_S_DSC;\n\t\t\tbreak;\n\t\t}\n\t\tcase MODEPAGE_CD_CAPABILITIES:\n\t\t{\n\t\t\tuint8_t buf[30];\n\n\t\t\tif (((size_t) len) > sizeof(buf)) {\n\t\t\t\tlen = sizeof(buf);\n\t\t\t}\n\n\t\t\tmemset(buf, 0, sizeof(buf));\n\t\t\tbe16enc(buf, 30 - 2);\n\t\t\tbuf[2] = 0x70;\n\t\t\tbuf[8] = 0x2A;\n\t\t\tbuf[9] = 30 - 10;\n\t\t\tbuf[10] = 0x08;\n\t\t\tbuf[12] = 0x71;\n\t\t\tbe16enc(&buf[18], 2);\n\t\t\tbe16enc(&buf[20], 512);\n\t\t\twrite_prdt(p, slot, cfis, buf, len);\n\t\t\ttfd = ATA_S_READY | ATA_S_DSC;\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tgoto error;\n\t\t}\n\t\tbreak;\n\tcase 3:\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x39;\n\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\nerror:\n\tcase 1:\n\tcase 2:\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x24;\n\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\n\t}\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\tahci_write_fis_d2h(p, slot, cfis, tfd);\n}\n\nstatic void\natapi_get_event_status_notification(struct ahci_port *p, int slot,\n    uint8_t *cfis)\n{\n\tuint8_t *acmd;\n\tuint32_t tfd;\n\n\tacmd = cfis + 0x40;\n\n\t/* we don't support asynchronous operation */\n\tif (!(acmd[1] & 1)) {\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x24;\n\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t} else {\n\t\tuint8_t buf[8];\n\t\tint len;\n\n\t\tlen = be16dec(acmd + 7);\n\t\tif (((size_t) len) > sizeof(buf)) {\n\t\t\tlen = sizeof(buf);\n\t\t}\n\n\t\tmemset(buf, 0, sizeof(buf));\n\t\tbe16enc(buf, 8 - 2);\n\t\tbuf[2] = 0x04;\n\t\tbuf[3] = 0x10;\n\t\tbuf[5] = 0x02;\n\t\twrite_prdt(p, slot, cfis, buf, len);\n\t\ttfd = ATA_S_READY | ATA_S_DSC;\n\t}\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\tahci_write_fis_d2h(p, slot, cfis, tfd);\n}\n\nstatic void\nhandle_packet_cmd(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\tuint8_t *acmd;\n\n\tacmd = cfis + 0x40;\n\n#ifdef AHCI_DEBUG\n\t{\n\t\tint i;\n\t\tDPRINTF(\"ACMD:\");\n\t\tfor (i = 0; i < 16; i++)\n\t\t\tDPRINTF(\"%02x \", acmd[i]);\n\t\tDPRINTF(\"\\n\");\n\t}\n#endif\n\n\tswitch (acmd[0]) {\n\tcase TEST_UNIT_READY:\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\tbreak;\n\tcase INQUIRY:\n\t\tatapi_inquiry(p, slot, cfis);\n\t\tbreak;\n\tcase READ_CAPACITY:\n\t\tatapi_read_capacity(p, slot, cfis);\n\t\tbreak;\n\tcase PREVENT_ALLOW:\n\t\t/* TODO */\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\tbreak;\n\tcase READ_TOC:\n\t\tatapi_read_toc(p, slot, cfis);\n\t\tbreak;\n\tcase REPORT_LUNS:\n\t\tatapi_report_luns(p, slot, cfis);\n\t\tbreak;\n\tcase READ_10:\n\tcase READ_12:\n\t\tatapi_read(p, slot, cfis, 0);\n\t\tbreak;\n\tcase REQUEST_SENSE:\n\t\tatapi_request_sense(p, slot, cfis);\n\t\tbreak;\n\tcase START_STOP_UNIT:\n\t\tatapi_start_stop_unit(p, slot, cfis);\n\t\tbreak;\n\tcase MODE_SENSE_10:\n\t\tatapi_mode_sense(p, slot, cfis);\n\t\tbreak;\n\tcase GET_EVENT_STATUS_NOTIFICATION:\n\t\tatapi_get_event_status_notification(p, slot, cfis);\n\t\tbreak;\n\tdefault:\n\t\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x20;\n\t\tahci_write_fis_d2h(p, slot, cfis, ((uint32_t) (p->sense_key << 12)) |\n\t\t\t((uint32_t) (ATA_S_READY | ATA_S_ERROR)));\n\t\tbreak;\n\t}\n}\n\nstatic void\nahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)\n{\n\n\tp->tfd |= ATA_S_BUSY;\n\tswitch (cfis[2]) {\n\tcase ATA_ATA_IDENTIFY:\n\t\thandle_identify(p, slot, cfis);\n\t\tbreak;\n\tcase ATA_SETFEATURES:\n\t{\n\t\tswitch (cfis[3]) {\n\t\tcase ATA_SF_ENAB_SATA_SF:\n\t\t\tswitch (cfis[12]) {\n\t\t\tcase ATA_SATA_SF_AN:\n\t\t\t\tp->tfd = ATA_S_DSC | ATA_S_READY;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tp->tfd = ATA_S_ERROR | ATA_S_READY;\n\t\t\t\tp->tfd |= (ATA_ERROR_ABORT << 8);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase ATA_SF_ENAB_WCACHE:\n\t\tcase ATA_SF_DIS_WCACHE:\n\t\tcase ATA_SF_ENAB_RCACHE:\n\t\tcase ATA_SF_DIS_RCACHE:\n\t\t\tp->tfd = ATA_S_DSC | ATA_S_READY;\n\t\t\tbreak;\n\t\tcase ATA_SF_SETXFER:\n\t\t{\n\t\t\tswitch (cfis[12] & 0xf8) {\n\t\t\tcase ATA_PIO:\n\t\t\tcase ATA_PIO0:\n\t\t\t\tbreak;\n\t\t\tcase ATA_WDMA0:\n\t\t\tcase ATA_UDMA0:\n\t\t\t\tp->xfermode = (cfis[12] & 0x7);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tp->tfd = ATA_S_DSC | ATA_S_READY;\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tp->tfd = ATA_S_ERROR | ATA_S_READY;\n\t\t\tp->tfd |= (ATA_ERROR_ABORT << 8);\n\t\t\tbreak;\n\t\t}\n\t\tahci_write_fis_d2h(p, slot, cfis, p->tfd);\n\t\tbreak;\n\t}\n\tcase ATA_SET_MULTI:\n\t\tif (cfis[12] != 0 &&\n\t\t\t(cfis[12] > 128 || (cfis[12] & (cfis[12] - 1)))) {\n\t\t\tp->tfd = ATA_S_ERROR | ATA_S_READY;\n\t\t\tp->tfd |= (ATA_ERROR_ABORT << 8);\n\t\t} else {\n\t\t\tp->mult_sectors = cfis[12];\n\t\t\tp->tfd = ATA_S_DSC | ATA_S_READY;\n\t\t}\n\t\tahci_write_fis_d2h(p, slot, cfis, p->tfd);\n\t\tbreak;\n\tcase ATA_READ:\n\tcase ATA_WRITE:\n\tcase ATA_READ48:\n\tcase ATA_WRITE48:\n\tcase ATA_READ_MUL:\n\tcase ATA_WRITE_MUL:\n\tcase ATA_READ_MUL48:\n\tcase ATA_WRITE_MUL48:\n\tcase ATA_READ_DMA:\n\tcase ATA_WRITE_DMA:\n\tcase ATA_READ_DMA48:\n\tcase ATA_WRITE_DMA48:\n\tcase ATA_READ_FPDMA_QUEUED:\n\tcase ATA_WRITE_FPDMA_QUEUED:\n\t\tahci_handle_rw(p, slot, cfis, 0);\n\t\tbreak;\n\tcase ATA_FLUSHCACHE:\n\tcase ATA_FLUSHCACHE48:\n\t\tahci_handle_flush(p, slot, cfis);\n\t\tbreak;\n\tcase ATA_DATA_SET_MANAGEMENT:\n\t\tif (cfis[11] == 0 && cfis[3] == ATA_DSM_TRIM &&\n\t\t    cfis[13] == 0 && cfis[12] == 1) {\n\t\t\tahci_handle_dsm_trim(p, slot, cfis, 0);\n\t\t\tbreak;\n\t\t}\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\n\tcase ATA_SEND_FPDMA_QUEUED:\n\t\tif ((cfis[13] & 0x1f) == ATA_SFPDMA_DSM &&\n\t\t    cfis[17] == 0 && cfis[16] == ATA_DSM_TRIM &&\n\t\t    cfis[11] == 0 && cfis[13] == 1) {\n\t\t\tahci_handle_dsm_trim(p, slot, cfis, 0);\n\t\t\tbreak;\n\t\t}\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\n\tcase ATA_READ_LOG_EXT:\n\tcase ATA_READ_LOG_DMA_EXT:\n\t\tahci_handle_read_log(p, slot, cfis);\n\t\tbreak;\n\tcase ATA_NOP:\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\n\tcase ATA_STANDBY_CMD:\n\tcase ATA_STANDBY_IMMEDIATE:\n\tcase ATA_IDLE_CMD:\n\tcase ATA_IDLE_IMMEDIATE:\n\tcase ATA_SLEEP:\n\t\tahci_write_fis_d2h(p, slot, cfis, ATA_S_READY | ATA_S_DSC);\n\t\tbreak;\n\tcase ATA_ATAPI_IDENTIFY:\n\t\thandle_atapi_identify(p, slot, cfis);\n\t\tbreak;\n\tcase ATA_PACKET_CMD:\n\t\tif (!p->atapi) {\n\t\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t\t} else\n\t\t\thandle_packet_cmd(p, slot, cfis);\n\t\tbreak;\n\tdefault:\n\t\tWPRINTF(\"Unsupported cmd:%02x\\n\", cfis[2]);\n\t\tahci_write_fis_d2h(p, slot, cfis,\n\t\t    (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR);\n\t\tbreak;\n\t}\n}\n\nstatic void\nahci_handle_slot(struct ahci_port *p, int slot)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\tstruct ahci_prdt_entry *prdt;\n\tstruct pci_ahci_softc *sc;\n\tuint8_t *cfis;\n\tint cfl;\n\n\tsc = p->pr_sc;\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\tcfl = (hdr->flags & 0x1f) * 4;\n\tcfis = paddr_guest2host(hdr->ctba,\n\t\t0x80 + hdr->prdtl * sizeof(struct ahci_prdt_entry));\n\tprdt = (struct ahci_prdt_entry *)((void *) (cfis + 0x80));\n\n#ifdef AHCI_DEBUG\n\tDPRINTF(\"\\ncfis:\");\n\tfor (i = 0; i < cfl; i++) {\n\t\tif (i % 10 == 0)\n\t\t\tDPRINTF(\"\\n\");\n\t\tDPRINTF(\"%02x \", cfis[i]);\n\t}\n\tDPRINTF(\"\\n\");\n\n\tfor (i = 0; i < hdr->prdtl; i++) {\n\t\tDPRINTF(\"%d@%08\"PRIx64\"\\n\", prdt->dbc & 0x3fffff, prdt->dba);\n\t\tprdt++;\n\t}\n#endif\n\n\tif (cfis[0] != FIS_TYPE_REGH2D) {\n\t\tWPRINTF(\"Not a H2D FIS:%02x\\n\", cfis[0]);\n\t\treturn;\n\t}\n\n\tif (cfis[1] & 0x80) {\n\t\tahci_handle_cmd(p, slot, cfis);\n\t} else {\n\t\tif (cfis[15] & (1 << 2))\n\t\t\tp->reset = 1;\n\t\telse if (p->reset) {\n\t\t\tp->reset = 0;\n\t\t\tahci_port_reset(p);\n\t\t}\n\t\tp->ci &= ~(1 << slot);\n\t}\n}\n\nstatic void\nahci_handle_port(struct ahci_port *p)\n{\n\n\tif (!(p->cmd & AHCI_P_CMD_ST))\n\t\treturn;\n\n\t/*\n\t * Search for any new commands to issue ignoring those that\n\t * are already in-flight.  Stop if device is busy or in error.\n\t */\n\tfor (; (p->ci & ~p->pending) != 0; p->ccs = ((p->ccs + 1) & 31)) {\n\t\tif ((p->tfd & (ATA_S_BUSY | ATA_S_DRQ)) != 0)\n\t\t\tbreak;\n\t\tif (p->waitforclear)\n\t\t\tbreak;\n\t\tif ((p->ci & ~p->pending & (1 << p->ccs)) != 0) {\n\t\t\tp->cmd &= ~((unsigned) AHCI_P_CMD_CCS_MASK);\n\t\t\tp->cmd |= p->ccs << AHCI_P_CMD_CCS_SHIFT;\n\t\t\tahci_handle_slot(p, ((int) p->ccs));\n\t\t}\n\t}\n}\n\n/*\n * blockif callback routine - this runs in the context of the blockif\n * i/o thread, so the mutex needs to be acquired.\n */\nstatic void\nata_ioreq_cb(struct blockif_req *br, int err)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\tstruct ahci_ioreq *aior;\n\tstruct ahci_port *p;\n\tstruct pci_ahci_softc *sc;\n\tuint32_t tfd;\n\tuint8_t *cfis;\n\tint slot, ncq, dsm;\n\n\tDPRINTF(\"%s %d\\n\", __func__, err);\n\n\tncq = dsm = 0;\n\taior = br->br_param;\n\tp = aior->io_pr;\n\tcfis = aior->cfis;\n\tslot = aior->slot;\n\tsc = p->pr_sc;\n\thdr = (struct ahci_cmd_hdr *)((void *) (p->cmd_lst + slot * AHCI_CL_SIZE));\n\n\tif (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||\n\t    cfis[2] == ATA_READ_FPDMA_QUEUED ||\n\t    cfis[2] == ATA_SEND_FPDMA_QUEUED)\n\t\tncq = 1;\n\tif (cfis[2] == ATA_DATA_SET_MANAGEMENT ||\n\t    (cfis[2] == ATA_SEND_FPDMA_QUEUED &&\n\t     (cfis[13] & 0x1f) == ATA_SFPDMA_DSM))\n\t\tdsm = 1;\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\t/*\n\t * Delete the blockif request from the busy list\n\t */\n\tTAILQ_REMOVE(&p->iobhd, aior, io_blist);\n\n\t/*\n\t * Move the blockif request back to the free list\n\t */\n\tSTAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);\n\n\tif (!err)\n\t\thdr->prdbc = aior->done;\n\n\tif (!err && aior->more) {\n\t\tif (dsm)\n\t\t\tahci_handle_dsm_trim(p, slot, cfis, aior->done);\n\t\telse \n\t\t\tahci_handle_rw(p, slot, cfis, aior->done);\n\t\tgoto out;\n\t}\n\n\tif (!err)\n\t\ttfd = ATA_S_READY | ATA_S_DSC;\n\telse\n\t\ttfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;\n\tif (ncq)\n\t\tahci_write_fis_sdb(p, slot, cfis, tfd);\n\telse\n\t\tahci_write_fis_d2h(p, slot, cfis, tfd);\n\n\t/*\n\t * This command is now complete.\n\t */\n\tp->pending &= ~(1 << slot);\n\n\tahci_check_stopped(p);\n\tahci_handle_port(p);\nout:\n\tpthread_mutex_unlock(&sc->mtx);\n\tDPRINTF(\"%s exit\\n\", __func__);\n}\n\nstatic void\natapi_ioreq_cb(struct blockif_req *br, int err)\n{\n\tstruct ahci_cmd_hdr *hdr;\n\tstruct ahci_ioreq *aior;\n\tstruct ahci_port *p;\n\tstruct pci_ahci_softc *sc;\n\tuint8_t *cfis;\n\tuint32_t tfd;\n\tint slot;\n\n\tDPRINTF(\"%s %d\\n\", __func__, err);\n\n\taior = br->br_param;\n\tp = aior->io_pr;\n\tcfis = aior->cfis;\n\tslot = aior->slot;\n\tsc = p->pr_sc;\n\thdr = (struct ahci_cmd_hdr *)\n\t\t((void *) (p->cmd_lst + aior->slot * AHCI_CL_SIZE));\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\t/*\n\t * Delete the blockif request from the busy list\n\t */\n\tTAILQ_REMOVE(&p->iobhd, aior, io_blist);\n\n\t/*\n\t * Move the blockif request back to the free list\n\t */\n\tSTAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);\n\n\tif (!err)\n\t\thdr->prdbc = aior->done;\n\n\tif (!err && aior->more) {\n\t\tatapi_read(p, slot, cfis, aior->done);\n\t\tgoto out;\n\t}\n\n\tif (!err) {\n\t\ttfd = ATA_S_READY | ATA_S_DSC;\n\t} else {\n\t\tp->sense_key = ATA_SENSE_ILLEGAL_REQUEST;\n\t\tp->asc = 0x21;\n\t\ttfd = (uint32_t) ((p->sense_key << 12) | ATA_S_READY | ATA_S_ERROR);\n\t}\n\tcfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;\n\tahci_write_fis_d2h(p, slot, cfis, tfd);\n\n\t/*\n\t * This command is now complete.\n\t */\n\tp->pending &= ~(1 << slot);\n\n\tahci_check_stopped(p);\n\tahci_handle_port(p);\nout:\n\tpthread_mutex_unlock(&sc->mtx);\n\tDPRINTF(\"%s exit\\n\", __func__);\n}\n\nstatic void\npci_ahci_ioreq_init(struct ahci_port *pr)\n{\n\tstruct ahci_ioreq *vr;\n\tint i;\n\n\tpr->ioqsz = blockif_queuesz(pr->bctx);\n\tpr->ioreq = calloc(((size_t) pr->ioqsz), sizeof(struct ahci_ioreq));\n\tSTAILQ_INIT(&pr->iofhd);\n\n\t/*\n\t * Add all i/o request entries to the free queue\n\t */\n\tfor (i = 0; i < pr->ioqsz; i++) {\n\t\tvr = &pr->ioreq[i];\n\t\tvr->io_pr = pr;\n\t\tif (!pr->atapi)\n\t\t\tvr->io_req.br_callback = ata_ioreq_cb;\n\t\telse\n\t\t\tvr->io_req.br_callback = atapi_ioreq_cb;\n\t\tvr->io_req.br_param = vr;\n\t\tSTAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist);\n\t}\n\n\tTAILQ_INIT(&pr->iobhd);\n}\n\nstatic void\npci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)\n{\n\tint port = (int) ((offset - AHCI_OFFSET) / AHCI_STEP);\n\toffset = (offset - AHCI_OFFSET) % AHCI_STEP;\n\tstruct ahci_port *p = &sc->port[port];\n\n\tDPRINTF(\"pci_ahci_port %d: write offset 0x%\"PRIx64\" value 0x%\"PRIx64\"\\n\",\n\t\tport, offset, value);\n\n\tswitch (offset) {\n\tcase AHCI_P_CLB:\n\t\tp->clb = (uint32_t) value;\n\t\tbreak;\n\tcase AHCI_P_CLBU:\n\t\tp->clbu = (uint32_t) value;\n\t\tbreak;\n\tcase AHCI_P_FB:\n\t\tp->fb = (uint32_t) value;\n\t\tbreak;\n\tcase AHCI_P_FBU:\n\t\tp->fbu = (uint32_t) value;\n\t\tbreak;\n\tcase AHCI_P_IS:\n\t\tp->is &= ~value;\n\t\tbreak;\n\tcase AHCI_P_IE:\n\t\tp->ie = value & 0xFDC000FF;\n\t\tahci_generate_intr(sc);\n\t\tbreak;\n\tcase AHCI_P_CMD:\n\t{\n\t\tp->cmd &= ~(AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD |\n\t\t    AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE |\n\t\t    AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE |\n\t\t    AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK);\n\t\tp->cmd |= (AHCI_P_CMD_ST | AHCI_P_CMD_SUD | AHCI_P_CMD_POD |\n\t\t    AHCI_P_CMD_CLO | AHCI_P_CMD_FRE | AHCI_P_CMD_APSTE |\n\t\t    AHCI_P_CMD_ATAPI | AHCI_P_CMD_DLAE | AHCI_P_CMD_ALPE |\n\t\t    AHCI_P_CMD_ASP | AHCI_P_CMD_ICC_MASK) & value;\n\n\t\tif (!(value & AHCI_P_CMD_ST)) {\n\t\t\tahci_port_stop(p);\n\t\t} else {\n\t\t\tuint64_t clb;\n\n\t\t\tp->cmd |= AHCI_P_CMD_CR;\n\t\t\tclb = (uint64_t)p->clbu << 32 | p->clb;\n\t\t\tp->cmd_lst = paddr_guest2host(clb, AHCI_CL_SIZE * AHCI_MAX_SLOTS);\n\t\t}\n\n\t\tif (value & AHCI_P_CMD_FRE) {\n\t\t\tuint64_t fb;\n\n\t\t\tp->cmd |= AHCI_P_CMD_FR;\n\t\t\tfb = (uint64_t)p->fbu << 32 | p->fb;\n\t\t\t/* we don't support FBSCP, so rfis size is 256Bytes */\n\t\t\tp->rfis = paddr_guest2host(fb, 256);\n\t\t} else {\n\t\t\tp->cmd &= ~((unsigned) AHCI_P_CMD_FR);\n\t\t}\n\n\t\tif (value & AHCI_P_CMD_CLO) {\n\t\t\tp->tfd &= ~((unsigned) (ATA_S_BUSY | ATA_S_DRQ));\n\t\t\tp->cmd &= ~((unsigned) AHCI_P_CMD_CLO);\n\t\t}\n\n\t\tif (value & AHCI_P_CMD_ICC_MASK) {\n\t\t\tp->cmd &= ~AHCI_P_CMD_ICC_MASK;\n\t\t}\n\n\t\tahci_handle_port(p);\n\t\tbreak;\n\t}\n\tcase AHCI_P_TFD:\n\tcase AHCI_P_SIG:\n\tcase AHCI_P_SSTS:\n\t\tWPRINTF(\"pci_ahci_port: read only registers 0x%\"PRIx64\"\\n\", offset);\n\t\tbreak;\n\tcase AHCI_P_SCTL:\n\t\tp->sctl = (uint32_t) value;\n\t\tif (!(p->cmd & AHCI_P_CMD_ST)) {\n\t\t\tif (value & ATA_SC_DET_RESET)\n\t\t\t\tahci_port_reset(p);\n\t\t}\n\t\tbreak;\n\tcase AHCI_P_SERR:\n\t\tp->serr &= ~value;\n\t\tbreak;\n\tcase AHCI_P_SACT:\n\t\tp->sact |= value;\n\t\tbreak;\n\tcase AHCI_P_CI:\n\t\tp->ci |= value;\n\t\tahci_handle_port(p);\n\t\tbreak;\n\tcase AHCI_P_SNTF:\n\tcase AHCI_P_FBS:\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic void\npci_ahci_host_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)\n{\n\tDPRINTF(\"pci_ahci_host: write offset 0x%\"PRIx64\" value 0x%\"PRIx64\"\\n\",\n\t\toffset, value);\n\n\tswitch (offset) {\n\tcase AHCI_CAP:\n\tcase AHCI_PI:\n\tcase AHCI_VS:\n\tcase AHCI_CAP2:\n\t\tDPRINTF(\"pci_ahci_host: read only registers 0x%\"PRIx64\"\\n\", offset);\n\t\tbreak;\n\tcase AHCI_GHC:\n\t\tif (value & AHCI_GHC_HR)\n\t\t\tahci_reset(sc);\n\t\telse if (value & AHCI_GHC_IE) {\n\t\t\tsc->ghc |= AHCI_GHC_IE;\n\t\t\tahci_generate_intr(sc);\n\t\t}\n\t\tbreak;\n\tcase AHCI_IS:\n\t\tsc->is &= ~value;\n\t\tahci_generate_intr(sc);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic void\npci_ahci_write(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size, uint64_t value)\n{\n\tstruct pci_ahci_softc *sc = pi->pi_arg;\n\n\tassert(baridx == 5);\n\tassert((offset % 4) == 0 && size == 4);\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\tif (offset < AHCI_OFFSET)\n\t\tpci_ahci_host_write(sc, offset, value);\n\telse if (offset < ((uint64_t) (AHCI_OFFSET + (sc->ports * AHCI_STEP))))\n\t\tpci_ahci_port_write(sc, offset, value);\n\telse\n\t\tWPRINTF(\"pci_ahci: unknown i/o write offset 0x%\"PRIx64\"\\n\", offset);\n\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\nstatic uint64_t\npci_ahci_host_read(struct pci_ahci_softc *sc, uint64_t offset)\n{\n\tuint32_t value;\n\n\tswitch (offset) {\n\tcase AHCI_CAP:\n\tcase AHCI_GHC:\n\tcase AHCI_IS:\n\tcase AHCI_PI:\n\tcase AHCI_VS:\n\tcase AHCI_CCCC:\n\tcase AHCI_CCCP:\n\tcase AHCI_EM_LOC:\n\tcase AHCI_EM_CTL:\n\tcase AHCI_CAP2:\n\t{\n\t\tuint32_t *p = &sc->cap;\n\t\tp += (offset - AHCI_CAP) / sizeof(uint32_t);\n\t\tvalue = *p;\n\t\tbreak;\n\t}\n\tdefault:\n\t\tvalue = 0;\n\t\tbreak;\n\t}\n\tDPRINTF(\"pci_ahci_host: read offset 0x%\"PRIx64\" value 0x%x\\n\",\n\t\toffset, value);\n\n\treturn (value);\n}\n\nstatic uint64_t\npci_ahci_port_read(struct pci_ahci_softc *sc, uint64_t offset)\n{\n\tuint32_t value;\n\tint port = (int) ((offset - AHCI_OFFSET) / AHCI_STEP);\n\toffset = (offset - AHCI_OFFSET) % AHCI_STEP;\n\n\tswitch (offset) {\n\tcase AHCI_P_CLB:\n\tcase AHCI_P_CLBU:\n\tcase AHCI_P_FB:\n\tcase AHCI_P_FBU:\n\tcase AHCI_P_IS:\n\tcase AHCI_P_IE:\n\tcase AHCI_P_CMD:\n\tcase AHCI_P_TFD:\n\tcase AHCI_P_SIG:\n\tcase AHCI_P_SSTS:\n\tcase AHCI_P_SCTL:\n\tcase AHCI_P_SERR:\n\tcase AHCI_P_SACT:\n\tcase AHCI_P_CI:\n\tcase AHCI_P_SNTF:\n\tcase AHCI_P_FBS:\n\t{\n\t\tuint32_t *p= &sc->port[port].clb;\n\t\tp += (offset - AHCI_P_CLB) / sizeof(uint32_t);\n\t\tvalue = *p;\n\t\tbreak;\n\t}\n\tdefault:\n\t\tvalue = 0;\n\t\tbreak;\n\t}\n\n\tDPRINTF(\"pci_ahci_port %d: read offset 0x%\"PRIx64\" value 0x%x\\n\",\n\t\tport, offset, value);\n\n\treturn value;\n}\n\nstatic uint64_t\npci_ahci_read(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t regoff, int size)\n{\n\tstruct pci_ahci_softc *sc = pi->pi_arg;\n\tuint64_t offset;\n\tuint32_t value;\n\n\tassert(baridx == 5);\n\tassert(size == 1 || size == 2 || size == 4);\n\tassert((regoff & ((uint64_t) (size - 1))) == 0);\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\t/* round down to a multiple of 4 bytes */\n\toffset = regoff & ~((uint64_t) 0x3);\n\tif (offset < AHCI_OFFSET)\n\t\tvalue = (uint32_t) pci_ahci_host_read(sc, offset);\n\telse if (offset < ((uint64_t) (AHCI_OFFSET + (sc->ports * AHCI_STEP))))\n\t\tvalue = (uint32_t) pci_ahci_port_read(sc, offset);\n\telse {\n\t\tvalue = 0;\n\t\tWPRINTF(\"pci_ahci: unknown i/o read offset 0x%\"PRIx64\"\\n\",\n\t\t    regoff);\n\t}\n\tvalue >>= 8 * (regoff & 0x3);\n\n\tpthread_mutex_unlock(&sc->mtx);\n\n\treturn (value);\n}\n\nstatic int\npci_ahci_init(struct pci_devinst *pi, char *opts, int atapi)\n{\n\tchar bident[sizeof(\"XX:X:X\")];\n\tstruct blockif_ctxt *bctxt;\n\tstruct pci_ahci_softc *sc;\n\tint ret, slots;\n\tu_char digest[CC_SHA256_DIGEST_LENGTH];\n\n\tret = 0;\n\n\tif (opts == NULL) {\n\t\tfprintf(stderr, \"pci_ahci: backing device required\\n\");\n\t\treturn (1);\n\t}\n\n#ifdef AHCI_DEBUG\n\tdbg = fopen(\"/tmp/log\", \"w+\");\n#endif\n\n\tsc = calloc(1, sizeof(struct pci_ahci_softc));\n\tpi->pi_arg = sc;\n\tsc->asc_pi = pi;\n\tsc->ports = MAX_PORTS;\n\n\t/*\n\t * Only use port 0 for a backing device. All other ports will be\n\t * marked as unused\n\t */\n\tsc->port[0].atapi = atapi;\n\n\t/*\n\t * Attempt to open the backing image. Use the PCI\n\t * slot/func for the identifier string.\n\t */\n\tsnprintf(bident, sizeof(bident), \"%d:%d\", pi->pi_slot, pi->pi_func);\n\tbctxt = blockif_open(opts, bident);\n\tif (bctxt == NULL) {       \t\n\t\tret = 1;\n\t\tgoto open_fail;\n\t}\t\n\tsc->port[0].bctx = bctxt;\n\tsc->port[0].pr_sc = sc;\n\n\t/*\n\t * Create an identifier for the backing file. Use parts of the\n\t * md5 sum of the filename\n\t */\n    CC_SHA256(opts, (CC_LONG)strlen(opts), digest);\n    snprintf(sc->port[0].ident, AHCI_PORT_IDENT, \"BHYVE-%02X%02X-%02X%02X-%02X%02X\",\n\t    digest[0], digest[1], digest[2], digest[3], digest[4], digest[5]);\n\n\t/*\n\t * Allocate blockif request structures and add them\n\t * to the free list\n\t */\n\tpci_ahci_ioreq_init(&sc->port[0]);\n\n\tpthread_mutex_init(&sc->mtx, NULL);\n\n\t/* Intel ICH8 AHCI */\n\tslots = sc->port[0].ioqsz;\n\tif (slots > 32)\n\t\tslots = 32;\n\t--slots;\n\tsc->cap = AHCI_CAP_64BIT | AHCI_CAP_SNCQ | AHCI_CAP_SSNTF |\n\t    AHCI_CAP_SMPS | AHCI_CAP_SSS | AHCI_CAP_SALP |\n\t    AHCI_CAP_SAL | AHCI_CAP_SCLO | (0x3 << AHCI_CAP_ISS_SHIFT)|\n\t    AHCI_CAP_PMD | AHCI_CAP_SSC | AHCI_CAP_PSC |\n\t    (((unsigned) slots) << AHCI_CAP_NCS_SHIFT) | AHCI_CAP_SXS |\n\t    (((unsigned) sc->ports) - 1);\n\n\t/* Only port 0 implemented */\n\tsc->pi = 1;\n\tsc->vs = 0x10300;\n\tsc->cap2 = AHCI_CAP2_APST;\n\tahci_reset(sc);\n\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, 0x2821);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, 0x8086);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);\n\tpci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_STORAGE_SATA);\n\tpci_set_cfgdata8(pi, PCIR_PROGIF, PCIP_STORAGE_SATA_AHCI_1_0);\n\tpci_emul_add_msicap(pi, 1);\n\tpci_emul_alloc_bar(pi, 5, PCIBAR_MEM32,\n\t\t((uint64_t) (AHCI_OFFSET + sc->ports * AHCI_STEP)));\n\n\tpci_lintr_request(pi);\n\nopen_fail:\n\tif (ret) {\n\t\tif (sc->port[0].bctx != NULL)\n\t\t\tblockif_close(sc->port[0].bctx);\n\t\tfree(sc);\n\t}\n\n\treturn (ret);\n}\n\nstatic int\npci_ahci_hd_init(struct pci_devinst *pi, char *opts)\n{\n\treturn (pci_ahci_init(pi, opts, 0));\n}\n\nstatic int\npci_ahci_atapi_init(struct pci_devinst *pi, char *opts)\n{\n\treturn (pci_ahci_init(pi, opts, 1));\n}\n\n/*\n * Use separate emulation names to distinguish drive and atapi devices\n */\nstatic struct pci_devemu pci_de_ahci_hd = {\n\t.pe_emu =\t\"ahci-hd\",\n\t.pe_init =\tpci_ahci_hd_init,\n\t.pe_barwrite =\tpci_ahci_write,\n\t.pe_barread =\tpci_ahci_read\n};\nPCI_EMUL_SET(pci_de_ahci_hd);\n\nstatic struct pci_devemu pci_de_ahci_cd = {\n\t.pe_emu =\t\"ahci-cd\",\n\t.pe_init =\tpci_ahci_atapi_init,\n\t.pe_barwrite =\tpci_ahci_write,\n\t.pe_barread =\tpci_ahci_read\n};\nPCI_EMUL_SET(pci_de_ahci_cd);\n"
  },
  {
    "path": "src/pci_e82545.c",
    "content": "/*\n * Copyright (c) 2016 Alexander Motin <mav@FreeBSD.org>\n * Copyright (c) 2015 Peter Grehan <grehan@freebsd.org>\n * Copyright (c) 2013 Jeremiah Lott, Avere Systems\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer\n *    in this position and unchanged.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n#include <machine/limits.h>\n#include <sys/ioctl.h>\n#include <sys/uio.h>\n#include <net/ethernet.h>\n#include <netinet/in.h>\n#include <netinet/tcp.h>\n\n#include <err.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sysexits.h>\n#include <unistd.h>\n#include <pthread.h>\n\n#include <dispatch/dispatch.h>\n#include <vmnet/vmnet.h>\n\n#include <xhyve/xhyve.h>\n\n#include <xhyve/support/misc.h>\n\n#include <xhyve/support/e1000_regs.h>\n#include <xhyve/support/e1000_defines.h>\n#include <xhyve/support/uuid.h>\n\n#include <xhyve/pci_emul.h>\n#include <xhyve/mevent.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-macros\"\n\n/* FreeBSD sys/net/ethernet.h */\n#define    ETHER_VLAN_ENCAP_LEN    4    /* len of 802.1Q VLAN encapsulation */\n\n/* Hardware/register definitions XXX: move some to common code. */\n#define E82545_VENDOR_ID_INTEL\t\t\t0x8086\n#define E82545_DEV_ID_82545EM_COPPER\t\t0x100F\n#define E82545_SUBDEV_ID\t\t\t0x1008\n\n#define E82545_REVISION_4\t\t\t4\n\n#define E82545_MDIC_DATA_MASK\t\t\t0x0000FFFF\n#define E82545_MDIC_OP_MASK\t\t\t0x0c000000\n#define E82545_MDIC_IE\t\t\t\t0x20000000\n\n#define E82545_EECD_FWE_DIS\t0x00000010 /* Flash writes disabled */\n#define E82545_EECD_FWE_EN\t0x00000020 /* Flash writes enabled */\n#define E82545_EECD_FWE_MASK\t0x00000030 /* Flash writes mask */\n\n#define E82545_BAR_REGISTER\t\t\t0\n#define E82545_BAR_REGISTER_LEN\t\t\t(128*1024)\n#define E82545_BAR_FLASH\t\t\t1\n#define E82545_BAR_FLASH_LEN\t\t\t(64*1024)\n#define E82545_BAR_IO\t\t\t\t2\n#define E82545_BAR_IO_LEN\t\t\t8\n\n#define E82545_IOADDR\t\t\t\t0x00000000\n#define E82545_IODATA\t\t\t\t0x00000004\n#define E82545_IO_REGISTER_MAX\t\t\t0x0001FFFF\n\n#define E82545_IO_FLASH_BASE            0x00080000\n#define E82545_IO_FLASH_MAX            0x000FFFFF\n\n#define E82545_ARRAY_ENTRY(reg, offset)        (reg + (offset<<2))\n#define E82545_RAR_MAX                15\n#define E82545_MTA_MAX                127\n#define E82545_VFTA_MAX                127\n\n/* Slightly modified from the driver versions, hardcoded for 3 opcode bits,\n * followed by 6 address bits.\n * TODO: make opcode bits and addr bits configurable?\n * NVM Commands - Microwire */\n#define E82545_NVM_OPCODE_BITS\t3\n#define E82545_NVM_ADDR_BITS\t6\n#define E82545_NVM_DATA_BITS\t16\n#define E82545_NVM_OPADDR_BITS\t(E82545_NVM_OPCODE_BITS + E82545_NVM_ADDR_BITS)\n#define E82545_NVM_ADDR_MASK\t((1 << E82545_NVM_ADDR_BITS)-1)\n#define E82545_NVM_OPCODE_MASK\t\\\n    (((1 << E82545_NVM_OPCODE_BITS) - 1) << E82545_NVM_ADDR_BITS)\n#define E82545_NVM_OPCODE_READ\t(0x6 << E82545_NVM_ADDR_BITS)\t/* read */\n#define E82545_NVM_OPCODE_WRITE\t(0x5 << E82545_NVM_ADDR_BITS)\t/* write */\n#define E82545_NVM_OPCODE_ERASE\t(0x7 << E82545_NVM_ADDR_BITS)\t/* erase */\n#define\tE82545_NVM_OPCODE_EWEN\t(0x4 << E82545_NVM_ADDR_BITS)\t/* wr-enable */\n\n#define\tE82545_NVM_EEPROM_SIZE\t64 /* 64 * 16-bit values == 128K */\n\n#define E1000_ICR_SRPD\t\t0x00010000\n\n/* This is an arbitrary number.  There is no hard limit on the chip. */\n#define I82545_MAX_TXSEGS\t64\n\n#pragma clang diagnostic pop\n\n/* Legacy receive descriptor */\nstruct e1000_rx_desc {\n\tuint64_t buffer_addr;\t/* Address of the descriptor's data buffer */\n\tuint16_t length;\t/* Length of data DMAed into data buffer */\n\tuint16_t csum;\t\t/* Packet checksum */\n\tuint8_t\t status;       \t/* Descriptor status */\n\tuint8_t  errors;\t/* Descriptor Errors */\n\tuint16_t special;\n};\n\n/* Transmit descriptor types */\n#define\tE1000_TXD_MASK\t\t(E1000_TXD_CMD_DEXT | 0x00F00000)\n#define E1000_TXD_TYP_L\t\t(0)\n#define E1000_TXD_TYP_C\t\t(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C)\n#define E1000_TXD_TYP_D\t\t(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)\n\n/* Legacy transmit descriptor */\nstruct e1000_tx_desc {\n\tuint64_t buffer_addr;   /* Address of the descriptor's data buffer */\n\tunion {\n\t\tuint32_t data;\n\t\tstruct {\n\t\t\tuint16_t length;  /* Data buffer length */\n\t\t\tuint8_t  cso;  /* Checksum offset */\n\t\t\tuint8_t  cmd;  /* Descriptor control */\n\t\t} flags;\n\t} lower;\n\tunion {\n\t\tuint32_t data;\n\t\tstruct {\n\t\t\tuint8_t status; /* Descriptor status */\n\t\t\tuint8_t css;  /* Checksum start */\n\t\t\tuint16_t special;\n\t\t} fields;\n\t} upper;\n};\n\n/* Context descriptor */\nstruct e1000_context_desc {\n\tunion {\n\t\tuint32_t ip_config;\n\t\tstruct {\n\t\t\tuint8_t ipcss;  /* IP checksum start */\n\t\t\tuint8_t ipcso;  /* IP checksum offset */\n\t\t\tuint16_t ipcse;  /* IP checksum end */\n\t\t} ip_fields;\n\t} lower_setup;\n\tunion {\n\t\tuint32_t tcp_config;\n\t\tstruct {\n\t\t\tuint8_t tucss;  /* TCP checksum start */\n\t\t\tuint8_t tucso;  /* TCP checksum offset */\n\t\t\tuint16_t tucse;  /* TCP checksum end */\n\t\t} tcp_fields;\n\t} upper_setup;\n\tuint32_t cmd_and_length;\n\tunion {\n\t\tuint32_t data;\n\t\tstruct {\n\t\t\tuint8_t status;  /* Descriptor status */\n\t\t\tuint8_t hdr_len;  /* Header length */\n\t\t\tuint16_t mss;  /* Maximum segment size */\n\t\t} fields;\n\t} tcp_seg_setup;\n};\n\n/* Data descriptor */\nstruct e1000_data_desc {\n\tuint64_t buffer_addr;  /* Address of the descriptor's buffer address */\n\tunion {\n\t\tuint32_t data;\n\t\tstruct {\n\t\t\tuint16_t length;  /* Data buffer length */\n\t\t\tuint8_t typ_len_ext;\n\t\t\tuint8_t cmd;\n\t\t} flags;\n\t} lower;\n\tunion {\n\t\tuint32_t data;\n\t\tstruct {\n\t\t\tuint8_t status;  /* Descriptor status */\n\t\t\tuint8_t popts;  /* Packet Options */\n\t\t\tuint16_t special;\n\t\t} fields;\n\t} upper;\n};\n\nunion e1000_tx_udesc {\n\tstruct e1000_tx_desc td;\n\tstruct e1000_context_desc cd;\n\tstruct e1000_data_desc dd;\n};\n\n/* Tx checksum info for a packet. */\nstruct ck_info {\n\tint\tck_valid;\t/* ck_info is valid */\n\tuint8_t\tck_start;\t/* start byte of cksum calcuation */\n\tuint8_t\tck_off;\t\t/* offset of cksum insertion */\n\tuint16_t ck_len;\t/* length of cksum calc: 0 is to packet-end */\n};\n\n/*\n * Debug printf\n */\nstatic int e82545_debug = 0;\n#define DPRINTF(msg,...) if (e82545_debug) fprintf(stderr, \"e82545: \" msg, __VA_ARGS__)\n#define WPRINTF(msg,...) fprintf(stderr, \"e82545: \" msg, __VA_ARGS__)\n\n#define\tMIN(a,b) (((a)<(b))?(a):(b))\n#define\tMAX(a,b) (((a)>(b))?(a):(b))\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\n/* s/w representation of the RAL/RAH regs */\nstruct  eth_uni {\n\tint\t\teu_valid;\n\tint\t\teu_addrsel;\n\tstruct ether_addr eu_eth;\n};\n\nstruct e82545_softc {\n\tstruct pci_devinst *esc_pi;\n\tstruct mevent   *esc_mevp;\n\tstruct mevent   *esc_mevpitr;\n\tpthread_mutex_t\tesc_mtx;\n    struct vmnet_state *vms;\n\n    /* General */\n\tuint32_t\tesc_CTRL;\t/* x0000 device ctl */\n\tuint32_t\tesc_FCAL;\t/* x0028 flow ctl addr lo */\n\tuint32_t\tesc_FCAH;\t/* x002C flow ctl addr hi */\n\tuint32_t\tesc_FCT;\t/* x0030 flow ctl type */\n\tuint32_t\tesc_VET;\t/* x0038 VLAN eth type */\n\tuint32_t\tesc_FCTTV;\t/* x0170 flow ctl tx timer */\n\tuint32_t\tesc_LEDCTL;\t/* x0E00 LED control */\n\tuint32_t\tesc_PBA;\t/* x1000 pkt buffer allocation */\n\n\t/* Interrupt control */\n\tint\t\tesc_irq_asserted;\n\tuint32_t\tesc_ICR;\t/* x00C0 cause read/clear */\n\tuint32_t\tesc_ITR;\t/* x00C4 intr throttling */\n\tuint32_t\tesc_ICS;\t/* x00C8 cause set */\n\tuint32_t\tesc_IMS;\t/* x00D0 mask set/read */\n\tuint32_t\tesc_IMC;\t/* x00D8 mask clear */\n\n\t/* Transmit */\n\tunion e1000_tx_udesc *esc_txdesc;\n\tstruct e1000_context_desc esc_txctx;\n\tpthread_t\tesc_tx_tid;\n\tpthread_cond_t\tesc_tx_cond;\n\tint\t\tesc_tx_enabled;\n\tint\t\tesc_tx_active;\n\tuint32_t\tesc_TXCW;\t/* x0178 transmit config */\n\tuint32_t\tesc_TCTL;\t/* x0400 transmit ctl */\n\tuint32_t\tesc_TIPG;\t/* x0410 inter-packet gap */\n\tuint16_t\tesc_AIT;\t/* x0458 Adaptive Interframe Throttle */\n\tuint64_t\tesc_tdba;      \t/* verified 64-bit desc table addr */\n\tuint32_t\tesc_TDBAL;\t/* x3800 desc table addr, low bits */\n\tuint32_t\tesc_TDBAH;\t/* x3804 desc table addr, hi 32-bits */\n\tuint32_t\tesc_TDLEN;\t/* x3808 # descriptors in bytes */\n\tuint16_t\tesc_TDH;\t/* x3810 desc table head idx */\n\tuint16_t\tesc_TDHr;\t/* internal read version of TDH */\n\tuint16_t\tesc_TDT;\t/* x3818 desc table tail idx */\n\tuint32_t\tesc_TIDV;\t/* x3820 intr delay */\n\tuint32_t\tesc_TXDCTL;\t/* x3828 desc control */\n\tuint32_t\tesc_TADV;\t/* x382C intr absolute delay */\n\n\t/* L2 frame acceptance */\n\tstruct eth_uni\tesc_uni[16];\t/* 16 x unicast MAC addresses */\n\tuint32_t\tesc_fmcast[128]; /* Multicast filter bit-match */\n\tuint32_t\tesc_fvlan[128]; /* VLAN 4096-bit filter */\n\n\t/* Receive */\n\tstruct e1000_rx_desc *esc_rxdesc;\n\tpthread_cond_t\tesc_rx_cond;\n\tint\t\tesc_rx_enabled;\n\tint\t\tesc_rx_active;\n\tint\t\tesc_rx_loopback;\n\tuint32_t\tesc_RCTL;\t/* x0100 receive ctl */\n\tuint32_t\tesc_FCRTL;\t/* x2160 flow cntl thresh, low */\n\tuint32_t\tesc_FCRTH;\t/* x2168 flow cntl thresh, hi */\n\tuint64_t\tesc_rdba;\t/* verified 64-bit desc table addr */\n\tuint32_t\tesc_RDBAL;\t/* x2800 desc table addr, low bits */\n\tuint32_t\tesc_RDBAH;\t/* x2804 desc table addr, hi 32-bits*/\n\tuint32_t\tesc_RDLEN;\t/* x2808 #descriptors */\n\tuint16_t\tesc_RDH;\t/* x2810 desc table head idx */\n\tuint16_t\tesc_RDT;\t/* x2818 desc table tail idx */\n\tuint32_t\tesc_RDTR;\t/* x2820 intr delay */\n\tuint32_t\tesc_RXDCTL;\t/* x2828 desc control */\n\tuint32_t\tesc_RADV;\t/* x282C intr absolute delay */\n\tuint32_t\tesc_RSRPD;\t/* x2C00 recv small packet detect */\n\tuint32_t\tesc_RXCSUM;     /* x5000 receive cksum ctl */\n\n\t/* IO Port register access */\n\tuint32_t io_addr;\n\n\t/* Shadow copy of MDIC */\n\tuint32_t mdi_control;\n\t/* Shadow copy of EECD */\n\tuint32_t eeprom_control;\n\t/* Latest NVM in/out */\n\tuint16_t nvm_data;\n\tuint16_t nvm_opaddr;\n\t/* stats */\n\tuint32_t missed_pkt_count; /* dropped for no room in rx queue */\n\tuint32_t pkt_rx_by_size[6];\n\tuint32_t pkt_tx_by_size[6];\n\tuint32_t good_pkt_rx_count;\n\tuint32_t bcast_pkt_rx_count;\n\tuint32_t mcast_pkt_rx_count;\n\tuint32_t good_pkt_tx_count;\n\tuint32_t bcast_pkt_tx_count;\n\tuint32_t mcast_pkt_tx_count;\n\tuint32_t oversize_rx_count;\n\tuint32_t tso_tx_count;\n\tuint64_t good_octets_rx;\n\tuint64_t good_octets_tx;\n\tuint64_t missed_octets; /* counts missed and oversized */\n\n\tuint8_t nvm_bits:6; /* number of bits remaining in/out */\n\tuint8_t nvm_mode:2;\n#define E82545_NVM_MODE_OPADDR  0x0\n#define E82545_NVM_MODE_DATAIN  0x1\n#define E82545_NVM_MODE_DATAOUT 0x2\n        /* EEPROM data */\n        uint16_t eeprom_data[E82545_NVM_EEPROM_SIZE];\n};\n\n#pragma clang diagnostic pop\n\nstatic void e82545_reset(struct e82545_softc *sc, int dev);\nstatic void e82545_rx_enable(struct e82545_softc *sc);\nstatic void e82545_rx_disable(struct e82545_softc *sc);\nstatic void e82545_tap_callback(struct e82545_softc *sc);\nstatic void e82545_tx_start(struct e82545_softc *sc);\nstatic void e82545_tx_enable(struct e82545_softc *sc);\nstatic void e82545_tx_disable(struct e82545_softc *sc);\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct vmnet_state {\n    interface_ref iface;\n    uint8_t mac[6];\n    unsigned int mtu;\n    unsigned int max_packet_size;\n};\n\n#pragma clang diagnostic pop\n\n/*\n * Drop privileges according to the CERT Secure C Coding Standard section\n * POS36-C\n * https://www.securecoding.cert.org/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges\n */\nstatic int drop_privileges(void) {\n    // If we are not effectively root, don't drop privileges\n    if (geteuid() != 0 && getegid() != 0) {\n        return 0;\n    }\n    if (setgid(getgid()) == -1) {\n        return -1;\n    }\n    if (setuid(getuid()) == -1) {\n        return -1;\n    }\n    return 0;\n}\n\n/*\n * Create an interface for the guest using Apple's vmnet framework.\n *\n * The interface works in VMNET_SHARED_MODE which allows for packets\n * of the guest to reach other guests and the Internet.\n *\n * See also: https://developer.apple.com/library/mac/documentation/vmnet/Reference/vmnet_Reference/index.html\n */\nstatic int\nvmn_create(struct e82545_softc *sc)\n{\n    xpc_object_t interface_desc;\n    uuid_t uuid;\n    __block interface_ref iface;\n    __block vmnet_return_t iface_status;\n    dispatch_semaphore_t iface_created;\n    dispatch_queue_t if_create_q;\n    dispatch_queue_t if_q;\n    struct vmnet_state *vms;\n    uint32_t uuid_status;\n\n    interface_desc = xpc_dictionary_create(NULL, NULL, 0);\n    xpc_dictionary_set_uint64(interface_desc, vmnet_operation_mode_key,\n                              VMNET_SHARED_MODE);\n\n    if (guest_uuid_str != NULL) {\n        uuid_from_string(guest_uuid_str, &uuid, &uuid_status);\n        if (uuid_status != uuid_s_ok) {\n            return (-1);\n        }\n    } else {\n        uuid_generate_random(uuid);\n    }\n\n    xpc_dictionary_set_uuid(interface_desc, vmnet_interface_id_key, uuid);\n    iface = NULL;\n    iface_status = 0;\n\n    vms = malloc(sizeof(struct vmnet_state));\n\n    if (!vms) {\n        return (-1);\n    }\n\n    if_create_q = dispatch_queue_create(\"org.xhyve.vmnet.create\",\n                                        DISPATCH_QUEUE_SERIAL);\n\n    iface_created = dispatch_semaphore_create(0);\n\n    iface = vmnet_start_interface(interface_desc, if_create_q,\n                                  ^(vmnet_return_t status, xpc_object_t interface_param)\n                                  {\n                                      iface_status = status;\n                                      if (status != VMNET_SUCCESS || !interface_param) {\n                                          dispatch_semaphore_signal(iface_created);\n                                          return;\n                                      }\n\n                                      if (sscanf(xpc_dictionary_get_string(interface_param,\n                                                                           vmnet_mac_address_key),\n                                                 \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n                                                 &vms->mac[0], &vms->mac[1], &vms->mac[2], &vms->mac[3],\n                                                 &vms->mac[4], &vms->mac[5]) != 6)\n                                      {\n                                          assert(0);\n                                      }\n\n                                      vms->mtu = (unsigned)xpc_dictionary_get_uint64(interface_param, vmnet_mtu_key);\n                                      vms->max_packet_size = (unsigned)xpc_dictionary_get_uint64(interface_param,\n                                                                                                 vmnet_max_packet_size_key);\n                                      dispatch_semaphore_signal(iface_created);\n                                  });\n\n    dispatch_semaphore_wait(iface_created, DISPATCH_TIME_FOREVER);\n    dispatch_release(if_create_q);\n\n    if (iface == NULL || iface_status != VMNET_SUCCESS) {\n        fprintf(stderr, \"virtio_net: Could not create vmnet interface, \"\n                \"permission denied or no entitlement?\\n\");\n        free(vms);\n        return (-1);\n    }\n\n    vms->iface = iface;\n    sc->vms = vms;\n\n    if_q = dispatch_queue_create(\"org.xhyve.vmnet.iface_q\", 0);\n\n    vmnet_interface_set_event_callback(iface, VMNET_INTERFACE_PACKETS_AVAILABLE,\n                                       if_q, ^(UNUSED interface_event_t event_id, UNUSED xpc_object_t event)\n                                       {\n                                           e82545_tap_callback(sc);\n                                       });\n    if (drop_privileges() == -1) {\n        perror(\"Dropping privileges after networking was enabled.\");\n        free(vms);\n        return (-1);\n    }\n\n    return (0);\n}\n\nstatic ssize_t\nvmn_read(struct vmnet_state *vms, struct iovec *iov, int n) {\n    vmnet_return_t r;\n    struct vmpktdesc v;\n    int pktcnt;\n    int i;\n\n    v.vm_pkt_size = 0;\n\n    for (i = 0; i < n; i++) {\n        v.vm_pkt_size += iov[i].iov_len;\n    }\n\n    assert(v.vm_pkt_size >= vms->max_packet_size);\n\n    v.vm_pkt_iov = iov;\n    v.vm_pkt_iovcnt = (uint32_t) n;\n    v.vm_flags = 0; /* TODO no clue what this is */\n\n    pktcnt = 1;\n\n    r = vmnet_read(vms->iface, &v, &pktcnt);\n\n    assert(r == VMNET_SUCCESS);\n\n    if (pktcnt < 1) {\n        return (-1);\n    }\n\n    return ((ssize_t) v.vm_pkt_size);\n}\n\nstatic void\nvmn_write(struct vmnet_state *vms, struct iovec *iov, int n) {\n    vmnet_return_t r;\n    struct vmpktdesc v;\n    int pktcnt;\n    int i;\n\n    v.vm_pkt_size = 0;\n\n    for (i = 0; i < n; i++) {\n        v.vm_pkt_size += iov[i].iov_len;\n    }\n\n    assert(v.vm_pkt_size <= vms->max_packet_size);\n\n    v.vm_pkt_iov = iov;\n    v.vm_pkt_iovcnt = (uint32_t) n;\n    v.vm_flags = 0; /* TODO no clue what this is */\n\n    pktcnt = 1;\n\n    r = vmnet_write(vms->iface, &v, &pktcnt);\n\n    assert(r == VMNET_SUCCESS);\n}\n\nstatic void\ne82545_init_eeprom(struct e82545_softc *sc)\n{\n\tuint16_t checksum, i;\n\n        /* mac addr */\n\tsc->eeprom_data[NVM_MAC_ADDR] = (uint16_t)((sc->vms->mac[0]) |\n\t\t(sc->vms->mac[1]) << 8);\n\tsc->eeprom_data[NVM_MAC_ADDR+1] = (uint16_t)((sc->vms->mac[2]) |\n\t\t(sc->vms->mac[3] << 8));\n\tsc->eeprom_data[NVM_MAC_ADDR+2] = (uint16_t)((sc->vms->mac[4]) |\n\t\t(sc->vms->mac[5] << 8));\n\n\t/* pci ids */\n\tsc->eeprom_data[NVM_SUB_DEV_ID] = E82545_SUBDEV_ID;\n\tsc->eeprom_data[NVM_SUB_VEN_ID] = E82545_VENDOR_ID_INTEL;\n\tsc->eeprom_data[NVM_DEV_ID] = E82545_DEV_ID_82545EM_COPPER;\n\tsc->eeprom_data[NVM_VEN_ID] = E82545_VENDOR_ID_INTEL;\n\n\t/* fill in the checksum */\n        checksum = 0;\n\tfor (i = 0; i < NVM_CHECKSUM_REG; i++) {\n\t\tchecksum += sc->eeprom_data[i];\n\t}\n\tchecksum = NVM_SUM - checksum;\n\tsc->eeprom_data[NVM_CHECKSUM_REG] = checksum;\n\tDPRINTF(\"eeprom checksum: 0x%x\\r\\n\", checksum);\n}\n\nstatic void\ne82545_write_mdi(UNUSED struct e82545_softc *sc, uint8_t reg_addr,\n\t\t\tuint8_t phy_addr, uint32_t data)\n{\n\tDPRINTF(\"Write mdi reg:0x%x phy:0x%x data: 0x%x\\r\\n\", reg_addr, phy_addr, data);\n}\n\nstatic uint32_t\ne82545_read_mdi(UNUSED struct e82545_softc *sc, uint8_t reg_addr,\n\t\t\tuint8_t phy_addr)\n{\n\t//DPRINTF(\"Read mdi reg:0x%x phy:0x%x\\r\\n\", reg_addr, phy_addr);\n\tswitch (reg_addr) {\n\tcase PHY_STATUS:\n\t\treturn (MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |\n\t\t\tMII_SR_AUTONEG_COMPLETE);\n\tcase PHY_AUTONEG_ADV:\n\t\treturn NWAY_AR_SELECTOR_FIELD;\n\tcase PHY_LP_ABILITY:\n\t\treturn 0;\n\tcase PHY_1000T_STATUS:\n\t\treturn (SR_1000T_LP_FD_CAPS | SR_1000T_REMOTE_RX_STATUS |\n\t\t\tSR_1000T_LOCAL_RX_STATUS);\n\tcase PHY_ID1:\n\t\treturn (M88E1011_I_PHY_ID >> 16) & 0xFFFF;\n\tcase PHY_ID2:\n\t\treturn (M88E1011_I_PHY_ID | E82545_REVISION_4) & 0xFFFF;\n\tdefault:\n\t\tDPRINTF(\"Unknown mdi read reg:0x%x phy:0x%x\\r\\n\", reg_addr, phy_addr);\n\t\treturn 0;\n\t}\n\t/* not reached */\n}\n\nstatic void\ne82545_eecd_strobe(struct e82545_softc *sc)\n{\n\t/* Microwire state machine */\n\t/*\n\tDPRINTF(\"eeprom state machine srtobe \"\n\t\t\"0x%x 0x%x 0x%x 0x%x\\r\\n\",\n\t\tsc->nvm_mode, sc->nvm_bits,\n\t\tsc->nvm_opaddr, sc->nvm_data);*/\n\n\tif (sc->nvm_bits == 0) {\n\t\tDPRINTF(\"eeprom state machine not expecting data! \"\n\t\t\t\"0x%x 0x%x 0x%x 0x%x\\r\\n\",\n\t\t\tsc->nvm_mode, sc->nvm_bits,\n\t\t\tsc->nvm_opaddr, sc->nvm_data);\n\t\treturn;\n\t}\n\tsc->nvm_bits--;\n\tif (sc->nvm_mode == E82545_NVM_MODE_DATAOUT) {\n\t\t/* shifting out */\n\t\tif (sc->nvm_data & 0x8000) {\n\t\t\tsc->eeprom_control |= E1000_EECD_DO;\n\t\t} else {\n\t\t\tsc->eeprom_control &= (uint32_t)~E1000_EECD_DO;\n\t\t}\n\t\tsc->nvm_data <<= 1;\n\t\tif (sc->nvm_bits == 0) {\n\t\t\t/* read done, back to opcode mode. */\n\t\t\tsc->nvm_opaddr = 0;\n\t\t\tsc->nvm_mode = E82545_NVM_MODE_OPADDR;\n\t\t\tsc->nvm_bits = E82545_NVM_OPADDR_BITS;\n\t\t}\n\t} else if (sc->nvm_mode == E82545_NVM_MODE_DATAIN) {\n\t\t/* shifting in */\n\t\tsc->nvm_data <<= 1;\n\t\tif (sc->eeprom_control & E1000_EECD_DI) {\n\t\t\tsc->nvm_data |= 1;\n\t\t}\n\t\tif (sc->nvm_bits == 0) {\n\t\t\t/* eeprom write */\n\t\t\tuint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;\n\t\t\tuint16_t addr = sc->nvm_opaddr & E82545_NVM_ADDR_MASK;\n\t\t\tif (op != E82545_NVM_OPCODE_WRITE) {\n\t\t\t\tDPRINTF(\"Illegal eeprom write op 0x%x\\r\\n\",\n\t\t\t\t\tsc->nvm_opaddr);\n\t\t\t} else if (addr >= E82545_NVM_EEPROM_SIZE) {\n\t\t\t\tDPRINTF(\"Illegal eeprom write addr 0x%x\\r\\n\",\n\t\t\t\t\tsc->nvm_opaddr);\n\t\t\t} else {\n\t\t\t\tDPRINTF(\"eeprom write eeprom[0x%x] = 0x%x\\r\\n\",\n\t\t\t\taddr, sc->nvm_data);\n\t\t\t\tsc->eeprom_data[addr] = sc->nvm_data;\n\t\t\t}\n\t\t\t/* back to opcode mode */\n\t\t\tsc->nvm_opaddr = 0;\n\t\t\tsc->nvm_mode = E82545_NVM_MODE_OPADDR;\n\t\t\tsc->nvm_bits = E82545_NVM_OPADDR_BITS;\n\t\t}\n\t} else if (sc->nvm_mode == E82545_NVM_MODE_OPADDR) {\n\t\tsc->nvm_opaddr <<= 1;\n\t\tif (sc->eeprom_control & E1000_EECD_DI) {\n\t\t\tsc->nvm_opaddr |= 1;\n\t\t}\n\t\tif (sc->nvm_bits == 0) {\n\t\t\tuint16_t op = sc->nvm_opaddr & E82545_NVM_OPCODE_MASK;\n\t\t\tswitch (op) {\n\t\t\tcase E82545_NVM_OPCODE_EWEN:\n\t\t\t\tDPRINTF(\"eeprom write enable: 0x%x\\r\\n\",\n\t\t\t\t\tsc->nvm_opaddr);\n\t\t\t\t/* back to opcode mode */\n\t\t\t\tsc->nvm_opaddr = 0;\n\t\t\t\tsc->nvm_mode = E82545_NVM_MODE_OPADDR;\n\t\t\t\tsc->nvm_bits = E82545_NVM_OPADDR_BITS;\n\t\t\t\tbreak;\n\t\t\tcase E82545_NVM_OPCODE_READ:\n\t\t\t{\n\t\t\t\tuint16_t addr = sc->nvm_opaddr &\n\t\t\t\t\tE82545_NVM_ADDR_MASK;\n\t\t\t\tsc->nvm_mode = E82545_NVM_MODE_DATAOUT;\n\t\t\t\tsc->nvm_bits = E82545_NVM_DATA_BITS;\n\t\t\t\tif (addr < E82545_NVM_EEPROM_SIZE) {\n\t\t\t\t\tsc->nvm_data = sc->eeprom_data[addr];\n\t\t\t\t\tDPRINTF(\"eeprom read: eeprom[0x%x] = 0x%x\\r\\n\",\n\t\t\t\t\t\taddr, sc->nvm_data);\n\t\t\t\t} else {\n\t\t\t\t\tDPRINTF(\"eeprom illegal read: 0x%x\\r\\n\",\n\t\t\t\t\t\tsc->nvm_opaddr);\n\t\t\t\t\tsc->nvm_data = 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase E82545_NVM_OPCODE_WRITE:\n\t\t\t\tsc->nvm_mode = E82545_NVM_MODE_DATAIN;\n\t\t\t\tsc->nvm_bits = E82545_NVM_DATA_BITS;\n\t\t\t\tsc->nvm_data = 0;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tDPRINTF(\"eeprom unknown op: 0x%x\\r\\r\",\n\t\t\t\t\tsc->nvm_opaddr);\n\t\t\t\t/* back to opcode mode */\n\t\t\t\tsc->nvm_opaddr = 0;\n\t\t\t\tsc->nvm_mode = E82545_NVM_MODE_OPADDR;\n\t\t\t\tsc->nvm_bits = E82545_NVM_OPADDR_BITS;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tDPRINTF(\"eeprom state machine wrong state! \"\n\t\t\t\"0x%x 0x%x 0x%x 0x%x\\r\\n\",\n\t\t\tsc->nvm_mode, sc->nvm_bits,\n\t\t\tsc->nvm_opaddr, sc->nvm_data);\n\t}\n}\n\nstatic void\ne82545_itr_callback(UNUSED int fd, UNUSED enum ev_type type, void *param)\n{\n\tuint32_t new;\n\tstruct e82545_softc *sc = param;\n\n\tpthread_mutex_lock(&sc->esc_mtx);\n\tnew = sc->esc_ICR & sc->esc_IMS;\n\tif (new && !sc->esc_irq_asserted) {\n\t\tDPRINTF(\"itr callback: lintr assert %x\\r\\n\", new);\n\t\tsc->esc_irq_asserted = 1;\n\t\tpci_lintr_assert(sc->esc_pi);\n\t} else {\n\t\tmevent_delete(sc->esc_mevpitr);\n\t\tsc->esc_mevpitr = NULL;\n\t}\n\tpthread_mutex_unlock(&sc->esc_mtx);\n}\n\nstatic void\ne82545_icr_assert(struct e82545_softc *sc, uint32_t bits)\n{\n\tuint32_t new;\n\n\tDPRINTF(\"icr assert: 0x%x\\r\\n\", bits);\n\n\t/*\n\t * An interrupt is only generated if bits are set that\n\t * aren't already in the ICR, these bits are unmasked,\n\t * and there isn't an interrupt already pending.\n\t */\n\tnew = bits & ~sc->esc_ICR & sc->esc_IMS;\n\tsc->esc_ICR |= bits;\n\n\tif (new == 0) {\n\t\tDPRINTF(\"icr assert: masked %x, ims %x\\r\\n\", new, sc->esc_IMS);\n\t} else if (sc->esc_mevpitr != NULL) {\n\t\tDPRINTF(\"icr assert: throttled %x, ims %x\\r\\n\", new, sc->esc_IMS);\n\t} else if (!sc->esc_irq_asserted) {\n\t\tDPRINTF(\"icr assert: lintr assert %x\\r\\n\", new);\n\t\tsc->esc_irq_asserted = 1;\n\t\tpci_lintr_assert(sc->esc_pi);\n\t\tif (sc->esc_ITR != 0) {\n\t\t\tsc->esc_mevpitr = mevent_add(\n\t\t\t    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */\n\t\t\t    EVF_TIMER, e82545_itr_callback, sc);\n\t\t}\n\t}\n}\n\nstatic void\ne82545_ims_change(struct e82545_softc *sc, uint32_t bits)\n{\n\tuint32_t new;\n\n\t/*\n\t * Changing the mask may allow previously asserted\n\t * but masked interrupt requests to generate an interrupt.\n\t */\n\tnew = bits & sc->esc_ICR & ~sc->esc_IMS;\n\tsc->esc_IMS |= bits;\n\n\tif (new == 0) {\n\t\tDPRINTF(\"ims change: masked %x, ims %x\\r\\n\", new, sc->esc_IMS);\n\t} else if (sc->esc_mevpitr != NULL) {\n\t\tDPRINTF(\"ims change: throttled %x, ims %x\\r\\n\", new, sc->esc_IMS);\n\t} else if (!sc->esc_irq_asserted) {\n\t\tDPRINTF(\"ims change: lintr assert %x\\n\\r\", new);\n\t\tsc->esc_irq_asserted = 1;\n\t\tpci_lintr_assert(sc->esc_pi);\n\t\tif (sc->esc_ITR != 0) {\n\t\t\tsc->esc_mevpitr = mevent_add(\n\t\t\t    (sc->esc_ITR + 3905) / 3906,  /* 256ns -> 1ms */\n\t\t\t    EVF_TIMER, e82545_itr_callback, sc);\n\t\t}\n\t}\n}\n\nstatic void\ne82545_icr_deassert(struct e82545_softc *sc, uint32_t bits)\n{\n\n\tDPRINTF(\"icr deassert: 0x%x\\r\\n\", bits);\n\tsc->esc_ICR &= ~bits;\n\n\t/*\n\t * If there are no longer any interrupt sources and there\n\t * was an asserted interrupt, clear it\n\t */\n\tif (sc->esc_irq_asserted && !(sc->esc_ICR & sc->esc_IMS)) {\n\t\tDPRINTF(\"icr deassert: lintr deassert %x\\r\\n\", bits);\n\t\tpci_lintr_deassert(sc->esc_pi);\n\t\tsc->esc_irq_asserted = 0;\n\t}\n}\n\nstatic void\ne82545_intr_write(struct e82545_softc *sc, uint32_t offset, uint32_t value)\n{\n\n\tDPRINTF(\"intr_write: off %x, val %x\\n\\r\", offset, value);\n\n\tswitch (offset) {\n\tcase E1000_ICR:\n\t\te82545_icr_deassert(sc, value);\n\t\tbreak;\n\tcase E1000_ITR:\n\t\tsc->esc_ITR = value;\n\t\tbreak;\n\tcase E1000_ICS:\n\t\tsc->esc_ICS = value;\t/* not used: store for debug */\n\t\te82545_icr_assert(sc, value);\n\t\tbreak;\n\tcase E1000_IMS:\n\t\te82545_ims_change(sc, value);\n\t\tbreak;\n\tcase E1000_IMC:\n\t\tsc->esc_IMC = value;\t/* for debug */\n\t\tsc->esc_IMS &= ~value;\n\t\t// XXX clear interrupts if all ICR bits now masked\n\t\t// and interrupt was pending ?\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic uint32_t\ne82545_intr_read(struct e82545_softc *sc, uint32_t offset)\n{\n\tuint32_t retval;\n\n\tretval = 0;\n\n\tDPRINTF(\"intr_read: off %x\\n\\r\", offset);\n\n\tswitch (offset) {\n\tcase E1000_ICR:\n\t\tretval = sc->esc_ICR;\n\t\tsc->esc_ICR = 0;\n\t\te82545_icr_deassert(sc, (uint32_t)~0);\n\t\tbreak;\n\tcase E1000_ITR:\n\t\tretval = sc->esc_ITR;\n\t\tbreak;\n\tcase E1000_ICS:\n\t\t/* write-only register */\n\t\tbreak;\n\tcase E1000_IMS:\n\t\tretval = sc->esc_IMS;\n\t\tbreak;\n\tcase E1000_IMC:\n\t\t/* write-only register */\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn (retval);\n}\n\nstatic void\ne82545_devctl(struct e82545_softc *sc, uint32_t val)\n{\n\n\tsc->esc_CTRL = val & (uint32_t)~E1000_CTRL_RST;\n\n\tif (val & E1000_CTRL_RST) {\n\t\tDPRINTF(\"e1k: s/w reset, ctl %x\\n\", val);\n\t\te82545_reset(sc, 1);\n\t}\n\t/* XXX check for phy reset ? */\n}\n\nstatic void\ne82545_rx_update_rdba(struct e82545_softc *sc)\n{\n\n\t/* XXX verify desc base/len within phys mem range */\n\tsc->esc_rdba = (uint64_t)sc->esc_RDBAH << 32 |\n\t    sc->esc_RDBAL;\n\n\t/* Cache host mapping of guest descriptor array */\n\tsc->esc_rxdesc = paddr_guest2host(sc->esc_rdba, sc->esc_RDLEN);\n}\n\nstatic void\ne82545_rx_ctl(struct e82545_softc *sc, uint32_t val)\n{\n\tint on;\n\n\ton = ((val & E1000_RCTL_EN) == E1000_RCTL_EN);\n\n\t/* Save RCTL after stripping reserved bits 31:27,24,21,14,11:10,0 */\n\tsc->esc_RCTL = val & ~0xF9204c01;\n\n\tDPRINTF(\"rx_ctl - %s RCTL %x, val %x\\n\",\n\t\ton ? \"on\" : \"off\", sc->esc_RCTL, val);\n\n\t/* state change requested */\n\tif (on != sc->esc_rx_enabled) {\n\t\tif (on) {\n\t\t\t/* Catch disallowed/unimplemented settings */\n\t\t\t//assert(!(val & E1000_RCTL_LBM_TCVR));\n\n\t\t\tif (sc->esc_RCTL & E1000_RCTL_LBM_TCVR) {\n\t\t\t\tsc->esc_rx_loopback = 1;\n\t\t\t} else {\n\t\t\t\tsc->esc_rx_loopback = 0;\n\t\t\t}\n\n\t\t\te82545_rx_update_rdba(sc);\n\t\t\te82545_rx_enable(sc);\n\t\t} else {\n\t\t\te82545_rx_disable(sc);\n\t\t\tsc->esc_rx_loopback = 0;\n\t\t\tsc->esc_rdba = 0;\n\t\t\tsc->esc_rxdesc = NULL;\n\t\t}\n\t}\n}\n\nstatic void\ne82545_tx_update_tdba(struct e82545_softc *sc)\n{\n\n\t/* XXX verify desc base/len within phys mem range */\n\tsc->esc_tdba = (uint64_t)sc->esc_TDBAH << 32 | sc->esc_TDBAL;\n\n\t/* Cache host mapping of guest descriptor array */\n\tsc->esc_txdesc = paddr_guest2host(sc->esc_tdba, sc->esc_TDLEN);\n}\n\nstatic void\ne82545_tx_ctl(struct e82545_softc *sc, uint32_t val)\n{\n\tint on;\n\n\ton = ((val & E1000_TCTL_EN) == E1000_TCTL_EN);\n\n\t/* ignore TCTL_EN settings that don't change state */\n\tif (on == sc->esc_tx_enabled)\n\t\treturn;\n\n\tif (on) {\n\t\te82545_tx_update_tdba(sc);\n\t\te82545_tx_enable(sc);\n\t} else {\n\t\te82545_tx_disable(sc);\n\t\tsc->esc_tdba = 0;\n\t\tsc->esc_txdesc = NULL;\n\t}\n\n\t/* Save TCTL value after stripping reserved bits 31:25,23,2,0 */\n\tsc->esc_TCTL = val & ~0xFE800005;\n}\n\nstatic int\ne82545_bufsz(uint32_t rctl)\n{\n\n\tswitch (rctl & (E1000_RCTL_BSEX | E1000_RCTL_SZ_256)) {\n\tcase (E1000_RCTL_SZ_2048): return (2048);\n\tcase (E1000_RCTL_SZ_1024): return (1024);\n\tcase (E1000_RCTL_SZ_512): return (512);\n\tcase (E1000_RCTL_SZ_256): return (256);\n\tcase (E1000_RCTL_BSEX|E1000_RCTL_SZ_16384): return (16384);\n\tcase (E1000_RCTL_BSEX|E1000_RCTL_SZ_8192): return (8192);\n\tcase (E1000_RCTL_BSEX|E1000_RCTL_SZ_4096): return (4096);\n\t}\n\treturn (256);\t/* Forbidden value. */\n}\n\nstatic uint8_t dummybuf[2048];\n\n/* XXX one packet at a time until this is debugged */\nstatic void\ne82545_tap_callback(struct e82545_softc *sc)\n{\n\tstruct e1000_rx_desc *rxd;\n\tstruct iovec vec[64];\n\tint left, len, lim, maxpktsz, maxpktdesc, bufsz, i, n, size;\n\tuint32_t cause = 0;\n\tuint16_t *tp, tag, head;\n\n\tpthread_mutex_lock(&sc->esc_mtx);\n\tDPRINTF(\"rx_run: head %x, tail %x\\r\\n\", sc->esc_RDH, sc->esc_RDT);\n\n\tif (!sc->esc_rx_enabled || sc->esc_rx_loopback) {\n\t\tDPRINTF(\"rx disabled (!%d || %d) -- packet(s) dropped\\r\\n\",\n\t\t    sc->esc_rx_enabled, sc->esc_rx_loopback);\n        vec[0].iov_base = dummybuf;\n        vec[0].iov_len = sizeof(dummybuf);\n        (void) vmn_read(sc->vms, vec, 1);\n\t\tgoto done1;\n\t}\n\tbufsz = e82545_bufsz(sc->esc_RCTL);\n\tmaxpktsz = (sc->esc_RCTL & E1000_RCTL_LPE) ? 16384 : 1522;\n\tmaxpktdesc = (maxpktsz + bufsz - 1) / bufsz;\n\tsize = sc->esc_RDLEN / 16;\n\thead = sc->esc_RDH;\n\tleft = (size + sc->esc_RDT - head) % size;\n\tif (left < maxpktdesc) {\n\t\tDPRINTF(\"rx overflow (%d < %d) -- packet(s) dropped\\r\\n\",\n\t\t    left, maxpktdesc);\n        vec[0].iov_base = dummybuf;\n        vec[0].iov_len = sizeof(dummybuf);\n        (void) vmn_read(sc->vms, vec, 1);\n\t\tgoto done1;\n\t}\n\n\tsc->esc_rx_active = 1;\n\tpthread_mutex_unlock(&sc->esc_mtx);\n\n\tfor (lim = size / 4; lim > 0 && left >= maxpktdesc; lim -= n) {\n\n\t\t/* Grab rx descriptor pointed to by the head pointer */\n\t\tfor (i = 0; i < maxpktdesc; i++) {\n\t\t\trxd = &sc->esc_rxdesc[(head + i) % size];\n\t\t\tvec[i].iov_base = paddr_guest2host(rxd->buffer_addr, (size_t)bufsz);\n\t\t\tvec[i].iov_len = (size_t)bufsz;\n\t\t}\n        len = (int)vmn_read(sc->vms, vec, maxpktdesc);\n\t\tif (len <= 0) {\n\t\t\tDPRINTF(\"tap: readv() returned %d\\n\", len);\n\t\t\tgoto done;\n\t\t}\n\n\t\t/*\n\t\t * Adjust the packet length based on whether the CRC needs\n\t\t * to be stripped or if the packet is less than the minimum\n\t\t * eth packet size.\n\t\t */\n\t\tif (len < ETHER_MIN_LEN - ETHER_CRC_LEN)\n\t\t\tlen = ETHER_MIN_LEN - ETHER_CRC_LEN;\n\t\tif (!(sc->esc_RCTL & E1000_RCTL_SECRC))\n\t\t\tlen += ETHER_CRC_LEN;\n\t\tn = (len + bufsz - 1) / bufsz;\n\n\t\tDPRINTF(\"packet read %d bytes, %d segs, head %d\\r\\n\",\n\t\t    len, n, head);\n\n\t\t/* Apply VLAN filter. */\n\t\ttp = (uint16_t *)vec[0].iov_base + 6;\n\t\tif ((sc->esc_RCTL & E1000_RCTL_VFE) &&\n\t\t    (ntohs(tp[0]) == sc->esc_VET)) {\n\t\t\ttag = ntohs(tp[1]) & 0x0fff;\n\t\t\tif ((sc->esc_fvlan[tag >> 5] &\n\t\t\t    (1 << (tag & 0x1f))) != 0) {\n\t\t\t\tDPRINTF(\"known VLAN %d\\r\\n\", tag);\n\t\t\t} else {\n\t\t\t\tDPRINTF(\"unknown VLAN %d\\r\\n\", tag);\n\t\t\t\tn = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t/* Update all consumed descriptors. */\n\t\tfor (i = 0; i < n - 1; i++) {\n\t\t\trxd = &sc->esc_rxdesc[(head + i) % size];\n\t\t\trxd->length = (uint16_t)bufsz;\n\t\t\trxd->csum = 0;\n\t\t\trxd->errors = 0;\n\t\t\trxd->special = 0;\n\t\t\trxd->status = E1000_RXD_STAT_DD;\n\t\t}\n\t\trxd = &sc->esc_rxdesc[(head + i) % size];\n\t\trxd->length = (uint16_t)(len % bufsz);\n\t\trxd->csum = 0;\n\t\trxd->errors = 0;\n\t\trxd->special = 0;\n\t\t/* XXX signal no checksum for now */\n\t\trxd->status = E1000_RXD_STAT_PIF | E1000_RXD_STAT_IXSM |\n\t\t    E1000_RXD_STAT_EOP | E1000_RXD_STAT_DD;\n\n\t\t/* Schedule receive interrupts. */\n\t\tif (len <= (int)sc->esc_RSRPD) {\n\t\t\tcause |= E1000_ICR_SRPD | E1000_ICR_RXT0;\n\t\t} else {\n\t\t\t/* XXX: RDRT and RADV timers should be here. */\n\t\t\tcause |= E1000_ICR_RXT0;\n\t\t}\n\n\t\thead = (uint16_t)((head + n) % size);\n\t\tleft -= n;\n\t}\n\ndone:\n\tpthread_mutex_lock(&sc->esc_mtx);\n\tsc->esc_rx_active = 0;\n\tif (sc->esc_rx_enabled == 0)\n\t\tpthread_cond_signal(&sc->esc_rx_cond);\n\n\tsc->esc_RDH = head;\n\t/* Respect E1000_RCTL_RDMTS */\n\tleft = (size + sc->esc_RDT - head) % size;\n\tif (left < (size >> (((sc->esc_RCTL >> 8) & 3) + 1)))\n\t\tcause |= E1000_ICR_RXDMT0;\n\t/* Assert all accumulated interrupts. */\n\tif (cause != 0)\n\t\te82545_icr_assert(sc, cause);\ndone1:\n\tDPRINTF(\"rx_run done: head %x, tail %x\\r\\n\", sc->esc_RDH, sc->esc_RDT);\n\tpthread_mutex_unlock(&sc->esc_mtx);\n}\n\nstatic uint16_t\ne82545_carry(uint32_t sum)\n{\n\n\tsum = (sum & 0xFFFF) + (sum >> 16);\n\tif (sum > 0xFFFF)\n\t\tsum -= 0xFFFF;\n\treturn (uint16_t)sum;\n}\n\nstatic uint16_t\ne82545_buf_checksum(uint8_t *buf, int len)\n{\n\tint i, limit;\n\tuint32_t sum = 0;\n\n\t/* Checksum all the pairs of bytes first... */\n    limit = len - (len & 1);\n\tfor (i = 0; i < limit; i += 2)\n\t\tsum += read_uint16_unaligned(buf + i);\n\n\t/*\n\t * If there's a single byte left over, checksum it, too.\n\t * Network byte order is big-endian, so the remaining byte is\n\t * the high byte.\n\t */\n\tif (i < len)\n\t\tsum += htons(buf[i] << 8);\n\n\treturn (e82545_carry(sum));\n}\n\nstatic uint16_t\ne82545_iov_checksum(struct iovec *iov, int iovcnt, int off, int len)\n{\n\tint now, odd;\n\tuint32_t sum = 0, s;\n\n\t/* Skip completely unneeded vectors. */\n\twhile (iovcnt > 0 && iov->iov_len <= (size_t)off && off > 0) {\n\t\toff -= iov->iov_len;\n\t\tiov++;\n\t\tiovcnt--;\n\t}\n\n\t/* Calculate checksum of requested range. */\n\todd = 0;\n\twhile (len > 0 && iovcnt > 0) {\n\t\tnow = MIN(len, (int)(iov->iov_len - (size_t)off));\n\t\ts = e82545_buf_checksum((uint8_t *)iov->iov_base + off, now);\n\t\tsum += odd ? (s << 8) : s;\n\t\todd ^= (now & 1);\n\t\tlen -= now;\n\t\toff = 0;\n\t\tiov++;\n\t\tiovcnt--;\n\t}\n\n\treturn (e82545_carry(sum));\n}\n\n/*\n * Return the transmit descriptor type.\n */\nstatic int\ne82545_txdesc_type(uint32_t lower)\n{\n\tint type;\n\n\ttype = 0;\n\n\tif (lower & E1000_TXD_CMD_DEXT)\n\t\ttype = lower & E1000_TXD_MASK;\n\n\treturn (type);\n}\n\nstatic void\ne82545_transmit_checksum(struct iovec *iov, int iovcnt, struct ck_info *ck)\n{\n\tuint16_t cksum;\n\tint cklen;\n\n\tDPRINTF(\"tx cksum: iovcnt/s/off/len %d/%d/%d/%d\\r\\n\",\n\t    iovcnt, ck->ck_start, ck->ck_off, ck->ck_len);\n\tcklen = ck->ck_len ? ck->ck_len - ck->ck_start + 1 : INT_MAX;\n\tcksum = e82545_iov_checksum(iov, iovcnt, ck->ck_start, cklen);\n    write_uint16_unaligned((uint8_t *)iov[0].iov_base + ck->ck_off, ~cksum);\n}\n\nstatic void\ne82545_transmit_backend(struct e82545_softc *sc, struct iovec *iov, int iovcnt)\n{\n    if (!sc->vms)\n        return;\n\n    vmn_write(sc->vms, iov, iovcnt);\n}\n\nstatic void\ne82545_transmit_done(struct e82545_softc *sc, uint16_t head, uint16_t tail,\n    uint16_t dsize, int *tdwb)\n{\n\tunion e1000_tx_udesc *dsc;\n\n\tfor ( ; head != tail; head = (head + 1) % dsize) {\n\t\tdsc = &sc->esc_txdesc[head];\n\t\tif (dsc->td.lower.data & E1000_TXD_CMD_RS) {\n\t\t\tdsc->td.upper.data |= E1000_TXD_STAT_DD;\n\t\t\t*tdwb = 1;\n\t\t}\n\t}\n}\n\nstatic int\ne82545_transmit(struct e82545_softc *sc, uint16_t head, uint16_t tail,\n    uint16_t dsize, uint16_t *rhead, int *tdwb)\n{\n    uint8_t *hdr = NULL;\n    uint8_t *hdrp = NULL;\n\tstruct iovec iovb[I82545_MAX_TXSEGS + 2];\n\tstruct iovec tiov[I82545_MAX_TXSEGS + 2];\n\tstruct e1000_context_desc *cd;\n\tstruct ck_info ckinfo[2];\n\tstruct iovec *iov;\n\tunion  e1000_tx_udesc *dsc;\n\tint desc, dtype, len, ntype, iovcnt, tlen, hdrlen, vlen, tcp, tso;\n\tint mss, paylen, seg, tiovcnt, left, now, nleft, nnow, pv, pvoff;\n\tuint32_t tcpsum, tcpseq;\n\tuint16_t ipcs, tcpcs, ipid, ohead;\n\n\tckinfo[0].ck_valid = ckinfo[1].ck_valid = 0;\n\tiovcnt = 0;\n\ttlen = 0;\n\tntype = 0;\n\ttso = 0;\n\tohead = head;\n\n\t/* iovb[0/1] may be used for writable copy of headers. */\n\tiov = &iovb[2];\n\n\tfor (desc = 0; ; desc++, head = (head + 1) % dsize) {\n\t\tif (head == tail) {\n\t\t\t*rhead = head;\n\t\t\treturn (0);\n\t\t}\n\t\tdsc = &sc->esc_txdesc[head];\n\t\tdtype = e82545_txdesc_type(dsc->td.lower.data);\n\n\t\tif (desc == 0) {\n\t\t\tswitch (dtype) {\n\t\t\tcase E1000_TXD_TYP_C:\n                    DPRINTF(\"tx ctxt desc idx %d: %016llx \"\n\t\t\t\t    \"%08x%08x\\r\\n\",\n\t\t\t\t    head, dsc->td.buffer_addr,\n\t\t\t\t    dsc->td.upper.data, dsc->td.lower.data);\n\t\t\t\t/* Save context and return */\n\t\t\t\tsc->esc_txctx = dsc->cd;\n\t\t\t\tgoto done;\n\t\t\tcase E1000_TXD_TYP_L:\n\t\t\t\tDPRINTF(\"tx legacy desc idx %d: %08x%08x\\r\\n\",\n\t\t\t\t    head, dsc->td.upper.data, dsc->td.lower.data);\n\t\t\t\t/*\n\t\t\t\t * legacy cksum start valid in first descriptor\n\t\t\t\t */\n\t\t\t\tntype = dtype;\n\t\t\t\tckinfo[0].ck_start = dsc->td.upper.fields.css;\n\t\t\t\tbreak;\n\t\t\tcase E1000_TXD_TYP_D:\n\t\t\t\tDPRINTF(\"tx data desc idx %d: %08x%08x\\r\\n\",\n\t\t\t\t    head, dsc->td.upper.data, dsc->td.lower.data);\n\t\t\t\tntype = dtype;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\t/* Descriptor type must be consistent */\n\t\t\tassert(dtype == ntype);\n\t\t\tDPRINTF(\"tx next desc idx %d: %08x%08x\\r\\n\",\n\t\t\t    head, dsc->td.upper.data, dsc->td.lower.data);\n\t\t}\n\n\t\tlen = (dtype == E1000_TXD_TYP_L) ? dsc->td.lower.flags.length :\n\t\t    dsc->dd.lower.data & 0xFFFFF;\n\n\t\tif (len > 0) {\n\t\t\t/* Strip checksum supplied by guest. */\n\t\t\tif ((dsc->td.lower.data & E1000_TXD_CMD_EOP) != 0 &&\n\t\t\t    (dsc->td.lower.data & E1000_TXD_CMD_IFCS) == 0)\n\t\t\t\tlen -= 2;\n\t\t\ttlen += len;\n\t\t\tif (iovcnt < I82545_MAX_TXSEGS) {\n\t\t\t\tiov[iovcnt].iov_base = paddr_guest2host(dsc->td.buffer_addr, (size_t)len);\n\t\t\t\tiov[iovcnt].iov_len = (size_t)len;\n\t\t\t}\n\t\t\tiovcnt++;\n\t\t}\n\n\t\t/*\n\t\t * Pull out info that is valid in the final descriptor\n\t\t * and exit descriptor loop.\n\t\t */\n\t\tif (dsc->td.lower.data & E1000_TXD_CMD_EOP) {\n\t\t\tif (dtype == E1000_TXD_TYP_L) {\n\t\t\t\tif (dsc->td.lower.data & E1000_TXD_CMD_IC) {\n\t\t\t\t\tckinfo[0].ck_valid = 1;\n\t\t\t\t\tckinfo[0].ck_off =\n\t\t\t\t\t    dsc->td.lower.flags.cso;\n\t\t\t\t\tckinfo[0].ck_len = 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcd = &sc->esc_txctx;\n\t\t\t\tif (dsc->dd.lower.data & E1000_TXD_CMD_TSE)\n\t\t\t\t\ttso = 1;\n\t\t\t\tif (dsc->dd.upper.fields.popts &\n\t\t\t\t    E1000_TXD_POPTS_IXSM)\n\t\t\t\t\tckinfo[0].ck_valid = 1;\n\t\t\t\tif (dsc->dd.upper.fields.popts &\n\t\t\t\t    E1000_TXD_POPTS_IXSM || tso) {\n\t\t\t\t\tckinfo[0].ck_start =\n\t\t\t\t\t    cd->lower_setup.ip_fields.ipcss;\n\t\t\t\t\tckinfo[0].ck_off =\n\t\t\t\t\t    cd->lower_setup.ip_fields.ipcso;\n\t\t\t\t\tckinfo[0].ck_len =\n\t\t\t\t\t    cd->lower_setup.ip_fields.ipcse;\n\t\t\t\t}\n\t\t\t\tif (dsc->dd.upper.fields.popts &\n\t\t\t\t    E1000_TXD_POPTS_TXSM)\n\t\t\t\t\tckinfo[1].ck_valid = 1;\n\t\t\t\tif (dsc->dd.upper.fields.popts &\n\t\t\t\t    E1000_TXD_POPTS_TXSM || tso) {\n\t\t\t\t\tckinfo[1].ck_start =\n\t\t\t\t\t    cd->upper_setup.tcp_fields.tucss;\n\t\t\t\t\tckinfo[1].ck_off =\n\t\t\t\t\t    cd->upper_setup.tcp_fields.tucso;\n\t\t\t\t\tckinfo[1].ck_len =\n\t\t\t\t\t    cd->upper_setup.tcp_fields.tucse;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (iovcnt > I82545_MAX_TXSEGS) {\n\t\tWPRINTF(\"tx too many descriptors (%d > %d) -- dropped\\r\\n\",\n\t\t    iovcnt, I82545_MAX_TXSEGS);\n\t\tgoto done;\n\t}\n\n\thdrlen = vlen = 0;\n\t/* Estimate writable space for VLAN header insertion. */\n\tif ((sc->esc_CTRL & E1000_CTRL_VME) &&\n\t    (dsc->td.lower.data & E1000_TXD_CMD_VLE)) {\n\t\thdrlen = ETHER_ADDR_LEN*2;\n\t\tvlen = ETHER_VLAN_ENCAP_LEN;\n\t}\n\tif (!tso) {\n\t\t/* Estimate required writable space for checksums. */\n\t\tif (ckinfo[0].ck_valid)\n\t\t\thdrlen = MAX(hdrlen, ckinfo[0].ck_off + 2);\n\t\tif (ckinfo[1].ck_valid)\n\t\t\thdrlen = MAX(hdrlen, ckinfo[1].ck_off + 2);\n\t\t/* Round up writable space to the first vector. */\n\t\tif (hdrlen != 0 && iov[0].iov_len > (size_t)hdrlen &&\n\t\t    iov[0].iov_len < (size_t)(hdrlen + 100))\n\t\t\thdrlen = (int)iov[0].iov_len;\n\t} else {\n\t\t/* In case of TSO header length provided by software. */\n\t\thdrlen = sc->esc_txctx.tcp_seg_setup.fields.hdr_len;\n\t}\n\n\t/* Allocate, fill and prepend writable header vector. */\n\tif (hdrlen != 0) {\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n#pragma clang diagnostic ignored \"-Walloca\"\n\t\thdr = __builtin_alloca((size_t)(hdrlen + vlen));\n#pragma clang diagnostic push\n\t\thdr += vlen;\n\t\tfor (left = hdrlen, hdrp = hdr; left > 0;\n\t\t    left -= now, hdrp += now) {\n\t\t\tnow = MIN(left, (int)(iov->iov_len));\n\t\t\tmemcpy(hdrp, iov->iov_base, now);\n            iov->iov_base = (uint8_t *)iov->iov_base + now;\n\t\t\tiov->iov_len -= (size_t)now;\n\t\t\tif (iov->iov_len == 0) {\n\t\t\t\tiov++;\n\t\t\t\tiovcnt--;\n\t\t\t}\n\t\t}\n\t\tiov--;\n\t\tiovcnt++;\n\t\tiov->iov_base = hdr;\n\t\tiov->iov_len = (size_t)hdrlen;\n\t}\n\n\t/* Insert VLAN tag. */\n\tif (vlen != 0) {\n\t\thdr -= ETHER_VLAN_ENCAP_LEN;\n\t\tmemmove(hdr, hdr + ETHER_VLAN_ENCAP_LEN, ETHER_ADDR_LEN*2);\n\t\thdrlen += ETHER_VLAN_ENCAP_LEN;\n\t\thdr[ETHER_ADDR_LEN*2 + 0] = (uint8_t)(sc->esc_VET >> 8);\n\t\thdr[ETHER_ADDR_LEN*2 + 1] = (uint8_t)(sc->esc_VET & 0xff);\n\t\thdr[ETHER_ADDR_LEN*2 + 2] = (uint8_t)(dsc->td.upper.fields.special >> 8);\n\t\thdr[ETHER_ADDR_LEN*2 + 3] = (uint8_t)(dsc->td.upper.fields.special & 0xff);\n\t\tiov->iov_base = hdr;\n\t\tiov->iov_len += ETHER_VLAN_ENCAP_LEN;\n\t\t/* Correct checksum offsets after VLAN tag insertion. */\n\t\tckinfo[0].ck_start += ETHER_VLAN_ENCAP_LEN;\n\t\tckinfo[0].ck_off += ETHER_VLAN_ENCAP_LEN;\n\t\tif (ckinfo[0].ck_len != 0)\n\t\t\tckinfo[0].ck_len += ETHER_VLAN_ENCAP_LEN;\n\t\tckinfo[1].ck_start += ETHER_VLAN_ENCAP_LEN;\n\t\tckinfo[1].ck_off += ETHER_VLAN_ENCAP_LEN;\n\t\tif (ckinfo[1].ck_len != 0)\n\t\t\tckinfo[1].ck_len += ETHER_VLAN_ENCAP_LEN;\n\t}\n\n\t/* Simple non-TSO case. */\n\tif (!tso) {\n\t\t/* Calculate checksums and transmit. */\n\t\tif (ckinfo[0].ck_valid)\n\t\t\te82545_transmit_checksum(iov, iovcnt, &ckinfo[0]);\n\t\tif (ckinfo[1].ck_valid)\n\t\t\te82545_transmit_checksum(iov, iovcnt, &ckinfo[1]);\n\t\te82545_transmit_backend(sc, iov, iovcnt);\n\t\tgoto done;\n\t}\n\n\t/* Doing TSO. */\n\ttcp = (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_TCP) != 0;\n\tmss = sc->esc_txctx.tcp_seg_setup.fields.mss;\n\tpaylen = (sc->esc_txctx.cmd_and_length & 0x000fffff);\n\tDPRINTF(\"tx %s segmentation offload %d+%d/%d bytes %d iovs\\r\\n\",\n\t    tcp ? \"TCP\" : \"UDP\", hdrlen, paylen, mss, iovcnt);\n    ipid = ntohs(read_uint16_unaligned(&hdr[ckinfo[0].ck_start + 4]));\n\ttcpseq = ntohl(read_uint32_unaligned(&hdr[ckinfo[1].ck_start + 4]));\n\tipcs = read_uint16_unaligned(&hdr[ckinfo[0].ck_off]);\n\ttcpcs = 0;\n\tif (ckinfo[1].ck_valid)\t/* Save partial pseudo-header checksum. */\n\t\ttcpcs = read_uint16_unaligned(&hdr[ckinfo[1].ck_off]);\n\tpv = 1;\n\tpvoff = 0;\n\tfor (seg = 0, left = paylen; left > 0; seg++, left -= now) {\n\t\tnow = MIN(left, mss);\n\n\t\t/* Construct IOVs for the segment. */\n\t\t/* Include whole original header. */\n\t\ttiov[0].iov_base = hdr;\n\t\ttiov[0].iov_len = (size_t)hdrlen;\n\t\ttiovcnt = 1;\n\t\t/* Include respective part of payload IOV. */\n\t\tfor (nleft = now; pv < iovcnt && nleft > 0; nleft -= nnow) {\n\t\t\tnnow = MIN(nleft, (int)iov[pv].iov_len - pvoff);\n\t\t\ttiov[tiovcnt].iov_base = (uint8_t *)iov[pv].iov_base + pvoff;\n\t\t\ttiov[tiovcnt++].iov_len = (size_t)nnow;\n\t\t\tif (pvoff + nnow == (int)iov[pv].iov_len) {\n\t\t\t\tpv++;\n\t\t\t\tpvoff = 0;\n\t\t\t} else\n\t\t\t\tpvoff += nnow;\n\t\t}\n\t\tDPRINTF(\"tx segment %d %d+%d bytes %d iovs\\r\\n\",\n\t\t    seg, hdrlen, now, tiovcnt);\n\n\t\t/* Update IP header. */\n\t\tif (sc->esc_txctx.cmd_and_length & E1000_TXD_CMD_IP) {\n\t\t\t/* IPv4 -- set length and ID */\n            write_uint16_unaligned(&hdr[ckinfo[0].ck_start + 2],\n                                   htons(hdrlen - ckinfo[0].ck_start + now));\n            write_uint16_unaligned(&hdr[ckinfo[0].ck_start + 4],\n                                   htons(ipid + seg));\n\t\t} else {\n\t\t\t/* IPv6 -- set length */\n            write_uint16_unaligned(&hdr[ckinfo[0].ck_start + 4],\n                                   htons(hdrlen - ckinfo[0].ck_start - 40 + now));\n\t\t}\n\n\t\t/* Update pseudo-header checksum. */\n\t\ttcpsum = tcpcs;\n\t\ttcpsum += htons(hdrlen - ckinfo[1].ck_start + now);\n\n\t\t/* Update TCP/UDP headers. */\n\t\tif (tcp) {\n\t\t\t/* Update sequence number and FIN/PUSH flags. */\n            write_uint32_unaligned(&hdr[ckinfo[1].ck_start + 4],\n                                   htonl((int)tcpseq + paylen - left));\n\t\t\tif (now < left) {\n\t\t\t\thdr[ckinfo[1].ck_start + 13] &=\n\t\t\t\t    ~(TH_FIN | TH_PUSH);\n\t\t\t}\n\t\t} else {\n\t\t\t/* Update payload length. */\n            write_uint32_unaligned(&hdr[ckinfo[1].ck_start + 4],\n                                   (uint32_t)(hdrlen - (int)ckinfo[1].ck_start + now));\n\t\t}\n\n\t\t/* Calculate checksums and transmit. */\n\t\tif (ckinfo[0].ck_valid) {\n            write_uint16_unaligned(&hdr[ckinfo[0].ck_off], ipcs);\n\t\t\te82545_transmit_checksum(tiov, tiovcnt, &ckinfo[0]);\n\t\t}\n\t\tif (ckinfo[1].ck_valid) {\n            write_uint16_unaligned(&hdr[ckinfo[1].ck_off],\n                                   e82545_carry(tcpsum));\n\t\t\te82545_transmit_checksum(tiov, tiovcnt, &ckinfo[1]);\n\t\t}\n\t\te82545_transmit_backend(sc, tiov, tiovcnt);\n\t}\n\ndone:\n\thead = (head + 1) % dsize;\n\te82545_transmit_done(sc, ohead, head, dsize, tdwb);\n\n\t*rhead = head;\n\treturn (desc + 1);\n}\n\nstatic void\ne82545_tx_run(struct e82545_softc *sc)\n{\n\tuint32_t cause;\n\tuint16_t head, rhead, tail, size;\n\tint lim, tdwb, sent;\n\n\thead = sc->esc_TDH;\n\ttail = sc->esc_TDT;\n\tsize = (uint16_t)(sc->esc_TDLEN / 16);\n\tDPRINTF(\"tx_run: head %x, rhead %x, tail %x\\r\\n\",\n\t    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);\n\n\tpthread_mutex_unlock(&sc->esc_mtx);\n\trhead = head;\n\ttdwb = 0;\n\tfor (lim = size / 4; sc->esc_tx_enabled && lim > 0; lim -= sent) {\n\t\tsent = e82545_transmit(sc, head, tail, size, &rhead, &tdwb);\n\t\tif (sent == 0)\n\t\t\tbreak;\n\t\thead = rhead;\n\t}\n\tpthread_mutex_lock(&sc->esc_mtx);\n\n\tsc->esc_TDH = head;\n\tsc->esc_TDHr = rhead;\n\tcause = 0;\n\tif (tdwb)\n\t\tcause |= E1000_ICR_TXDW;\n\tif (lim != size / 4 && sc->esc_TDH == sc->esc_TDT)\n\t\tcause |= E1000_ICR_TXQE;\n\tif (cause)\n\t\te82545_icr_assert(sc, cause);\n\n\tDPRINTF(\"tx_run done: head %x, rhead %x, tail %x\\r\\n\",\n\t    sc->esc_TDH, sc->esc_TDHr, sc->esc_TDT);\n}\n\nstatic _Noreturn void *\ne82545_tx_thread(void *param)\n{\n\tstruct e82545_softc *sc = param;\n    char nstr[80];\n\n    snprintf(nstr, sizeof(nstr), \"e82545-%d:%d tx\", sc->esc_pi->pi_slot,\n             sc->esc_pi->pi_func);\n    pthread_setname_np(nstr);\n\n\tpthread_mutex_lock(&sc->esc_mtx);\n\tfor (;;) {\n\t\twhile (!sc->esc_tx_enabled || sc->esc_TDHr == sc->esc_TDT) {\n\t\t\tif (sc->esc_tx_enabled && sc->esc_TDHr != sc->esc_TDT)\n\t\t\t\tbreak;\n\t\t\tsc->esc_tx_active = 0;\n\t\t\tif (sc->esc_tx_enabled == 0)\n\t\t\t\tpthread_cond_signal(&sc->esc_tx_cond);\n\t\t\tpthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);\n\t\t}\n\t\tsc->esc_tx_active = 1;\n\n\t\t/* Process some tx descriptors.  Lock dropped inside. */\n\t\te82545_tx_run(sc);\n\t}\n}\n\nstatic void\ne82545_tx_start(struct e82545_softc *sc)\n{\n\n\tif (sc->esc_tx_active == 0)\n\t\tpthread_cond_signal(&sc->esc_tx_cond);\n}\n\nstatic void\ne82545_tx_enable(struct e82545_softc *sc)\n{\n\n\tsc->esc_tx_enabled = 1;\n}\n\nstatic void\ne82545_tx_disable(struct e82545_softc *sc)\n{\n\n\tsc->esc_tx_enabled = 0;\n\twhile (sc->esc_tx_active)\n\t\tpthread_cond_wait(&sc->esc_tx_cond, &sc->esc_mtx);\n}\n\nstatic void\ne82545_rx_enable(struct e82545_softc *sc)\n{\n\n\tsc->esc_rx_enabled = 1;\n}\n\nstatic void\ne82545_rx_disable(struct e82545_softc *sc)\n{\n\n\tsc->esc_rx_enabled = 0;\n\twhile (sc->esc_rx_active)\n\t\tpthread_cond_wait(&sc->esc_rx_cond, &sc->esc_mtx);\n}\n\nstatic void\ne82545_write_ra(struct e82545_softc *sc, int reg, uint32_t wval)\n{\n        struct eth_uni *eu;\n\tint idx;\n\n\tidx = reg >> 1;\n\tassert(idx < 15);\n\n\teu = &sc->esc_uni[idx];\n\n\tif (reg & 0x1) {\n\t\t/* RAH */\n\t\teu->eu_valid = ((wval & E1000_RAH_AV) == E1000_RAH_AV);\n\t\teu->eu_addrsel = (wval >> 16) & 0x3;\n\t\teu->eu_eth.octet[5] = (u_char)(wval >> 8);\n\t\teu->eu_eth.octet[4] = (u_char)wval;\n\t} else {\n\t\t/* RAL */\n\t\teu->eu_eth.octet[3] = (u_char)(wval >> 24);\n\t\teu->eu_eth.octet[2] = (u_char)(wval >> 16);\n\t\teu->eu_eth.octet[1] = (u_char)(wval >> 8);\n\t\teu->eu_eth.octet[0] = (u_char)wval;\n\t}\n}\n\nstatic uint32_t\ne82545_read_ra(struct e82545_softc *sc, int reg)\n{\n        struct eth_uni *eu;\n\tuint32_t retval;\n\tint idx;\n\n\tidx = reg >> 1;\n\tassert(idx < 15);\n\n\teu = &sc->esc_uni[idx];\n\n\tif (reg & 0x1) {\n\t\t/* RAH */\n\t\tretval = (uint32_t)(eu->eu_valid << 31) |\n\t\t\t (uint32_t)(eu->eu_addrsel << 16) |\n             (uint32_t)(eu->eu_eth.octet[5] << 8) |\n\t\t\t eu->eu_eth.octet[4];\n\t} else {\n\t\t/* RAL */\n\t\tretval = (uint32_t)(eu->eu_eth.octet[3] << 24) |\n\t\t\t (uint32_t)(eu->eu_eth.octet[2] << 16) |\n\t\t\t (uint32_t)(eu->eu_eth.octet[1] << 8) |\n\t\t\t eu->eu_eth.octet[0];\n\t}\n\n\treturn (retval);\n}\n\nstatic void\ne82545_write_register(struct e82545_softc *sc, uint32_t offset, uint32_t value)\n{\n\tint ridx;\n\n\tif (offset & 0x3) {\n\t\tDPRINTF(\"Unaligned register write offset:0x%x value:0x%x\\r\\n\", offset, value);\n\t\treturn;\n\t}\n\tDPRINTF(\"Register write: 0x%x value: 0x%x\\r\\n\", offset, value);\n\n\tswitch (offset) {\n\tcase E1000_CTRL:\n\tcase E1000_CTRL_DUP:\n\t\te82545_devctl(sc, value);\n\t\tbreak;\n\tcase E1000_FCAL:\n\t\tsc->esc_FCAL = value;\n\t\tbreak;\n\tcase E1000_FCAH:\n\t\tsc->esc_FCAH = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_FCT:\n\t\tsc->esc_FCT = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_VET:\n\t\tsc->esc_VET = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_FCTTV:\n\t\tsc->esc_FCTTV = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_LEDCTL:\n\t\tsc->esc_LEDCTL = value & (uint32_t)~0x30303000;\n\t\tbreak;\n\tcase E1000_PBA:\n\t\tsc->esc_PBA = value & 0x0000FF80;\n\t\tbreak;\n\tcase E1000_ICR:\n\tcase E1000_ITR:\n\tcase E1000_ICS:\n\tcase E1000_IMS:\n\tcase E1000_IMC:\n\t\te82545_intr_write(sc, offset, value);\n\t\tbreak;\n\tcase E1000_RCTL:\n\t\te82545_rx_ctl(sc, value);\n\t\tbreak;\n\tcase E1000_FCRTL:\n\t\tsc->esc_FCRTL = value & ~0xFFFF0007;\n\t\tbreak;\n\tcase E1000_FCRTH:\n\t\tsc->esc_FCRTH = value & ~0xFFFF0007;\n\t\tbreak;\n\tcase E1000_RDBAL(0):\n\t\tsc->esc_RDBAL = value & (uint32_t)~0xF;\n\t\tif (sc->esc_rx_enabled) {\n\t\t\t/* Apparently legal: update cached address */\n\t\t\te82545_rx_update_rdba(sc);\n\t\t}\n\t\tbreak;\n\tcase E1000_RDBAH(0):\n\t\tassert(!sc->esc_rx_enabled);\n\t\tsc->esc_RDBAH = value;\n\t\tbreak;\n\tcase E1000_RDLEN(0):\n\t\tassert(!sc->esc_rx_enabled);\n\t\tsc->esc_RDLEN = value & ~0xFFF0007F;\n\t\tbreak;\n\tcase E1000_RDH(0):\n\t\t/* XXX should only ever be zero ? Range check ? */\n\t\tsc->esc_RDH = (uint16_t)value;\n\t\tbreak;\n\tcase E1000_RDT(0):\n\t\t/* XXX if this opens up the rx ring, do something ? */\n\t\tsc->esc_RDT = (uint16_t)value;\n\t\tbreak;\n\tcase E1000_RDTR:\n\t\t/* ignore FPD bit 31 */\n\t\tsc->esc_RDTR = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_RXDCTL(0):\n\t\tsc->esc_RXDCTL = value & ~0xFEC0C0C0;\n\t\tbreak;\n\tcase E1000_RADV:\n\t\tsc->esc_RADV = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_RSRPD:\n\t\tsc->esc_RSRPD = value & ~0xFFFFF000;\n\t\tbreak;\n\tcase E1000_RXCSUM:\n\t\tsc->esc_RXCSUM = value & ~0xFFFFF800;\n\t\tbreak;\n\tcase E1000_TXCW:\n\t\tsc->esc_TXCW = value & (uint32_t)~0x3FFF0000;\n\t\tbreak;\n\tcase E1000_TCTL:\n\t\te82545_tx_ctl(sc, value);\n\t\tbreak;\n\tcase E1000_TIPG:\n\t\tsc->esc_TIPG = value;\n\t\tbreak;\n\tcase E1000_AIT:\n\t\tsc->esc_AIT = (uint16_t)value;\n\t\tbreak;\n\tcase E1000_TDBAL(0):\n\t\tsc->esc_TDBAL = value & (uint32_t)~0xF;\n\t\tif (sc->esc_tx_enabled) {\n\t\t\t/* Apparently legal */\n\t\t\te82545_tx_update_tdba(sc);\n\t\t}\n\t\tbreak;\n\tcase E1000_TDBAH(0):\n\t\t//assert(!sc->esc_tx_enabled);\n\t\tsc->esc_TDBAH = value;\n\t\tbreak;\n\tcase E1000_TDLEN(0):\n\t\t//assert(!sc->esc_tx_enabled);\n\t\tsc->esc_TDLEN = value & ~0xFFF0007F;\n\t\tbreak;\n\tcase E1000_TDH(0):\n\t\t//assert(!sc->esc_tx_enabled);\n\t\t/* XXX should only ever be zero ? Range check ? */\n\t\tsc->esc_TDHr = sc->esc_TDH = (uint16_t)value;\n\t\tbreak;\n\tcase E1000_TDT(0):\n\t\t/* XXX range check ? */\n\t\tsc->esc_TDT = (uint16_t)value;\n\t\tif (sc->esc_tx_enabled)\n\t\t\te82545_tx_start(sc);\n\t\tbreak;\n\tcase E1000_TIDV:\n\t\tsc->esc_TIDV = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_TXDCTL(0):\n\t\t//assert(!sc->esc_tx_enabled);\n\t\tsc->esc_TXDCTL = value & (uint32_t)~0xC0C0C0;\n\t\tbreak;\n\tcase E1000_TADV:\n\t\tsc->esc_TADV = value & ~0xFFFF0000;\n\t\tbreak;\n\tcase E1000_EECD:\n\t{\n\t\t//DPRINTF(\"EECD write 0x%x -> 0x%x\\r\\n\", sc->eeprom_control, value);\n\t\t/* edge triggered low->high */\n\t\tuint32_t eecd_strobe = ((sc->eeprom_control & E1000_EECD_SK) ?\n\t\t\t0 : (value & E1000_EECD_SK));\n\t\tuint32_t eecd_mask = (E1000_EECD_SK|E1000_EECD_CS|\n\t\t\t\t\tE1000_EECD_DI|E1000_EECD_REQ);\n\t\tsc->eeprom_control &= ~eecd_mask;\n\t\tsc->eeprom_control |= (value & eecd_mask);\n\t\t/* grant/revoke immediately */\n\t\tif (value & E1000_EECD_REQ) {\n\t\t\tsc->eeprom_control |= E1000_EECD_GNT;\n\t\t} else {\n                        sc->eeprom_control &= (uint32_t)~E1000_EECD_GNT;\n\t\t}\n\t\tif (eecd_strobe && (sc->eeprom_control & E1000_EECD_CS)) {\n\t\t\te82545_eecd_strobe(sc);\n\t\t}\n\t\treturn;\n\t}\n\tcase E1000_MDIC:\n\t{\n\t\tuint8_t reg_addr = (uint8_t)((value & E1000_MDIC_REG_MASK) >>\n\t\t\t\t\t\tE1000_MDIC_REG_SHIFT);\n\t\tuint8_t phy_addr = (uint8_t)((value & E1000_MDIC_PHY_MASK) >>\n\t\t\t\t\t\tE1000_MDIC_PHY_SHIFT);\n\t\tsc->mdi_control =\n\t\t\t(value & ~(E1000_MDIC_ERROR|E1000_MDIC_DEST));\n\t\tif ((value & E1000_MDIC_READY) != 0) {\n\t\t\tDPRINTF(\"Incorrect MDIC ready bit: 0x%x\\r\\n\", value);\n\t\t\treturn;\n\t\t}\n\t\tswitch (value & E82545_MDIC_OP_MASK) {\n\t\tcase E1000_MDIC_OP_READ:\n\t\t\tsc->mdi_control &= (uint32_t)~E82545_MDIC_DATA_MASK;\n\t\t\tsc->mdi_control |= e82545_read_mdi(sc, reg_addr, phy_addr);\n\t\t\tbreak;\n\t\tcase E1000_MDIC_OP_WRITE:\n\t\t\te82545_write_mdi(sc, reg_addr, phy_addr,\n\t\t\t\tvalue & E82545_MDIC_DATA_MASK);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tDPRINTF(\"Unknown MDIC op: 0x%x\\r\\n\", value);\n\t\t\treturn;\n\t\t}\n\t\t/* TODO: barrier? */\n\t\tsc->mdi_control |= E1000_MDIC_READY;\n\t\tif (value & E82545_MDIC_IE) {\n\t\t\t// TODO: generate interrupt\n\t\t}\n\t\treturn;\n\t}\n\tcase E1000_MANC:\n\tcase E1000_STATUS:\n\t\treturn;\n\tdefault:\n        if ((offset >= E1000_RAL(0)) && (offset <= E1000_RAH(15))) {\n            /* convert to u32 offset */\n            ridx = (offset - E1000_RAL(0)) >> 2;\n            e82545_write_ra(sc, ridx, value);\n        } else if ((offset >= E1000_MTA) && (offset <= E1000_MTA + (127*4))) {\n            sc->esc_fmcast[(offset - E1000_MTA) >> 2] = value;\n        } else if ((offset >= E1000_VFTA) && (offset <= E1000_VFTA + (127*4))) {\n            sc->esc_fvlan[(offset - E1000_VFTA) >> 2] = value;\n        } else {\n            DPRINTF(\"Unknown write register: 0x%x value:%x\\r\\n\", offset, value);\n        }\n\t\treturn;\n\t}\n}\n\nstatic uint32_t\ne82545_read_register(struct e82545_softc *sc, uint32_t offset)\n{\n\tuint32_t retval;\n\tint ridx;\n\n\tif (offset & 0x3) {\n\t\tDPRINTF(\"Unaligned register read offset:0x%x\\r\\n\", offset);\n\t\treturn 0;\n\t}\n\n\tDPRINTF(\"Register read: 0x%x\\r\\n\", offset);\n\n\tswitch (offset) {\n\tcase E1000_CTRL:\n\t\tretval = sc->esc_CTRL;\n\t\tbreak;\n\tcase E1000_STATUS:\n\t\tretval = E1000_STATUS_FD | E1000_STATUS_LU |\n\t\t    E1000_STATUS_SPEED_1000;\n\t\tbreak;\n\tcase E1000_FCAL:\n\t\tretval = sc->esc_FCAL;\n\t\tbreak;\n\tcase E1000_FCAH:\n\t\tretval = sc->esc_FCAH;\n\t\tbreak;\n\tcase E1000_FCT:\n\t\tretval = sc->esc_FCT;\n\t\tbreak;\n\tcase E1000_VET:\n\t\tretval = sc->esc_VET;\n\t\tbreak;\n\tcase E1000_FCTTV:\n\t\tretval = sc->esc_FCTTV;\n\t\tbreak;\n\tcase E1000_LEDCTL:\n\t\tretval = sc->esc_LEDCTL;\n\t\tbreak;\n\tcase E1000_PBA:\n\t\tretval = sc->esc_PBA;\n\t\tbreak;\n\tcase E1000_ICR:\n\tcase E1000_ITR:\n\tcase E1000_ICS:\n\tcase E1000_IMS:\n\tcase E1000_IMC:\n\t\tretval = e82545_intr_read(sc, offset);\n\t\tbreak;\n\tcase E1000_RCTL:\n\t\tretval = sc->esc_RCTL;\n\t\tbreak;\n\tcase E1000_FCRTL:\n\t\tretval = sc->esc_FCRTL;\n\t\tbreak;\n\tcase E1000_FCRTH:\n\t\tretval = sc->esc_FCRTH;\n\t\tbreak;\n\tcase E1000_RDBAL(0):\n\t\tretval = sc->esc_RDBAL;\n\t\tbreak;\n\tcase E1000_RDBAH(0):\n\t\tretval = sc->esc_RDBAH;\n\t\tbreak;\n\tcase E1000_RDLEN(0):\n\t\tretval = sc->esc_RDLEN;\n\t\tbreak;\n\tcase E1000_RDH(0):\n\t\tretval = sc->esc_RDH;\n\t\tbreak;\n\tcase E1000_RDT(0):\n\t\tretval = sc->esc_RDT;\n\t\tbreak;\n\tcase E1000_RDTR:\n\t\tretval = sc->esc_RDTR;\n\t\tbreak;\n\tcase E1000_RXDCTL(0):\n\t\tretval = sc->esc_RXDCTL;\n\t\tbreak;\n\tcase E1000_RADV:\n\t\tretval = sc->esc_RADV;\n\t\tbreak;\n\tcase E1000_RSRPD:\n\t\tretval = sc->esc_RSRPD;\n\t\tbreak;\n\tcase E1000_RXCSUM:\n\t\tretval = sc->esc_RXCSUM;\n\t\tbreak;\n\tcase E1000_TXCW:\n\t\tretval = sc->esc_TXCW;\n\t\tbreak;\n\tcase E1000_TCTL:\n\t\tretval = sc->esc_TCTL;\n\t\tbreak;\n\tcase E1000_TIPG:\n\t\tretval = sc->esc_TIPG;\n\t\tbreak;\n\tcase E1000_AIT:\n\t\tretval = sc->esc_AIT;\n\t\tbreak;\n\tcase E1000_TDBAL(0):\n\t\tretval = sc->esc_TDBAL;\n\t\tbreak;\n\tcase E1000_TDBAH(0):\n\t\tretval = sc->esc_TDBAH;\n\t\tbreak;\n\tcase E1000_TDLEN(0):\n\t\tretval = sc->esc_TDLEN;\n\t\tbreak;\n\tcase E1000_TDH(0):\n\t\tretval = sc->esc_TDH;\n\t\tbreak;\n\tcase E1000_TDT(0):\n\t\tretval = sc->esc_TDT;\n\t\tbreak;\n\tcase E1000_TIDV:\n\t\tretval = sc->esc_TIDV;\n\t\tbreak;\n\tcase E1000_TXDCTL(0):\n\t\tretval = sc->esc_TXDCTL;\n\t\tbreak;\n\tcase E1000_TADV:\n\t\tretval = sc->esc_TADV;\n\t\tbreak;\n\tcase E1000_EECD:\n\t\t//DPRINTF(\"EECD read %x\\r\\n\", sc->eeprom_control);\n\t\tretval = sc->eeprom_control;\n\t\tbreak;\n\tcase E1000_MDIC:\n\t\tretval = sc->mdi_control;\n\t\tbreak;\n\tcase E1000_MANC:\n\t\tretval = 0;\n\t\tbreak;\n\t/* stats that we emulate. */\n\tcase E1000_MPC:\n\t\tretval = sc->missed_pkt_count;\n\t\tbreak;\n\tcase E1000_PRC64:\n\t\tretval = sc->pkt_rx_by_size[0];\n\t\tbreak;\n\tcase E1000_PRC127:\n\t\tretval = sc->pkt_rx_by_size[1];\n\t\tbreak;\n\tcase E1000_PRC255:\n\t\tretval = sc->pkt_rx_by_size[2];\n\t\tbreak;\n\tcase E1000_PRC511:\n\t\tretval = sc->pkt_rx_by_size[3];\n\t\tbreak;\n\tcase E1000_PRC1023:\n\t\tretval = sc->pkt_rx_by_size[4];\n\t\tbreak;\n\tcase E1000_PRC1522:\n\t\tretval = sc->pkt_rx_by_size[5];\n\t\tbreak;\n\tcase E1000_GPRC:\n\t\tretval = sc->good_pkt_rx_count;\n\t\tbreak;\n\tcase E1000_BPRC:\n\t\tretval = sc->bcast_pkt_rx_count;\n\t\tbreak;\n\tcase E1000_MPRC:\n\t\tretval = sc->mcast_pkt_rx_count;\n\t\tbreak;\n\tcase E1000_GPTC:\n\tcase E1000_TPT:\n\t\tretval = sc->good_pkt_tx_count;\n\t\tbreak;\n\tcase E1000_GORCL:\n\t\tretval = (uint32_t)sc->good_octets_rx;\n\t\tbreak;\n\tcase E1000_GORCH:\n\t\tretval = (uint32_t)(sc->good_octets_rx >> 32);\n\t\tbreak;\n\tcase E1000_TOTL:\n\tcase E1000_GOTCL:\n\t\tretval = (uint32_t)sc->good_octets_tx;\n\t\tbreak;\n\tcase E1000_TOTH:\n\tcase E1000_GOTCH:\n\t\tretval = (uint32_t)(sc->good_octets_tx >> 32);\n\t\tbreak;\n\tcase E1000_ROC:\n\t\tretval = sc->oversize_rx_count;\n\t\tbreak;\n\tcase E1000_TORL:\n\t\tretval = (uint32_t)(sc->good_octets_rx + sc->missed_octets);\n\t\tbreak;\n\tcase E1000_TORH:\n\t\tretval = (uint32_t)((sc->good_octets_rx +\n\t\t    sc->missed_octets) >> 32);\n\t\tbreak;\n\tcase E1000_TPR:\n\t\tretval = sc->good_pkt_rx_count + sc->missed_pkt_count +\n\t\t    sc->oversize_rx_count;\n\t\tbreak;\n\tcase E1000_PTC64:\n\t\tretval = sc->pkt_tx_by_size[0];\n\t\tbreak;\n\tcase E1000_PTC127:\n\t\tretval = sc->pkt_tx_by_size[1];\n\t\tbreak;\n\tcase E1000_PTC255:\n\t\tretval = sc->pkt_tx_by_size[2];\n\t\tbreak;\n\tcase E1000_PTC511:\n\t\tretval = sc->pkt_tx_by_size[3];\n\t\tbreak;\n\tcase E1000_PTC1023:\n\t\tretval = sc->pkt_tx_by_size[4];\n\t\tbreak;\n\tcase E1000_PTC1522:\n\t\tretval = sc->pkt_tx_by_size[5];\n\t\tbreak;\n\tcase E1000_MPTC:\n\t\tretval = sc->mcast_pkt_tx_count;\n\t\tbreak;\n\tcase E1000_BPTC:\n\t\tretval = sc->bcast_pkt_tx_count;\n\t\tbreak;\n\tcase E1000_TSCTC:\n\t\tretval = sc->tso_tx_count;\n\t\tbreak;\n\t/* stats that are always 0. */\n\tcase E1000_CRCERRS:\n\tcase E1000_ALGNERRC:\n\tcase E1000_SYMERRS:\n\tcase E1000_RXERRC:\n\tcase E1000_SCC:\n\tcase E1000_ECOL:\n\tcase E1000_MCC:\n\tcase E1000_LATECOL:\n\tcase E1000_COLC:\n\tcase E1000_DC:\n\tcase E1000_TNCRS:\n\tcase E1000_SEC:\n\tcase E1000_CEXTERR:\n\tcase E1000_RLEC:\n\tcase E1000_XONRXC:\n\tcase E1000_XONTXC:\n\tcase E1000_XOFFRXC:\n\tcase E1000_XOFFTXC:\n\tcase E1000_FCRUC:\n\tcase E1000_RNBC:\n\tcase E1000_RUC:\n\tcase E1000_RFC:\n\tcase E1000_RJC:\n\tcase E1000_MGTPRC:\n\tcase E1000_MGTPDC:\n\tcase E1000_MGTPTC:\n\tcase E1000_TSCTFC:\n\t\tretval = 0;\n\t\tbreak;\n\tdefault:\n        if ((offset >= E1000_RAL(0)) && (offset <= E1000_RAH(15))) {\n            /* convert to u32 offset */\n            ridx = (offset - E1000_RAL(0)) >> 2;\n            retval = e82545_read_ra(sc, ridx);\n        } else if ((offset >= E1000_MTA) && (offset <= E1000_MTA + (127*4))) {\n            retval = sc->esc_fmcast[(offset - E1000_MTA) >> 2];\n        } else if ((offset >= E1000_VFTA) && (offset <= E1000_VFTA + (127*4))) {\n            retval = sc->esc_fvlan[(offset - E1000_VFTA) >> 2];\n        } else {\n            DPRINTF(\"Unknown read register: 0x%x\\r\\n\", offset);\n            retval = 0;\n        }\n\t\tbreak;\n\t}\n\n\treturn (retval);\n}\n\nstatic void\ne82545_write(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\t     uint64_t offset, int size, uint64_t value)\n{\n\tstruct e82545_softc *sc;\n\n\t//DPRINTF(\"Write bar:%d offset:0x%lx value:0x%lx size:%d\\r\\n\", baridx, offset, value, size);\n\n\tsc = pi->pi_arg;\n\n\tpthread_mutex_lock(&sc->esc_mtx);\n\n\tswitch (baridx) {\n\tcase E82545_BAR_IO:\n\t\tswitch (offset) {\n\t\tcase E82545_IOADDR:\n\t\t\tif (size != 4) {\n\t\t\t\tDPRINTF(\"Wrong io addr write sz:%d value:0x%llx\\r\\n\", size, value);\n\t\t\t} else\n\t\t\t\tsc->io_addr = (uint32_t)value;\n\t\t\tbreak;\n\t\tcase E82545_IODATA:\n\t\t\tif (size != 4) {\n\t\t\t\tDPRINTF(\"Wrong io data write size:%d value:0x%llx\\r\\n\", size, value);\n\t\t\t} else if (sc->io_addr > E82545_IO_REGISTER_MAX) {\n\t\t\t\tDPRINTF(\"Non-register io write addr:0x%x value:0x%llx\\r\\n\", sc->io_addr, value);\n\t\t\t} else\n\t\t\t\te82545_write_register(sc, sc->io_addr,\n\t\t\t\t\t\t      (uint32_t)value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tDPRINTF(\"Unknown io bar write offset:0x%llx value:0x%llx size:%d\\r\\n\", offset, value, size);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase E82545_BAR_REGISTER:\n\t\tif (size != 4) {\n\t\t\tDPRINTF(\"Wrong register write size:%d offset:0x%llx value:0x%llx\\r\\n\", size, offset, value);\n\t\t} else\n\t\t\te82545_write_register(sc, (uint32_t)offset,\n\t\t\t\t\t      (uint32_t)value);\n\t\tbreak;\n\tdefault:\n            DPRINTF(\"Unknown write bar:%d off:0x%llx val:0x%llx size:%d\\r\\n\",\n\t\t\tbaridx, offset, value, size);\n\t}\n\n\tpthread_mutex_unlock(&sc->esc_mtx);\n}\n\nstatic uint64_t\ne82545_read(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\t    uint64_t offset, int size)\n{\n\tstruct e82545_softc *sc;\n\tuint64_t retval;\n\n\t//DPRINTF(\"Read  bar:%d offset:0x%lx size:%d\\r\\n\", baridx, offset, size);\n\tsc = pi->pi_arg;\n\tretval = 0;\n\n\tpthread_mutex_lock(&sc->esc_mtx);\n\n\tswitch (baridx) {\n\tcase E82545_BAR_IO:\n\t\tswitch (offset) {\n\t\tcase E82545_IOADDR:\n\t\t\tif (size != 4) {\n\t\t\t\tDPRINTF(\"Wrong io addr read sz:%d\\r\\n\", size);\n\t\t\t} else\n\t\t\t\tretval = sc->io_addr;\n\t\t\tbreak;\n\t\tcase E82545_IODATA:\n\t\t\tif (size != 4) {\n\t\t\t\tDPRINTF(\"Wrong io data read sz:%d\\r\\n\", size);\n\t\t\t}\n\t\t\tif (sc->io_addr > E82545_IO_REGISTER_MAX) {\n\t\t\t\tDPRINTF(\"Non-register io read addr:0x%x\\r\\n\",\n\t\t\t\t\tsc->io_addr);\n\t\t\t} else\n\t\t\t\tretval = e82545_read_register(sc, sc->io_addr);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tDPRINTF(\"Unknown io bar read offset:0x%llx size:%d\\r\\n\",\n\t\t\t\toffset, size);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase E82545_BAR_REGISTER:\n\t\tif (size != 4) {\n\t\t\tDPRINTF(\"Wrong register read size:%d offset:0x%llx\\r\\n\",\n\t\t\t\tsize, offset);\n\t\t} else\n\t\t\tretval = e82545_read_register(sc, (uint32_t)offset);\n\t\tbreak;\n\tdefault:\n\t\tDPRINTF(\"Unknown read bar:%d offset:0x%llx size:%d\\r\\n\",\n\t\t\tbaridx, offset, size);\n\t\tbreak;\n\t}\n\n\tpthread_mutex_unlock(&sc->esc_mtx);\n\n\treturn (retval);\n}\n\nstatic void\ne82545_reset(struct e82545_softc *sc, int drvr)\n{\n\tint i;\n\n\te82545_rx_disable(sc);\n\te82545_tx_disable(sc);\n\n\t/* clear outstanding interrupts */\n\tif (sc->esc_irq_asserted)\n\t\tpci_lintr_deassert(sc->esc_pi);\n\n\t/* misc */\n\tif (!drvr) {\n\t\tsc->esc_FCAL = 0;\n\t\tsc->esc_FCAH = 0;\n\t\tsc->esc_FCT = 0;\n\t\tsc->esc_VET = 0;\n\t\tsc->esc_FCTTV = 0;\n\t}\n\tsc->esc_LEDCTL = 0x07061302;\n\tsc->esc_PBA = 0x00100030;\n\n\t/* start nvm in opcode mode. */\n\tsc->nvm_opaddr = 0;\n\tsc->nvm_mode = E82545_NVM_MODE_OPADDR;\n\tsc->nvm_bits = E82545_NVM_OPADDR_BITS;\n\tsc->eeprom_control = E1000_EECD_PRES | E82545_EECD_FWE_EN;\n\te82545_init_eeprom(sc);\n\n\t/* interrupt */\n\tsc->esc_ICR = 0;\n\tsc->esc_ITR = 250;\n\tsc->esc_ICS = 0;\n\tsc->esc_IMS = 0;\n\tsc->esc_IMC = 0;\n\n\t/* L2 filters */\n\tif (!drvr) {\n\t\tmemset(sc->esc_fvlan, 0, sizeof(sc->esc_fvlan));\n\t\tmemset(sc->esc_fmcast, 0, sizeof(sc->esc_fmcast));\n\t\tmemset(sc->esc_uni, 0, sizeof(sc->esc_uni));\n\n\t\t/* XXX not necessary on 82545 ?? */\n\t\tsc->esc_uni[0].eu_valid = 1;\n\t\tmemcpy(sc->esc_uni[0].eu_eth.octet, sc->vms->mac,\n\t\t    ETHER_ADDR_LEN);\n\t} else {\n\t\t/* Clear RAH valid bits */\n\t\tfor (i = 0; i < 16; i++)\n\t\t\tsc->esc_uni[i].eu_valid = 0;\n\t}\n\n\t/* receive */\n\tif (!drvr) {\n\t\tsc->esc_RDBAL = 0;\n\t\tsc->esc_RDBAH = 0;\n\t}\n\tsc->esc_RCTL = 0;\n\tsc->esc_FCRTL = 0;\n\tsc->esc_FCRTH = 0;\n\tsc->esc_RDLEN = 0;\n\tsc->esc_RDH = 0;\n\tsc->esc_RDT = 0;\n\tsc->esc_RDTR = 0;\n\tsc->esc_RXDCTL = (1 << 24) | (1 << 16); /* default GRAN/WTHRESH */\n\tsc->esc_RADV = 0;\n\tsc->esc_RXCSUM = 0;\n\n\t/* transmit */\n\tif (!drvr) {\n\t\tsc->esc_TDBAL = 0;\n\t\tsc->esc_TDBAH = 0;\n\t\tsc->esc_TIPG = 0;\n\t\tsc->esc_AIT = 0;\n\t\tsc->esc_TIDV = 0;\n\t\tsc->esc_TADV = 0;\n\t}\n\tsc->esc_tdba = 0;\n\tsc->esc_txdesc = NULL;\n\tsc->esc_TXCW = 0;\n\tsc->esc_TCTL = 0;\n\tsc->esc_TDLEN = 0;\n\tsc->esc_TDT = 0;\n\tsc->esc_TDHr = sc->esc_TDH = 0;\n\tsc->esc_TXDCTL = 0;\n}\n\nstatic int\ne82545_init(struct pci_devinst *pi, char *opts)\n{\n\tDPRINTF(\"Loading with options: %s\\r\\n\", opts);\n\n\tstruct e82545_softc *sc;\n\n\t/* Setup our softc */\n\tsc = calloc(1, sizeof(*sc));\n\n\tpi->pi_arg = sc;\n\tsc->esc_pi = pi;\n\n\tpthread_mutex_init(&sc->esc_mtx, NULL);\n\tpthread_cond_init(&sc->esc_rx_cond, NULL);\n\tpthread_cond_init(&sc->esc_tx_cond, NULL);\n\tpthread_create(&sc->esc_tx_tid, NULL, e82545_tx_thread, sc);\n\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, E82545_DEV_ID_82545EM_COPPER);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, E82545_VENDOR_ID_INTEL);\n\tpci_set_cfgdata8(pi,  PCIR_CLASS, PCIC_NETWORK);\n\tpci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_NETWORK_ETHERNET);\n\tpci_set_cfgdata16(pi, PCIR_SUBDEV_0, E82545_SUBDEV_ID);\n\tpci_set_cfgdata16(pi, PCIR_SUBVEND_0, E82545_VENDOR_ID_INTEL);\n\n\tpci_set_cfgdata8(pi,  PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);\n\tpci_set_cfgdata8(pi,  PCIR_INTPIN, 0x1);\n\n\t/* TODO: this card also supports msi, but the freebsd driver for it\n\t * does not, so I have not implemented it. */\n\tpci_lintr_request(pi);\n\n\tpci_emul_alloc_bar(pi, E82545_BAR_REGISTER, PCIBAR_MEM32,\n\t\tE82545_BAR_REGISTER_LEN);\n\tpci_emul_alloc_bar(pi, E82545_BAR_FLASH, PCIBAR_MEM32,\n\t\tE82545_BAR_FLASH_LEN);\n\tpci_emul_alloc_bar(pi, E82545_BAR_IO, PCIBAR_IO,\n\t\tE82545_BAR_IO_LEN);\n\n\t/*\n\t * Attempt to open the tap device and read the MAC address\n\t * if specified.  Copied from virtio-net, slightly modified.\n\t */\n    if (vmn_create(sc) == -1) {\n        return (-1);\n    }\n\n    if (print_mac == 1)\n    {\n        printf(\"MAC: %02x:%02x:%02x:%02x:%02x:%02x\\n\",\n               sc->vms->mac[0], sc->vms->mac[1], sc->vms->mac[2],\n               sc->vms->mac[3], sc->vms->mac[4], sc->vms->mac[5]);\n        exit(0);\n    }\n\n\t/* H/w initiated reset */\n\te82545_reset(sc, 0);\n\n\treturn (0);\n}\n\nstatic struct pci_devemu pci_de_e82545 = {\n\t.pe_emu = \t\"e1000\",\n\t.pe_init =\te82545_init,\n\t.pe_barwrite =\te82545_write,\n\t.pe_barread =\te82545_read\n};\nPCI_EMUL_SET(pci_de_e82545);\n\n"
  },
  {
    "path": "src/pci_emul.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <pthread.h>\n#include <errno.h>\n#include <assert.h>\n\n#include <xhyve/support/linker_set.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/acpi.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/inout.h>\n#include <xhyve/ioapic.h>\n#include <xhyve/mem.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/pci_irq.h>\n#include <xhyve/pci_lpc.h>\n\n#define CONF1_ADDR_PORT 0x0cf8\n#define CONF1_DATA_PORT0 0x0cfc\n#define CONF1_DATA_PORT1 0x0cfd\n#define CONF1_DATA_PORT2 0x0cfe\n#define CONF1_DATA_PORT3 0x0cff\n\n#define CONF1_ENABLE 0x80000000ul\n\n#define\tMAXBUSES (PCI_BUSMAX + 1)\n#define MAXSLOTS (PCI_SLOTMAX + 1)\n#define\tMAXFUNCS (PCI_FUNCMAX + 1)\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct funcinfo {\n\tchar *fi_name;\n\tchar *fi_param;\n\tstruct pci_devinst *fi_devi;\n};\n\nstruct intxinfo {\n\tint ii_count;\n\tint ii_pirq_pin;\n\tint ii_ioapic_irq;\n};\n\nstruct slotinfo {\n\tstruct intxinfo si_intpins[4];\n\tstruct funcinfo si_funcs[MAXFUNCS];\n};\n\nstruct businfo {\n\tuint16_t iobase, iolimit; /* I/O window */\n\tuint32_t membase32, memlimit32; /* mmio window below 4GB */\n\tuint64_t membase64, memlimit64; /* mmio window above 4GB */\n\tstruct slotinfo slotinfo[MAXSLOTS];\n};\n#pragma clang diagnostic pop\n\nstatic struct businfo *pci_businfo[MAXBUSES];\n\nSET_DECLARE(pci_devemu_set, struct pci_devemu);\n\nstatic uint64_t pci_emul_iobase;\nstatic uint64_t pci_emul_membase32;\nstatic uint64_t pci_emul_membase64;\n\n#define\tPCI_EMUL_IOBASE\t\t0x2000\n#define\tPCI_EMUL_IOLIMIT\t0x10000\n\n#define\tPCI_EMUL_ECFG_BASE\t0xE0000000\t\t    /* 3.5GB */\n#define\tPCI_EMUL_ECFG_SIZE\t(MAXBUSES * 1024 * 1024)    /* 1MB per bus */\nSYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE);\n\n#define\tPCI_EMUL_MEMLIMIT32\tPCI_EMUL_ECFG_BASE\n\n#define\tPCI_EMUL_MEMBASE64\t0xD000000000UL\n#define\tPCI_EMUL_MEMLIMIT64\t0xFD00000000UL\n\nstatic struct pci_devemu *pci_emul_finddev(char *name);\nstatic void pci_lintr_route(struct pci_devinst *pi);\nstatic void pci_lintr_update(struct pci_devinst *pi);\nstatic void pci_cfgrw(int vcpu, int in, int bus, int slot, int func, int coff,\n\tint bytes, uint32_t *val);\n\nstatic __inline void\nCFGWRITE(struct pci_devinst *pi, int coff, uint32_t val, int bytes)\n{\n\n\tif (bytes == 1)\n\t\tpci_set_cfgdata8(pi, coff, ((uint8_t) val));\n\telse if (bytes == 2)\n\t\tpci_set_cfgdata16(pi, coff, ((uint16_t) val));\n\telse\n\t\tpci_set_cfgdata32(pi, coff, val);\n}\n\nstatic __inline uint32_t\nCFGREAD(struct pci_devinst *pi, int coff, int bytes)\n{\n\n\tif (bytes == 1)\n\t\treturn (pci_get_cfgdata8(pi, coff));\n\telse if (bytes == 2)\n\t\treturn (pci_get_cfgdata16(pi, coff));\n\telse\n\t\treturn (pci_get_cfgdata32(pi, coff));\n}\n\n/*\n * I/O access\n */\n\n/*\n * Slot options are in the form:\n *\n *  <bus>:<slot>:<func>,<emul>[,<config>]\n *  <slot>[:<func>],<emul>[,<config>]\n *\n *  slot is 0..31\n *  func is 0..7\n *  emul is a string describing the type of PCI device e.g. virtio-net\n *  config is an optional string, depending on the device, that can be\n *  used for configuration.\n *   Examples are:\n *     1,virtio-net,tap0\n *     3:0,dummy\n */\nstatic void\npci_parse_slot_usage(char *aopt)\n{\n\tfprintf(stderr, \"Invalid PCI slot info field \\\"%s\\\"\\n\", aopt);\n}\n\nint\npci_parse_slot(char *opt)\n{\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tchar *emul, *config, *str, *cp;\n\tint error, bnum, snum, fnum;\n\n\terror = -1;\n\tstr = strdup(opt);\n\n\temul = config = NULL;\n\tif ((cp = strchr(str, ',')) != NULL) {\n\t\t*cp = '\\0';\n\t\temul = cp + 1;\n\t\tif ((cp = strchr(emul, ',')) != NULL) {\n\t\t\t*cp = '\\0';\n\t\t\tconfig = cp + 1;\n\t\t}\n\t} else {\n\t\tpci_parse_slot_usage(opt);\n\t\tgoto done;\n\t}\n\n\t/* <bus>:<slot>:<func> */\n\tif (sscanf(str, \"%d:%d:%d\", &bnum, &snum, &fnum) != 3) {\n\t\tbnum = 0;\n\t\t/* <slot>:<func> */\n\t\tif (sscanf(str, \"%d:%d\", &snum, &fnum) != 2) {\n\t\t\tfnum = 0;\n\t\t\t/* <slot> */\n\t\t\tif (sscanf(str, \"%d\", &snum) != 1) {\n\t\t\t\tsnum = -1;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (bnum < 0 || bnum >= MAXBUSES || snum < 0 || snum >= MAXSLOTS ||\n\t    fnum < 0 || fnum >= MAXFUNCS) {\n\t\tpci_parse_slot_usage(opt);\n\t\tgoto done;\n\t}\n\n\tif (pci_businfo[bnum] == NULL)\n\t\tpci_businfo[bnum] = calloc(1, sizeof(struct businfo));\n\n\tbi = pci_businfo[bnum];\n\tsi = &bi->slotinfo[snum];\n\n\tif (si->si_funcs[fnum].fi_name != NULL) {\n\t\tfprintf(stderr, \"pci slot %d:%d already occupied!\\n\",\n\t\t\tsnum, fnum);\n\t\tgoto done;\n\t}\n\n\tif (pci_emul_finddev(emul) == NULL) {\n\t\tfprintf(stderr, \"pci slot %d:%d: unknown device \\\"%s\\\"\\n\",\n\t\t\tsnum, fnum, emul);\n\t\tgoto done;\n\t}\n\n\terror = 0;\n\tsi->si_funcs[fnum].fi_name = emul;\n\tsi->si_funcs[fnum].fi_param = config;\n\ndone:\n\tif (error)\n\t\tfree(str);\n\n\treturn (error);\n}\n\nstatic int\npci_valid_pba_offset(struct pci_devinst *pi, uint64_t offset)\n{\n\n\tif (offset < pi->pi_msix.pba_offset)\n\t\treturn (0);\n\n\tif (offset >= pi->pi_msix.pba_offset + ((unsigned) pi->pi_msix.pba_size)) {\n\t\treturn (0);\n\t}\n\n\treturn (1);\n}\n\nint\npci_emul_msix_twrite(struct pci_devinst *pi, uint64_t offset, int size,\n\t\t     uint64_t value)\n{\n\tint msix_entry_offset;\n\tint tab_index;\n\tchar *dest;\n\n\t/* support only 4 or 8 byte writes */\n\tif (size != 4 && size != 8)\n\t\treturn (-1);\n\n\t/*\n\t * Return if table index is beyond what device supports\n\t */\n\ttab_index = (int) (offset / MSIX_TABLE_ENTRY_SIZE);\n\tif (tab_index >= pi->pi_msix.table_count)\n\t\treturn (-1);\n\n\tmsix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;\n\n\t/* support only aligned writes */\n\tif ((msix_entry_offset % size) != 0)\n\t\treturn (-1);\n\n\tdest = (char *)(pi->pi_msix.table + tab_index);\n\tdest += msix_entry_offset;\n\n\tif (size == 4)\n\t\t*((uint32_t *)((void *) dest)) = (uint32_t) value;\n\telse\n\t\t*((uint64_t *)((void *) dest)) = value;\n\n\treturn (0);\n}\n\nuint64_t\npci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size)\n{\n\tchar *dest;\n\tint msix_entry_offset;\n\tint tab_index;\n\tuint64_t retval = ~((uint64_t) 0);\n\n\t/*\n\t * The PCI standard only allows 4 and 8 byte accesses to the MSI-X\n\t * table but we also allow 1 byte access to accomodate reads from\n\t * ddb.\n\t */\n\tif (size != 1 && size != 4 && size != 8)\n\t\treturn (retval);\n\n\tmsix_entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;\n\n\t/* support only aligned reads */\n\tif ((msix_entry_offset % size) != 0) {\n\t\treturn (retval);\n\t}\n\n\ttab_index = (int) (offset / MSIX_TABLE_ENTRY_SIZE);\n\n\tif (tab_index < pi->pi_msix.table_count) {\n\t\t/* valid MSI-X Table access */\n\t\tdest = (char *)(pi->pi_msix.table + tab_index);\n\t\tdest += msix_entry_offset;\n\n\t\tif (size == 1)\n\t\t\tretval = *((uint8_t *)((void *) dest));\n\t\telse if (size == 4)\n\t\t\tretval = *((uint32_t *)((void *) dest));\n\t\telse\n\t\t\tretval = *((uint64_t *)((void *) dest));\n\t} else if (pci_valid_pba_offset(pi, offset)) {\n\t\t/* return 0 for PBA access */\n\t\tretval = 0;\n\t}\n\n\treturn (retval);\n}\n\nint\npci_msix_table_bar(struct pci_devinst *pi)\n{\n\n\tif (pi->pi_msix.table != NULL)\n\t\treturn (pi->pi_msix.table_bar);\n\telse\n\t\treturn (-1);\n}\n\nint\npci_msix_pba_bar(struct pci_devinst *pi)\n{\n\n\tif (pi->pi_msix.table != NULL)\n\t\treturn (pi->pi_msix.pba_bar);\n\telse\n\t\treturn (-1);\n}\n\nstatic int\npci_emul_io_handler(int vcpu, int in, int port, int bytes, uint32_t *eax,\n\tvoid *arg)\n{\n\tstruct pci_devinst *pdi = arg;\n\tstruct pci_devemu *pe = pdi->pi_d;\n\tuint64_t offset;\n\tint i;\n\n\tfor (i = 0; i <= PCI_BARMAX; i++) {\n\t\tif ((pdi->pi_bar[i].type == PCIBAR_IO) &&\n\t\t    (((uint64_t) port) >= pdi->pi_bar[i].addr) &&\n\t\t    (((uint64_t) (port + bytes)) <=\n\t\t    \t(pdi->pi_bar[i].addr + pdi->pi_bar[i].size)))\n\t\t{\n\t\t\toffset = ((uint64_t) port) - pdi->pi_bar[i].addr;\n\t\t\tif (in)\n\t\t\t\t*eax = (uint32_t) (*pe->pe_barread)(vcpu, pdi, i, offset,\n\t\t\t\t\tbytes);\n\t\t\telse\n\t\t\t\t(*pe->pe_barwrite)(vcpu, pdi, i, offset, bytes, *eax);\n\t\t\treturn (0);\n\t\t}\n\t}\n\treturn (-1);\n}\n\nstatic int\npci_emul_mem_handler(int vcpu, int dir, uint64_t addr,\n\t\t     int size, uint64_t *val, void *arg1, long arg2)\n{\n\tstruct pci_devinst *pdi = arg1;\n\tstruct pci_devemu *pe = pdi->pi_d;\n\tuint64_t offset;\n\tint bidx = (int) arg2;\n\n\tassert(bidx <= PCI_BARMAX);\n\tassert((pdi->pi_bar[bidx].type == PCIBAR_MEM32) ||\n\t\t(pdi->pi_bar[bidx].type == PCIBAR_MEM64));\n\tassert((addr >= pdi->pi_bar[bidx].addr) &&\n\t\t((addr + ((uint64_t) size)) <=\n\t\t\t(pdi->pi_bar[bidx].addr + pdi->pi_bar[bidx].size)));\n\n\toffset = addr - pdi->pi_bar[bidx].addr;\n\n\tif (dir == MEM_F_WRITE) {\n\t\tif (size == 8) {\n\t\t\t(*pe->pe_barwrite)(vcpu, pdi, bidx, offset, 4, *val & 0xffffffff);\n\t\t\t(*pe->pe_barwrite)(vcpu, pdi, bidx, offset + 4, 4, *val >> 32);\n\t\t} else {\n\t\t\t(*pe->pe_barwrite)(vcpu, pdi, bidx, offset, size, *val);\n\t\t}\n\t} else {\n\t\tif (size == 8) {\n\t\t\t*val = (*pe->pe_barread)(vcpu, pdi, bidx, offset, 4);\n\t\t\t*val |= (*pe->pe_barread)(vcpu, pdi, bidx, offset + 4, 4) << 32;\n\t\t} else {\n\t\t\t*val = (*pe->pe_barread)(vcpu, pdi, bidx, offset, size);\n\t\t}\n\t}\n\n\treturn (0);\n}\n\n\nstatic int\npci_emul_alloc_resource(uint64_t *baseptr, uint64_t limit, uint64_t size,\n\t\t\tuint64_t *addr)\n{\n\tuint64_t base;\n\n\tassert((size & (size - 1)) == 0);\t/* must be a power of 2 */\n\n\tbase = roundup2(*baseptr, size);\n\n\tif (base + size <= limit) {\n\t\t*addr = base;\n\t\t*baseptr = base + size;\n\t\treturn (0);\n\t} else\n\t\treturn (-1);\n}\n\nint\npci_emul_alloc_bar(struct pci_devinst *pdi, int idx, enum pcibar_type type,\n\t\t   uint64_t size)\n{\n\n\treturn (pci_emul_alloc_pbar(pdi, idx, 0, type, size));\n}\n\n/*\n * Register (or unregister) the MMIO or I/O region associated with the BAR\n * register 'idx' of an emulated pci device.\n */\nstatic void\nmodify_bar_registration(struct pci_devinst *pi, int idx, int registration)\n{\n\tint error;\n\tstruct inout_port iop;\n\tstruct mem_range mr;\n\n\tswitch (pi->pi_bar[idx].type) {\n\tcase PCIBAR_IO:\n\t\tbzero(&iop, sizeof(struct inout_port));\n\t\tiop.name = pi->pi_name;\n\t\tiop.port = (int) pi->pi_bar[idx].addr;\n\t\tiop.size = (int)pi->pi_bar[idx].size;\n\t\tif (registration) {\n\t\t\tiop.flags = IOPORT_F_INOUT;\n\t\t\tiop.handler = pci_emul_io_handler;\n\t\t\tiop.arg = pi;\n\t\t\terror = register_inout(&iop);\n\t\t} else \n\t\t\terror = unregister_inout(&iop);\n\t\tbreak;\n\tcase PCIBAR_MEM32:\n\tcase PCIBAR_MEM64:\n\t\tbzero(&mr, sizeof(struct mem_range));\n\t\tmr.name = pi->pi_name;\n\t\tmr.base = pi->pi_bar[idx].addr;\n\t\tmr.size = pi->pi_bar[idx].size;\n\t\tif (registration) {\n\t\t\tmr.flags = MEM_F_RW;\n\t\t\tmr.handler = pci_emul_mem_handler;\n\t\t\tmr.arg1 = pi;\n\t\t\tmr.arg2 = idx;\n\t\t\terror = register_mem(&mr);\n\t\t} else\n\t\t\terror = unregister_mem(&mr);\n\t\tbreak;\n\tcase PCIBAR_NONE:\n\tcase PCIBAR_MEMHI64:\n\t\terror = EINVAL;\n\t\tbreak;\n\t}\n\tassert(error == 0);\n}\n\nstatic void\nunregister_bar(struct pci_devinst *pi, int idx)\n{\n\n\tmodify_bar_registration(pi, idx, 0);\n}\n\nstatic void\nregister_bar(struct pci_devinst *pi, int idx)\n{\n\n\tmodify_bar_registration(pi, idx, 1);\n}\n\n/* Are we decoding i/o port accesses for the emulated pci device? */\nstatic int\nporten(struct pci_devinst *pi)\n{\n\tuint16_t cmd;\n\n\tcmd = pci_get_cfgdata16(pi, PCIR_COMMAND);\n\n\treturn (cmd & PCIM_CMD_PORTEN);\n}\n\n/* Are we decoding memory accesses for the emulated pci device? */\nstatic int\nmemen(struct pci_devinst *pi)\n{\n\tuint16_t cmd;\n\n\tcmd = pci_get_cfgdata16(pi, PCIR_COMMAND);\n\n\treturn (cmd & PCIM_CMD_MEMEN);\n}\n\n/*\n * Update the MMIO or I/O address that is decoded by the BAR register.\n *\n * If the pci device has enabled the address space decoding then intercept\n * the address range decoded by the BAR register.\n */\nstatic void\nupdate_bar_address(struct  pci_devinst *pi, uint64_t addr, int idx, int type)\n{\n\tint decode;\n\n\tif (pi->pi_bar[idx].type == PCIBAR_IO)\n\t\tdecode = porten(pi);\n\telse\n\t\tdecode = memen(pi);\n\n\tif (decode)\n\t\tunregister_bar(pi, idx);\n\n\tswitch (type) {\n\tcase PCIBAR_IO:\n\tcase PCIBAR_MEM32:\n\t\tpi->pi_bar[idx].addr = addr;\n\t\tbreak;\n\tcase PCIBAR_MEM64:\n\t\tpi->pi_bar[idx].addr &= ~0xffffffffUL;\n\t\tpi->pi_bar[idx].addr |= addr;\n\t\tbreak;\n\tcase PCIBAR_MEMHI64:\n\t\tpi->pi_bar[idx].addr &= 0xffffffff;\n\t\tpi->pi_bar[idx].addr |= addr;\n\t\tbreak;\n\tdefault:\n\t\tassert(0);\n\t}\n\n\tif (decode)\n\t\tregister_bar(pi, idx);\n}\n\nint\npci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase,\n\t\t    enum pcibar_type type, uint64_t size)\n{\n\tint error;\n\tuint64_t *baseptr, limit, addr, mask, lobits, bar;\n\n\tassert(idx >= 0 && idx <= PCI_BARMAX);\n\n\taddr = 0;\n\tlimit = 0;\n\n\tif ((size & (size - 1)) != 0)\n\t\tsize = 1UL << flsl((long) size); /* round up to a power of 2 */\n\n\t/* Enforce minimum BAR sizes required by the PCI standard */\n\tif (type == PCIBAR_IO) {\n\t\tif (size < 4)\n\t\t\tsize = 4;\n\t} else {\n\t\tif (size < 16)\n\t\t\tsize = 16;\n\t}\n\n\tswitch (type) {\n\tcase PCIBAR_NONE:\n\t\tbaseptr = NULL;\n\t\taddr = mask = lobits = 0;\n\t\tbreak;\n\tcase PCIBAR_IO:\n\t\tbaseptr = &pci_emul_iobase;\n\t\tlimit = PCI_EMUL_IOLIMIT;\n\t\tmask = PCIM_BAR_IO_BASE;\n\t\tlobits = PCIM_BAR_IO_SPACE;\n\t\tbreak;\n\tcase PCIBAR_MEM64:\n\t\t/*\n\t\t * XXX\n\t\t * Some drivers do not work well if the 64-bit BAR is allocated\n\t\t * above 4GB. Allow for this by allocating small requests under\n\t\t * 4GB unless then allocation size is larger than some arbitrary\n\t\t * number (32MB currently).\n\t\t */\n\t\tif (size > 32 * 1024 * 1024) {\n\t\t\t/*\n\t\t\t * XXX special case for device requiring peer-peer DMA\n\t\t\t */\n\t\t\tif (size == 0x100000000UL)\n\t\t\t\tbaseptr = &hostbase;\n\t\t\telse\n\t\t\t\tbaseptr = &pci_emul_membase64;\n\t\t\tlimit = PCI_EMUL_MEMLIMIT64;\n\t\t\tmask = PCIM_BAR_MEM_BASE;\n\t\t\tlobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |\n\t\t\t\t PCIM_BAR_MEM_PREFETCH;\n\t\t\tbreak;\n\t\t} else {\n\t\t\tbaseptr = &pci_emul_membase32;\n\t\t\tlimit = PCI_EMUL_MEMLIMIT32;\n\t\t\tmask = PCIM_BAR_MEM_BASE;\n\t\t\tlobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64;\n\t\t}\n\t\tbreak;\n\tcase PCIBAR_MEM32:\n\t\tbaseptr = &pci_emul_membase32;\n\t\tlimit = PCI_EMUL_MEMLIMIT32;\n\t\tmask = PCIM_BAR_MEM_BASE;\n\t\tlobits = PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;\n\t\tbreak;\n\tcase PCIBAR_MEMHI64:\n\t\tprintf(\"pci_emul_alloc_base: invalid bar type %d\\n\", type);\n\t\tassert(0);\n\t}\n\n\tif (baseptr != NULL) {\n\t\terror = pci_emul_alloc_resource(baseptr, limit, size, &addr);\n\t\tif (error != 0)\n\t\t\treturn (error);\n\t}\n\n\tpdi->pi_bar[idx].type = type;\n\tpdi->pi_bar[idx].addr = addr;\n\tpdi->pi_bar[idx].size = size;\n\n\t/* Initialize the BAR register in config space */\n\tbar = (addr & mask) | lobits;\n\tpci_set_cfgdata32(pdi, PCIR_BAR(idx), ((uint32_t) bar));\n\n\tif (type == PCIBAR_MEM64) {\n\t\tassert(idx + 1 <= PCI_BARMAX);\n\t\tpdi->pi_bar[idx + 1].type = PCIBAR_MEMHI64;\n\t\tpci_set_cfgdata32(pdi, PCIR_BAR(idx + 1), bar >> 32);\n\t}\n\t\n\tregister_bar(pdi, idx);\n\n\treturn (0);\n}\n\n#define\tCAP_START_OFFSET\t0x40\nstatic int\npci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)\n{\n\tint i, capoff, reallen;\n\tuint16_t sts;\n\n\tassert(caplen > 0);\n\n\treallen = roundup2(caplen, 4);\t\t/* dword aligned */\n\n\tsts = pci_get_cfgdata16(pi, PCIR_STATUS);\n\tif ((sts & PCIM_STATUS_CAPPRESENT) == 0)\n\t\tcapoff = CAP_START_OFFSET;\n\telse\n\t\tcapoff = pi->pi_capend + 1;\n\n\t/* Check if we have enough space */\n\tif (capoff + reallen > PCI_REGMAX + 1)\n\t\treturn (-1);\n\n\t/* Set the previous capability pointer */\n\tif ((sts & PCIM_STATUS_CAPPRESENT) == 0) {\n\t\tpci_set_cfgdata8(pi, PCIR_CAP_PTR, ((uint8_t) capoff));\n\t\tpci_set_cfgdata16(pi, PCIR_STATUS, sts|PCIM_STATUS_CAPPRESENT);\n\t} else\n\t\tpci_set_cfgdata8(pi, pi->pi_prevcap + 1, ((uint8_t) capoff));\n\n\t/* Copy the capability */\n\tfor (i = 0; i < caplen; i++)\n\t\tpci_set_cfgdata8(pi, capoff + i, capdata[i]);\n\n\t/* Set the next capability pointer */\n\tpci_set_cfgdata8(pi, capoff + 1, 0);\n\n\tpi->pi_prevcap = capoff;\n\tpi->pi_capend = capoff + reallen - 1;\n\treturn (0);\n}\n\nstatic struct pci_devemu *\npci_emul_finddev(char *name)\n{\n\tstruct pci_devemu **pdpp, *pdp;\n\n\tSET_FOREACH(pdpp, pci_devemu_set) {\n\t\tpdp = *pdpp;\n\t\tif (!strcmp(pdp->pe_emu, name)) {\n\t\t\treturn (pdp);\n\t\t}\n\t}\n\n\treturn (NULL);\n}\n\nstatic int\npci_emul_init(struct pci_devemu *pde, int bus, int slot,\n    int func, struct funcinfo *fi)\n{\n\tstruct pci_devinst *pdi;\n\tint err;\n\n\tpdi = calloc(1, sizeof(struct pci_devinst));\n\n\tpdi->pi_bus = (uint8_t) bus;\n\tpdi->pi_slot = (uint8_t) slot;\n\tpdi->pi_func = (uint8_t) func;\n\tpthread_mutex_init(&pdi->pi_lintr.lock, NULL);\n\tpdi->pi_lintr.pin = 0;\n\tpdi->pi_lintr.state = IDLE;\n\tpdi->pi_lintr.pirq_pin = 0;\n\tpdi->pi_lintr.ioapic_irq = 0;\n\tpdi->pi_d = pde;\n\tsnprintf(pdi->pi_name, PI_NAMESZ, \"%s-pci-%d\", pde->pe_emu, slot);\n\n\t/* Disable legacy interrupts */\n\tpci_set_cfgdata8(pdi, PCIR_INTLINE, 255);\n\tpci_set_cfgdata8(pdi, PCIR_INTPIN, 0);\n\n\tpci_set_cfgdata8(pdi, PCIR_COMMAND,\n\t\t    PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);\n\n\terr = (*pde->pe_init)(pdi, fi->fi_param);\n\tif (err == 0)\n\t\tfi->fi_devi = pdi;\n\telse\n\t\tfree(pdi);\n\n\treturn (err);\n}\n\nvoid\npci_populate_msicap(struct msicap *msicap, int msgnum, int nextptr)\n{\n\tint mmc;\n\n\tCTASSERT(sizeof(struct msicap) == 14);\n\n\t/* Number of msi messages must be a power of 2 between 1 and 32 */\n\tassert((msgnum & (msgnum - 1)) == 0 && msgnum >= 1 && msgnum <= 32);\n\tmmc = ffs(msgnum) - 1;\n\n\tbzero(msicap, sizeof(struct msicap));\n\tmsicap->capid = PCIY_MSI;\n\tmsicap->nextptr = (uint8_t) nextptr;\n\tmsicap->msgctrl = (uint16_t) (PCIM_MSICTRL_64BIT | (mmc << 1));\n}\n\nint\npci_emul_add_msicap(struct pci_devinst *pi, int msgnum)\n{\n\tstruct msicap msicap;\n\n\tpci_populate_msicap(&msicap, msgnum, 0);\n\n\treturn (pci_emul_add_capability(pi, (u_char *)&msicap, sizeof(msicap)));\n}\n\nstatic void\npci_populate_msixcap(struct msixcap *msixcap, int msgnum, int barnum,\n\t\t     uint32_t msix_tab_size)\n{\n\tCTASSERT(sizeof(struct msixcap) == 12);\n\n\tassert(msix_tab_size % 4096 == 0);\n\n\tbzero(msixcap, sizeof(struct msixcap));\n\tmsixcap->capid = PCIY_MSIX;\n\n\t/*\n\t * Message Control Register, all fields set to\n\t * zero except for the Table Size.\n\t * Note: Table size N is encoded as N-1\n\t */\n\tmsixcap->msgctrl = (uint16_t) (msgnum - 1);\n\n\t/*\n\t * MSI-X BAR setup:\n\t * - MSI-X table start at offset 0\n\t * - PBA table starts at a 4K aligned offset after the MSI-X table\n\t */\n\tmsixcap->table_info = barnum & PCIM_MSIX_BIR_MASK;\n\tmsixcap->pba_info = msix_tab_size | (barnum & PCIM_MSIX_BIR_MASK);\n}\n\nstatic void\npci_msix_table_init(struct pci_devinst *pi, int table_entries)\n{\n\tint i, table_size;\n\n\tassert(table_entries > 0);\n\tassert(table_entries <= MAX_MSIX_TABLE_ENTRIES);\n\n\ttable_size = table_entries * MSIX_TABLE_ENTRY_SIZE;\n\tpi->pi_msix.table = calloc(1, ((size_t) table_size));\n\n\t/* set mask bit of vector control register */\n\tfor (i = 0; i < table_entries; i++)\n\t\tpi->pi_msix.table[i].vector_control |= PCIM_MSIX_VCTRL_MASK;\n}\n\nint\npci_emul_add_msixcap(struct pci_devinst *pi, int msgnum, int barnum)\n{\n\tuint32_t tab_size;\n\tstruct msixcap msixcap;\n\n\tassert(msgnum >= 1 && msgnum <= MAX_MSIX_TABLE_ENTRIES);\n\tassert(barnum >= 0 && barnum <= PCIR_MAX_BAR_0);\n\t\n\ttab_size = (uint32_t) (msgnum * MSIX_TABLE_ENTRY_SIZE);\n\n\t/* Align table size to nearest 4K */\n\ttab_size = roundup2(tab_size, 4096u);\n\n\tpi->pi_msix.table_bar = barnum;\n\tpi->pi_msix.pba_bar   = barnum;\n\tpi->pi_msix.table_offset = 0;\n\tpi->pi_msix.table_count = msgnum;\n\tpi->pi_msix.pba_offset = tab_size;\n\tpi->pi_msix.pba_size = PBA_SIZE(msgnum);\n\n\tpci_msix_table_init(pi, msgnum);\n\n\tpci_populate_msixcap(&msixcap, msgnum, barnum, tab_size);\n\n\t/* allocate memory for MSI-X Table and PBA */\n\tpci_emul_alloc_bar(pi, barnum, PCIBAR_MEM32,\n\t\t(tab_size + ((uint32_t) pi->pi_msix.pba_size)));\n\n\treturn (pci_emul_add_capability(pi, (u_char *)&msixcap,\n\t\t\t\t\tsizeof(msixcap)));\n}\n\nvoid\nmsixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,\n\t\t int bytes, uint32_t val)\n{\n\tuint16_t msgctrl, rwmask;\n\tint off, table_bar;\n\t\n\toff = offset - capoff;\n\ttable_bar = pi->pi_msix.table_bar;\n\t/* Message Control Register */\n\tif (off == 2 && bytes == 2) {\n\t\trwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;\n\t\tmsgctrl = pci_get_cfgdata16(pi, offset);\n\t\tmsgctrl &= ~rwmask;\n\t\tmsgctrl |= val & rwmask;\n\t\tval = msgctrl;\n\n\t\tpi->pi_msix.enabled = val & PCIM_MSIXCTRL_MSIX_ENABLE;\n\t\tpi->pi_msix.function_mask = val & PCIM_MSIXCTRL_FUNCTION_MASK;\n\t\tpci_lintr_update(pi);\n\t} \n\t\n\tCFGWRITE(pi, offset, val, bytes);\n}\n\nvoid\nmsicap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,\n\t\tint bytes, uint32_t val)\n{\n\tuint16_t msgctrl, rwmask, msgdata, mme;\n\tuint32_t addrlo;\n\n\t/*\n\t * If guest is writing to the message control register make sure\n\t * we do not overwrite read-only fields.\n\t */\n\tif ((offset - capoff) == 2 && bytes == 2) {\n\t\trwmask = PCIM_MSICTRL_MME_MASK | PCIM_MSICTRL_MSI_ENABLE;\n\t\tmsgctrl = pci_get_cfgdata16(pi, offset);\n\t\tmsgctrl &= ~rwmask;\n\t\tmsgctrl |= val & rwmask;\n\t\tval = msgctrl;\n\n\t\taddrlo = pci_get_cfgdata32(pi, capoff + 4);\n\t\tif (msgctrl & PCIM_MSICTRL_64BIT)\n\t\t\tmsgdata = pci_get_cfgdata16(pi, capoff + 12);\n\t\telse\n\t\t\tmsgdata = pci_get_cfgdata16(pi, capoff + 8);\n\n\t\tmme = msgctrl & PCIM_MSICTRL_MME_MASK;\n\t\tpi->pi_msi.enabled = msgctrl & PCIM_MSICTRL_MSI_ENABLE ? 1 : 0;\n\t\tif (pi->pi_msi.enabled) {\n\t\t\tpi->pi_msi.addr = addrlo;\n\t\t\tpi->pi_msi.msg_data = msgdata;\n\t\t\tpi->pi_msi.maxmsgnum = 1 << (mme >> 4);\n\t\t} else {\n\t\t\tpi->pi_msi.maxmsgnum = 0;\n\t\t}\n\t\tpci_lintr_update(pi);\n\t}\n\n\tCFGWRITE(pi, offset, val, bytes);\n}\n\nstatic void\npciecap_cfgwrite(struct pci_devinst *pi, UNUSED int capoff, int offset,\n\t\t int bytes, uint32_t val)\n{\n\n\t/* XXX don't write to the readonly parts */\n\tCFGWRITE(pi, offset, val, bytes);\n}\n\n#define\tPCIECAP_VERSION\t0x2\nint\npci_emul_add_pciecap(struct pci_devinst *pi, int type)\n{\n\tint err;\n\tstruct pciecap pciecap;\n\n\tCTASSERT(sizeof(struct pciecap) == 60);\n\n\tif (type != PCIEM_TYPE_ROOT_PORT)\n\t\treturn (-1);\n\n\tbzero(&pciecap, sizeof(pciecap));\n\n\tpciecap.capid = PCIY_EXPRESS;\n\tpciecap.pcie_capabilities = PCIECAP_VERSION | PCIEM_TYPE_ROOT_PORT;\n\tpciecap.link_capabilities = 0x411;\t/* gen1, x1 */\n\tpciecap.link_status = 0x11;\t\t/* gen1, x1 */\n\n\terr = pci_emul_add_capability(pi, (u_char *)&pciecap, sizeof(pciecap));\n\treturn (err);\n}\n\n/*\n * This function assumes that 'coff' is in the capabilities region of the\n * config space.\n */\nstatic void\npci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes, uint32_t val)\n{\n\tint capid;\n\tuint8_t capoff, nextoff;\n\n\t/* Do not allow un-aligned writes */\n\tif ((offset & (bytes - 1)) != 0)\n\t\treturn;\n\n\t/* Find the capability that we want to update */\n\tcapoff = CAP_START_OFFSET;\n\twhile (1) {\n\t\tnextoff = pci_get_cfgdata8(pi, capoff + 1);\n\t\tif (nextoff == 0)\n\t\t\tbreak;\n\t\tif (offset >= capoff && offset < nextoff)\n\t\t\tbreak;\n\n\t\tcapoff = nextoff;\n\t}\n\tassert(offset >= capoff);\n\n\t/*\n\t * Capability ID and Next Capability Pointer are readonly.\n\t * However, some o/s's do 4-byte writes that include these.\n\t * For this case, trim the write back to 2 bytes and adjust\n\t * the data.\n\t */\n\tif (offset == capoff || offset == capoff + 1) {\n\t\tif (offset == capoff && bytes == 4) {\n\t\t\tbytes = 2;\n\t\t\toffset += 2;\n\t\t\tval >>= 16;\n\t\t} else\n\t\t\treturn;\n\t}\n\n\tcapid = pci_get_cfgdata8(pi, capoff);\n\tswitch (capid) {\n\tcase PCIY_MSI:\n\t\tmsicap_cfgwrite(pi, capoff, offset, bytes, val);\n\t\tbreak;\n\tcase PCIY_MSIX:\n\t\tmsixcap_cfgwrite(pi, capoff, offset, bytes, val);\n\t\tbreak;\n\tcase PCIY_EXPRESS:\n\t\tpciecap_cfgwrite(pi, capoff, offset, bytes, val);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nstatic int\npci_emul_iscap(struct pci_devinst *pi, int offset)\n{\n\tuint16_t sts;\n\n\tsts = pci_get_cfgdata16(pi, PCIR_STATUS);\n\tif ((sts & PCIM_STATUS_CAPPRESENT) != 0) {\n\t\tif (offset >= CAP_START_OFFSET && offset <= pi->pi_capend)\n\t\t\treturn (1);\n\t}\n\treturn (0);\n}\n\nstatic int\npci_emul_fallback_handler(UNUSED int vcpu, int dir, UNUSED uint64_t addr,\n\tUNUSED int size, uint64_t *val, UNUSED void *arg1, UNUSED long arg2)\n{\n\t/*\n\t * Ignore writes; return 0xff's for reads. The mem read code\n\t * will take care of truncating to the correct size.\n\t */\n\tif (dir == MEM_F_READ) {\n\t\t*val = 0xffffffffffffffff;\n\t}\n\n\treturn (0);\n}\n\nstatic int\npci_emul_ecfg_handler(int vcpu, int dir, uint64_t addr, int bytes,\n\tuint64_t *val, UNUSED void *arg1, UNUSED long arg2)\n{\n\tint bus, slot, func, coff, in;\n\n\tcoff = addr & 0xfff;\n\tfunc = (addr >> 12) & 0x7;\n\tslot = (addr >> 15) & 0x1f;\n\tbus = (addr >> 20) & 0xff;\n\tin = (dir == MEM_F_READ);\n\tif (in)\n\t\t*val = ~0UL;\n\tpci_cfgrw(vcpu, in, bus, slot, func, coff, bytes, (uint32_t *)val);\n\treturn (0);\n}\n\nuint64_t\npci_ecfg_base(void)\n{\n\n\treturn (PCI_EMUL_ECFG_BASE);\n}\n\n#define\tBUSIO_ROUNDUP\t\t32\n#define\tBUSMEM_ROUNDUP\t\t(1024 * 1024)\n\nint\ninit_pci(void)\n{\n\tstruct mem_range mr;\n\tstruct pci_devemu *pde;\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tstruct funcinfo *fi;\n\tsize_t lowmem;\n\tint bus, slot, func;\n\tint error;\n\n\tpci_emul_iobase = PCI_EMUL_IOBASE;\n\tpci_emul_membase32 = xh_vm_get_lowmem_limit();\n\tpci_emul_membase64 = PCI_EMUL_MEMBASE64;\n\n\tfor (bus = 0; bus < MAXBUSES; bus++) {\n\t\tif ((bi = pci_businfo[bus]) == NULL)\n\t\t\tcontinue;\n\t\t/* \n\t\t * Keep track of the i/o and memory resources allocated to\n\t\t * this bus.\n\t\t */\n\t\tbi->iobase = (uint16_t) pci_emul_iobase;\n\t\tbi->membase32 = (uint32_t) pci_emul_membase32;\n\t\tbi->membase64 = (uint32_t) pci_emul_membase64;\n\n\t\tfor (slot = 0; slot < MAXSLOTS; slot++) {\n\t\t\tsi = &bi->slotinfo[slot];\n\t\t\tfor (func = 0; func < MAXFUNCS; func++) {\n\t\t\t\tfi = &si->si_funcs[func];\n\t\t\t\tif (fi->fi_name == NULL)\n\t\t\t\t\tcontinue;\n\t\t\t\tpde = pci_emul_finddev(fi->fi_name);\n\t\t\t\tassert(pde != NULL);\n\t\t\t\terror = pci_emul_init(pde, bus, slot, func, fi);\n\t\t\t\tif (error)\n\t\t\t\t\treturn (error);\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Add some slop to the I/O and memory resources decoded by\n\t\t * this bus to give a guest some flexibility if it wants to\n\t\t * reprogram the BARs.\n\t\t */\n\t\tpci_emul_iobase += BUSIO_ROUNDUP;\n\t\tpci_emul_iobase = roundup2(pci_emul_iobase, ((uint32_t) BUSIO_ROUNDUP));\n\t\tbi->iolimit = (uint16_t) pci_emul_iobase;\n\n\t\tpci_emul_membase32 += BUSMEM_ROUNDUP;\n\t\tpci_emul_membase32 = roundup2(pci_emul_membase32,\n\t\t\t((uint64_t) BUSMEM_ROUNDUP));\n\t\tbi->memlimit32 = (uint32_t) pci_emul_membase32;\n\n\t\tpci_emul_membase64 += BUSMEM_ROUNDUP;\n\t\tpci_emul_membase64 = roundup2(pci_emul_membase64,\n\t\t\t((uint64_t) BUSMEM_ROUNDUP));\n\t\tbi->memlimit64 = pci_emul_membase64;\n\t}\n\n\t/*\n\t * PCI backends are initialized before routing INTx interrupts\n\t * so that LPC devices are able to reserve ISA IRQs before\n\t * routing PIRQ pins.\n\t */\n\tfor (bus = 0; bus < MAXBUSES; bus++) {\n\t\tif ((bi = pci_businfo[bus]) == NULL)\n\t\t\tcontinue;\n\n\t\tfor (slot = 0; slot < MAXSLOTS; slot++) {\n\t\t\tsi = &bi->slotinfo[slot];\n\t\t\tfor (func = 0; func < MAXFUNCS; func++) {\n\t\t\t\tfi = &si->si_funcs[func];\n\t\t\t\tif (fi->fi_devi == NULL)\n\t\t\t\t\tcontinue;\n\t\t\t\tpci_lintr_route(fi->fi_devi);\n\t\t\t}\n\t\t}\n\t}\n\tlpc_pirq_routed();\n\n\t/*\n\t * The guest physical memory map looks like the following:\n\t * [0,\t\t    lowmem)\t\tguest system memory\n\t * [lowmem,\t    lowmem_limit)\tmemory hole (may be absent)\n\t * [lowmem_limit,   0xE0000000)\t\tPCI hole (32-bit BAR allocation)\n\t * [0xE0000000,\t    0xF0000000)\t\tPCI extended config window\n\t * [0xF0000000,\t    4GB)\t\tLAPIC, IOAPIC, HPET, firmware\n\t * [4GB,\t    4GB + highmem)\n\t */\n\n\t/*\n\t * Accesses to memory addresses that are not allocated to system\n\t * memory or PCI devices return 0xff's.\n\t */\n\tlowmem = xh_vm_get_lowmem_size();\n\tbzero(&mr, sizeof(struct mem_range));\n\tmr.name = \"PCI hole\";\n\tmr.flags = MEM_F_RW | MEM_F_IMMUTABLE;\n\tmr.base = lowmem;\n\tmr.size = (4ULL * 1024 * 1024 * 1024) - lowmem;\n\tmr.handler = pci_emul_fallback_handler;\n\terror = register_mem_fallback(&mr);\n\tassert(error == 0);\n\n\t/* PCI extended config space */\n\tbzero(&mr, sizeof(struct mem_range));\n\tmr.name = \"PCI ECFG\";\n\tmr.flags = MEM_F_RW | MEM_F_IMMUTABLE;\n\tmr.base = PCI_EMUL_ECFG_BASE;\n\tmr.size = PCI_EMUL_ECFG_SIZE;\n\tmr.handler = pci_emul_ecfg_handler;\n\terror = register_mem(&mr);\n\tassert(error == 0);\n\n\treturn (0);\n}\n\nstatic void\npci_apic_prt_entry(UNUSED int bus, int slot, int pin, UNUSED int pirq_pin,\n\tint ioapic_irq, UNUSED void *arg)\n{\n\n\tdsdt_line(\"  Package ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    0x%X,\", slot << 16 | 0xffff);\n\tdsdt_line(\"    0x%02X,\", pin - 1);\n\tdsdt_line(\"    Zero,\");\n\tdsdt_line(\"    0x%X\", ioapic_irq);\n\tdsdt_line(\"  },\");\n}\n\nstatic void\npci_pirq_prt_entry(UNUSED int bus, int slot, int pin, int pirq_pin,\n\tUNUSED int ioapic_irq, UNUSED void *arg)\n{\n\tchar *name;\n\n\tname = lpc_pirq_name(pirq_pin);\n\tif (name == NULL)\n\t\treturn;\n\tdsdt_line(\"  Package ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    0x%X,\", slot << 16 | 0xffff);\n\tdsdt_line(\"    0x%02X,\", pin - 1);\n\tdsdt_line(\"    %s,\", name);\n\tdsdt_line(\"    0x00\");\n\tdsdt_line(\"  },\");\n\tfree(name);\n}\n\n/*\n * A bhyve virtual machine has a flat PCI hierarchy with a root port\n * corresponding to each PCI bus.\n */\n#if ACPITBL_AML\nstatic void\npci_bus_write_dsdt(int bus)\n{\n\tstruct businfo *bi;\n\n\t/*\n\t * If there are no devices on this 'bus' then just return.\n\t */\n\tif ((bi = pci_businfo[bus]) == NULL) {\n\t\t/*\n\t\t * Bus 0 is special because it decodes the I/O ports used\n\t\t * for PCI config space access even if there are no devices\n\t\t * on it.\n\t\t */\n\t\tif (bus != 0)\n\t\t\treturn;\n\t}\n\n\tdsdt_fixup(bus, bi->iobase, bi->iolimit, bi->membase32, bi->memlimit32,\n\t\tbi->membase64, bi->memlimit64);\n\n\t(void) pci_pirq_prt_entry;\n\t(void) pci_apic_prt_entry;\n}\n#else\nstatic void\npci_bus_write_dsdt(int bus)\n{\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tstruct pci_devinst *pi;\n\tint count, func, slot;\n\n\t/*\n\t * If there are no devices on this 'bus' then just return.\n\t */\n\tif ((bi = pci_businfo[bus]) == NULL) {\n\t\t/*\n\t\t * Bus 0 is special because it decodes the I/O ports used\n\t\t * for PCI config space access even if there are no devices\n\t\t * on it.\n\t\t */\n\t\tif (bus != 0)\n\t\t\treturn;\n\t}\n\n\tdsdt_line(\"  Device (PC%02X)\", bus);\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Name (_HID, EisaId (\\\"PNP0A03\\\"))\");\n\tdsdt_line(\"    Name (_ADR, Zero)\");\n\n\tdsdt_line(\"    Method (_BBN, 0, NotSerialized)\");\n\tdsdt_line(\"    {\");\n\tdsdt_line(\"        Return (0x%08X)\", bus);\n\tdsdt_line(\"    }\");\n\tdsdt_line(\"    Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"    {\");\n\tdsdt_line(\"      WordBusNumber (ResourceProducer, MinFixed, \"\n\t    \"MaxFixed, PosDecode,\");\n\tdsdt_line(\"        0x0000,             // Granularity\");\n\tdsdt_line(\"        0x%04X,             // Range Minimum\", bus);\n\tdsdt_line(\"        0x%04X,             // Range Maximum\", bus);\n\tdsdt_line(\"        0x0000,             // Translation Offset\");\n\tdsdt_line(\"        0x0001,             // Length\");\n\tdsdt_line(\"        ,, )\");\n\n\tif (bus == 0) {\n\t\tdsdt_indent(3);\n\t\tdsdt_fixed_ioport(0xCF8, 8);\n\t\tdsdt_unindent(3);\n\n\t\tdsdt_line(\"      WordIO (ResourceProducer, MinFixed, MaxFixed, \"\n\t\t    \"PosDecode, EntireRange,\");\n\t\tdsdt_line(\"        0x0000,             // Granularity\");\n\t\tdsdt_line(\"        0x0000,             // Range Minimum\");\n\t\tdsdt_line(\"        0x0CF7,             // Range Maximum\");\n\t\tdsdt_line(\"        0x0000,             // Translation Offset\");\n\t\tdsdt_line(\"        0x0CF8,             // Length\");\n\t\tdsdt_line(\"        ,, , TypeStatic)\");\n\n\t\tdsdt_line(\"      WordIO (ResourceProducer, MinFixed, MaxFixed, \"\n\t\t    \"PosDecode, EntireRange,\");\n\t\tdsdt_line(\"        0x0000,             // Granularity\");\n\t\tdsdt_line(\"        0x0D00,             // Range Minimum\");\n\t\tdsdt_line(\"        0x%04X,             // Range Maximum\",\n\t\t    PCI_EMUL_IOBASE - 1);\n\t\tdsdt_line(\"        0x0000,             // Translation Offset\");\n\t\tdsdt_line(\"        0x%04X,             // Length\",\n\t\t    PCI_EMUL_IOBASE - 0x0D00);\n\t\tdsdt_line(\"        ,, , TypeStatic)\");\n\n\t\tif (bi == NULL) {\n\t\t\tdsdt_line(\"    })\");\n\t\t\tgoto done;\n\t\t}\n\t}\n\tassert(bi != NULL);\n\n\t/* i/o window */\n\tdsdt_line(\"      WordIO (ResourceProducer, MinFixed, MaxFixed, \"\n\t    \"PosDecode, EntireRange,\");\n\tdsdt_line(\"        0x0000,             // Granularity\");\n\tdsdt_line(\"        0x%04X,             // Range Minimum\", bi->iobase);\n\tdsdt_line(\"        0x%04X,             // Range Maximum\",\n\t    bi->iolimit - 1);\n\tdsdt_line(\"        0x0000,             // Translation Offset\");\n\tdsdt_line(\"        0x%04X,             // Length\",\n\t    bi->iolimit - bi->iobase);\n\tdsdt_line(\"        ,, , TypeStatic)\");\n\n\t/* mmio window (32-bit) */\n\tdsdt_line(\"      DWordMemory (ResourceProducer, PosDecode, \"\n\t    \"MinFixed, MaxFixed, NonCacheable, ReadWrite,\");\n\tdsdt_line(\"        0x00000000,         // Granularity\");\n\tdsdt_line(\"        0x%08X,         // Range Minimum\\n\", bi->membase32);\n\tdsdt_line(\"        0x%08X,         // Range Maximum\\n\",\n\t    bi->memlimit32 - 1);\n\tdsdt_line(\"        0x00000000,         // Translation Offset\");\n\tdsdt_line(\"        0x%08X,         // Length\\n\",\n\t    bi->memlimit32 - bi->membase32);\n\tdsdt_line(\"        ,, , AddressRangeMemory, TypeStatic)\");\n\n\t/* mmio window (64-bit) */\n\tdsdt_line(\"      QWordMemory (ResourceProducer, PosDecode, \"\n\t    \"MinFixed, MaxFixed, NonCacheable, ReadWrite,\");\n\tdsdt_line(\"        0x0000000000000000, // Granularity\");\n\tdsdt_line(\"        0x%016lX, // Range Minimum\\n\", bi->membase64);\n\tdsdt_line(\"        0x%016lX, // Range Maximum\\n\",\n\t    bi->memlimit64 - 1);\n\tdsdt_line(\"        0x0000000000000000, // Translation Offset\");\n\tdsdt_line(\"        0x%016lX, // Length\\n\",\n\t    bi->memlimit64 - bi->membase64);\n\tdsdt_line(\"        ,, , AddressRangeMemory, TypeStatic)\");\n\tdsdt_line(\"    })\");\n\n\tcount = pci_count_lintr(bus);\n\tif (count != 0) {\n\t\tdsdt_indent(2);\n\t\tdsdt_line(\"Name (PPRT, Package ()\");\n\t\tdsdt_line(\"{\");\n\t\tpci_walk_lintr(bus, pci_pirq_prt_entry, NULL);\n \t\tdsdt_line(\"})\");\n\t\tdsdt_line(\"Name (APRT, Package ()\");\n\t\tdsdt_line(\"{\");\n\t\tpci_walk_lintr(bus, pci_apic_prt_entry, NULL);\n \t\tdsdt_line(\"})\");\n\t\tdsdt_line(\"Method (_PRT, 0, NotSerialized)\");\n\t\tdsdt_line(\"{\");\n\t\tdsdt_line(\"  If (PICM)\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    Return (APRT)\");\n\t\tdsdt_line(\"  }\");\n\t\tdsdt_line(\"  Else\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    Return (PPRT)\");\n\t\tdsdt_line(\"  }\");\n\t\tdsdt_line(\"}\");\n\t\tdsdt_unindent(2);\n\t}\n\n\tdsdt_indent(2);\n\tfor (slot = 0; slot < MAXSLOTS; slot++) {\n\t\tsi = &bi->slotinfo[slot];\n\t\tfor (func = 0; func < MAXFUNCS; func++) {\n\t\t\tpi = si->si_funcs[func].fi_devi;\n\t\t\tif (pi != NULL && pi->pi_d->pe_write_dsdt != NULL)\n\t\t\t\tpi->pi_d->pe_write_dsdt(pi);\n\t\t}\n\t}\n\tdsdt_unindent(2);\ndone:\n\tdsdt_line(\"  }\");\n}\n#endif\n\n#if ACPITBL_AML\nvoid\npci_write_dsdt(void)\n{\n\tint bus;\n\n\tfor (bus = 0; bus < MAXBUSES; bus++) {\n\t\tpci_bus_write_dsdt(bus);\n\t}\n}\n#else\nvoid\npci_write_dsdt(void)\n{\n\tint bus;\n\n\tdsdt_indent(1);\n\tdsdt_line(\"Name (PICM, 0x00)\");\n\tdsdt_line(\"Method (_PIC, 1, NotSerialized)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Store (Arg0, PICM)\");\n\tdsdt_line(\"}\");\n\tdsdt_line(\"\");\n\tdsdt_line(\"Scope (_SB)\");\n\tdsdt_line(\"{\");\n\tfor (bus = 0; bus < MAXBUSES; bus++)\n\t\tpci_bus_write_dsdt(bus);\n\tdsdt_line(\"}\");\n\tdsdt_unindent(1);\n}\n#endif\n\nint\npci_bus_configured(int bus)\n{\n\tassert(bus >= 0 && bus < MAXBUSES);\n\treturn (pci_businfo[bus] != NULL);\n}\n\nint\npci_msi_enabled(struct pci_devinst *pi)\n{\n\treturn (pi->pi_msi.enabled);\n}\n\nstatic int\npci_msi_maxmsgnum(struct pci_devinst *pi)\n{\n\tif (pi->pi_msi.enabled)\n\t\treturn (pi->pi_msi.maxmsgnum);\n\telse\n\t\treturn (0);\n}\n\nint\npci_msix_enabled(struct pci_devinst *pi)\n{\n\n\treturn (pi->pi_msix.enabled && !pi->pi_msi.enabled);\n}\n\nvoid\npci_generate_msix(struct pci_devinst *pi, int index)\n{\n\tstruct msix_table_entry *mte;\n\n\tif (!pci_msix_enabled(pi))\n\t\treturn;\n\n\tif (pi->pi_msix.function_mask)\n\t\treturn;\n\n\tif (index >= pi->pi_msix.table_count)\n\t\treturn;\n\n\tmte = &pi->pi_msix.table[index];\n\tif ((mte->vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {\n\t\t/* XXX Set PBA bit if interrupt is disabled */\n\t\txh_vm_lapic_msi(mte->addr, mte->msg_data);\n\t}\n}\n\nvoid\npci_generate_msi(struct pci_devinst *pi, int index)\n{\n\n\tif (pci_msi_enabled(pi) && index < pci_msi_maxmsgnum(pi)) {\n\t\txh_vm_lapic_msi(pi->pi_msi.addr, pi->pi_msi.msg_data +\n\t\t\t((uint64_t) index));\n\t}\n}\n\nstatic bool\npci_lintr_permitted(struct pci_devinst *pi)\n{\n\tuint16_t cmd;\n\n\tcmd = pci_get_cfgdata16(pi, PCIR_COMMAND);\n\treturn (!(pi->pi_msi.enabled || pi->pi_msix.enabled ||\n\t\t(cmd & PCIM_CMD_INTxDIS)));\n}\n\nvoid\npci_lintr_request(struct pci_devinst *pi)\n{\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tint bestpin, bestcount, pin;\n\n\tbi = pci_businfo[pi->pi_bus];\n\tassert(bi != NULL);\n\n\t/*\n\t * Just allocate a pin from our slot.  The pin will be\n\t * assigned IRQs later when interrupts are routed.\n\t */\n\tsi = &bi->slotinfo[pi->pi_slot];\n\tbestpin = 0;\n\tbestcount = si->si_intpins[0].ii_count;\n\tfor (pin = 1; pin < 4; pin++) {\n\t\tif (si->si_intpins[pin].ii_count < bestcount) {\n\t\t\tbestpin = pin;\n\t\t\tbestcount = si->si_intpins[pin].ii_count;\n\t\t}\n\t}\n\n\tsi->si_intpins[bestpin].ii_count++;\n\tpi->pi_lintr.pin = (int8_t) (bestpin + 1);\n\tpci_set_cfgdata8(pi, PCIR_INTPIN, ((uint8_t) (bestpin + 1)));\n}\n\nstatic void\npci_lintr_route(struct pci_devinst *pi)\n{\n\tstruct businfo *bi;\n\tstruct intxinfo *ii;\n\n\tif (pi->pi_lintr.pin == 0)\n\t\treturn;\n\n\tbi = pci_businfo[pi->pi_bus];\n\tassert(bi != NULL);\n\tii = &bi->slotinfo[pi->pi_slot].si_intpins[pi->pi_lintr.pin - 1];\n\n\t/*\n\t * Attempt to allocate an I/O APIC pin for this intpin if one\n\t * is not yet assigned.\n\t */\n\tif (ii->ii_ioapic_irq == 0)\n\t\tii->ii_ioapic_irq = ioapic_pci_alloc_irq(pi);\n\tassert(ii->ii_ioapic_irq > 0);\n\n\t/*\n\t * Attempt to allocate a PIRQ pin for this intpin if one is\n\t * not yet assigned.\n\t */\n\tif (ii->ii_pirq_pin == 0)\n\t\tii->ii_pirq_pin = pirq_alloc_pin(pi);\n\tassert(ii->ii_pirq_pin > 0);\n\n\tpi->pi_lintr.ioapic_irq = ii->ii_ioapic_irq;\n\tpi->pi_lintr.pirq_pin = ii->ii_pirq_pin;\n\tpci_set_cfgdata8(pi, PCIR_INTLINE, ((uint8_t) pirq_irq(ii->ii_pirq_pin)));\n}\n\nvoid\npci_lintr_assert(struct pci_devinst *pi)\n{\n\n\tassert(pi->pi_lintr.pin > 0);\n\n\tpthread_mutex_lock(&pi->pi_lintr.lock);\n\tif (pi->pi_lintr.state == IDLE) {\n\t\tif (pci_lintr_permitted(pi)) {\n\t\t\tpi->pi_lintr.state = ASSERTED;\n\t\t\tpci_irq_assert(pi);\n\t\t} else\n\t\t\tpi->pi_lintr.state = PENDING;\n\t}\n\tpthread_mutex_unlock(&pi->pi_lintr.lock);\n}\n\nvoid\npci_lintr_deassert(struct pci_devinst *pi)\n{\n\n\tassert(pi->pi_lintr.pin > 0);\n\n\tpthread_mutex_lock(&pi->pi_lintr.lock);\n\tif (pi->pi_lintr.state == ASSERTED) {\n\t\tpi->pi_lintr.state = IDLE;\n\t\tpci_irq_deassert(pi);\n\t} else if (pi->pi_lintr.state == PENDING)\n\t\tpi->pi_lintr.state = IDLE;\n\tpthread_mutex_unlock(&pi->pi_lintr.lock);\n}\n\nstatic void\npci_lintr_update(struct pci_devinst *pi)\n{\n\n\tpthread_mutex_lock(&pi->pi_lintr.lock);\n\tif (pi->pi_lintr.state == ASSERTED && !pci_lintr_permitted(pi)) {\n\t\tpci_irq_deassert(pi);\n\t\tpi->pi_lintr.state = PENDING;\n\t} else if (pi->pi_lintr.state == PENDING && pci_lintr_permitted(pi)) {\n\t\tpi->pi_lintr.state = ASSERTED;\n\t\tpci_irq_assert(pi);\n\t}\n\tpthread_mutex_unlock(&pi->pi_lintr.lock);\n}\n\nint\npci_count_lintr(int bus)\n{\n\tint count, slot, pin;\n\tstruct slotinfo *slotinfo;\n\n\tcount = 0;\n\tif (pci_businfo[bus] != NULL) {\n\t\tfor (slot = 0; slot < MAXSLOTS; slot++) {\n\t\t\tslotinfo = &pci_businfo[bus]->slotinfo[slot];\n\t\t\tfor (pin = 0; pin < 4; pin++) {\n\t\t\t\tif (slotinfo->si_intpins[pin].ii_count != 0)\n\t\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t}\n\treturn (count);\n}\n\nvoid\npci_walk_lintr(int bus, pci_lintr_cb cb, void *arg)\n{\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tstruct intxinfo *ii;\n\tint slot, pin;\n\n\tif ((bi = pci_businfo[bus]) == NULL)\n\t\treturn;\n\n\tfor (slot = 0; slot < MAXSLOTS; slot++) {\n\t\tsi = &bi->slotinfo[slot];\n\t\tfor (pin = 0; pin < 4; pin++) {\n\t\t\tii = &si->si_intpins[pin];\n\t\t\tif (ii->ii_count != 0)\n\t\t\t\tcb(bus, slot, pin + 1, ii->ii_pirq_pin,\n\t\t\t\t    ii->ii_ioapic_irq, arg);\n\t\t}\n\t}\n}\n\n/*\n * Return 1 if the emulated device in 'slot' is a multi-function device.\n * Return 0 otherwise.\n */\nstatic int\npci_emul_is_mfdev(int bus, int slot)\n{\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tint f, numfuncs;\n\n\tnumfuncs = 0;\n\tif ((bi = pci_businfo[bus]) != NULL) {\n\t\tsi = &bi->slotinfo[slot];\n\t\tfor (f = 0; f < MAXFUNCS; f++) {\n\t\t\tif (si->si_funcs[f].fi_devi != NULL) {\n\t\t\t\tnumfuncs++;\n\t\t\t}\n\t\t}\n\t}\n\treturn (numfuncs > 1);\n}\n\n/*\n * Ensure that the PCIM_MFDEV bit is properly set (or unset) depending on\n * whether or not is a multi-function being emulated in the pci 'slot'.\n */\nstatic void\npci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv)\n{\n\tint mfdev;\n\n\tif (off <= PCIR_HDRTYPE && off + bytes > PCIR_HDRTYPE) {\n\t\tmfdev = pci_emul_is_mfdev(bus, slot);\n\t\tswitch (bytes) {\n\t\tcase 1:\n\t\tcase 2:\n\t\t\t*rv &= ~((uint32_t) PCIM_MFDEV);\n\t\t\tif (mfdev) {\n\t\t\t\t*rv |= PCIM_MFDEV;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\t*rv &= ~((uint32_t) (PCIM_MFDEV << 16));\n\t\t\tif (mfdev) {\n\t\t\t\t*rv |= (PCIM_MFDEV << 16);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nstatic void\npci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes)\n{\n\tint i, rshift;\n\tuint32_t cmd, cmd2, changed, old, readonly;\n\n\tcmd = pci_get_cfgdata16(pi, PCIR_COMMAND);\t/* stash old value */\n\n\t/*\n\t * From PCI Local Bus Specification 3.0 sections 6.2.2 and 6.2.3.\n\t *\n\t * XXX Bits 8, 11, 12, 13, 14 and 15 in the status register are\n\t * 'write 1 to clear'. However these bits are not set to '1' by\n\t * any device emulation so it is simpler to treat them as readonly.\n\t */\n\trshift = (coff & 0x3) * 8;\n\treadonly = 0xFFFFF880 >> rshift;\n\n\told = CFGREAD(pi, coff, bytes);\n\tnew &= ~readonly;\n\tnew |= (old & readonly);\n\tCFGWRITE(pi, coff, new, bytes);\t\t\t/* update config */\n\n\tcmd2 = pci_get_cfgdata16(pi, PCIR_COMMAND);\t/* get updated value */\n\tchanged = cmd ^ cmd2;\n\n\t/*\n\t * If the MMIO or I/O address space decoding has changed then\n\t * register/unregister all BARs that decode that address space.\n\t */\n\tfor (i = 0; i <= PCI_BARMAX; i++) {\n\t\tswitch (pi->pi_bar[i].type) {\n\t\t\tcase PCIBAR_NONE:\n\t\t\tcase PCIBAR_MEMHI64:\n\t\t\t\tbreak;\n\t\t\tcase PCIBAR_IO:\n\t\t\t\t/* I/O address space decoding changed? */\n\t\t\t\tif (changed & PCIM_CMD_PORTEN) {\n\t\t\t\t\tif (porten(pi))\n\t\t\t\t\t\tregister_bar(pi, i);\n\t\t\t\t\telse\n\t\t\t\t\t\tunregister_bar(pi, i);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase PCIBAR_MEM32:\n\t\t\tcase PCIBAR_MEM64:\n\t\t\t\t/* MMIO address space decoding changed? */\n\t\t\t\tif (changed & PCIM_CMD_MEMEN) {\n\t\t\t\t\tif (memen(pi))\n\t\t\t\t\t\tregister_bar(pi, i);\n\t\t\t\t\telse\n\t\t\t\t\t\tunregister_bar(pi, i);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/*\n\t * If INTx has been unmasked and is pending, assert the\n\t * interrupt.\n\t */\n\tpci_lintr_update(pi);\n}\t\n\nstatic void\npci_cfgrw(int vcpu, int in, int bus, int slot, int func, int coff, int bytes,\n\tuint32_t *eax)\n{\n\tstruct businfo *bi;\n\tstruct slotinfo *si;\n\tstruct pci_devinst *pi;\n\tstruct pci_devemu *pe;\n\tint idx, needcfg;\n\tuint64_t addr, bar, mask;\n\n\tif ((bi = pci_businfo[bus]) != NULL) {\n\t\tsi = &bi->slotinfo[slot];\n\t\tpi = si->si_funcs[func].fi_devi;\n\t} else\n\t\tpi = NULL;\n\n\t/*\n\t * Just return if there is no device at this slot:func or if the\n\t * the guest is doing an un-aligned access.\n\t */\n\tif (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) ||\n\t    (coff & (bytes - 1)) != 0) {\n\t\tif (in)\n\t\t\t*eax = 0xffffffff;\n\t\treturn;\n\t}\n\n\t/*\n\t * Ignore all writes beyond the standard config space and return all\n\t * ones on reads.\n\t */\n\tif (coff >= PCI_REGMAX + 1) {\n\t\tif (in) {\n\t\t\t*eax = 0xffffffff;\n\t\t\t/*\n\t\t\t * Extended capabilities begin at offset 256 in config\n\t\t\t * space. Absence of extended capabilities is signaled\n\t\t\t * with all 0s in the extended capability header at\n\t\t\t * offset 256.\n\t\t\t */\n\t\t\tif (coff <= PCI_REGMAX + 4)\n\t\t\t\t*eax = 0x00000000;\n\t\t}\n\t\treturn;\n\t}\n\n\tpe = pi->pi_d;\n\n\t/*\n\t * Config read\n\t */\n\tif (in) {\n\t\t/* Let the device emulation override the default handler */\n\t\tif (pe->pe_cfgread != NULL) {\n\t\t\tneedcfg = pe->pe_cfgread(vcpu, pi, coff, bytes,\n\t\t\t    eax);\n\t\t} else {\n\t\t\tneedcfg = 1;\n\t\t}\n\n\t\tif (needcfg)\n\t\t\t*eax = CFGREAD(pi, coff, bytes);\n\n\t\tpci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax);\n\t} else {\n\t\t/* Let the device emulation override the default handler */\n\t\tif (pe->pe_cfgwrite != NULL &&\n\t\t    (*pe->pe_cfgwrite)(vcpu, pi, coff, bytes, *eax) == 0)\n\t\t\treturn;\n\n\t\t/*\n\t\t * Special handling for write to BAR registers\n\t\t */\n\t\tif (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) {\n\t\t\t/*\n\t\t\t * Ignore writes to BAR registers that are not\n\t\t\t * 4-byte aligned.\n\t\t\t */\n\t\t\tif (bytes != 4 || (coff & 0x3) != 0)\n\t\t\t\treturn;\n\t\t\tidx = (coff - PCIR_BAR(0)) / 4;\n\t\t\tmask = ~(pi->pi_bar[idx].size - 1);\n\t\t\tswitch (pi->pi_bar[idx].type) {\n\t\t\tcase PCIBAR_NONE:\n\t\t\t\tpi->pi_bar[idx].addr = bar = 0;\n\t\t\t\tbreak;\n\t\t\tcase PCIBAR_IO:\n\t\t\t\taddr = *eax & mask;\n\t\t\t\taddr &= 0xffff;\n\t\t\t\tbar = addr | PCIM_BAR_IO_SPACE;\n\t\t\t\t/*\n\t\t\t\t * Register the new BAR value for interception\n\t\t\t\t */\n\t\t\t\tif (addr != pi->pi_bar[idx].addr) {\n\t\t\t\t\tupdate_bar_address(pi, addr, idx,\n\t\t\t\t\t\t\t   PCIBAR_IO);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase PCIBAR_MEM32:\n\t\t\t\taddr = bar = *eax & mask;\n\t\t\t\tbar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_32;\n\t\t\t\tif (addr != pi->pi_bar[idx].addr) {\n\t\t\t\t\tupdate_bar_address(pi, addr, idx,\n\t\t\t\t\t\t\t   PCIBAR_MEM32);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase PCIBAR_MEM64:\n\t\t\t\taddr = bar = *eax & mask;\n\t\t\t\tbar |= PCIM_BAR_MEM_SPACE | PCIM_BAR_MEM_64 |\n\t\t\t\t       PCIM_BAR_MEM_PREFETCH;\n\t\t\t\tif (addr != (uint32_t)pi->pi_bar[idx].addr) {\n\t\t\t\t\tupdate_bar_address(pi, addr, idx,\n\t\t\t\t\t\t\t   PCIBAR_MEM64);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase PCIBAR_MEMHI64:\n\t\t\t\tmask = ~(pi->pi_bar[idx - 1].size - 1);\n\t\t\t\taddr = ((uint64_t)*eax << 32) & mask;\n\t\t\t\tbar = addr >> 32;\n\t\t\t\tif (bar != pi->pi_bar[idx - 1].addr >> 32) {\n\t\t\t\t\tupdate_bar_address(pi, addr, idx - 1,\n\t\t\t\t\t\t\t   PCIBAR_MEMHI64);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpci_set_cfgdata32(pi, coff, ((uint32_t) bar));\n\n\t\t} else if (pci_emul_iscap(pi, coff)) {\n\t\t\tpci_emul_capwrite(pi, coff, bytes, *eax);\n\t\t} else if (coff >= PCIR_COMMAND && coff < PCIR_REVID) {\n\t\t\tpci_emul_cmdsts_write(pi, coff, *eax, bytes);\n\t\t} else {\n\t\t\tCFGWRITE(pi, coff, *eax, bytes);\n\t\t}\n\t}\n}\n\nstatic int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff;\n\nstatic int\npci_emul_cfgaddr(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tuint32_t x;\n\n\tif (bytes != 4) {\n\t\tif (in)\n\t\t\t*eax = (bytes == 2) ? 0xffff : 0xff;\n\t\treturn (0);\n\t}\n\n\tif (in) {\n\t\tx = (uint32_t) ((cfgbus << 16) | (cfgslot << 11) | (cfgfunc << 8) |\n\t\t\tcfgoff);\n\n\t\tif (cfgenable)\n\t\t\tx |= CONF1_ENABLE;\n\t\t*eax = x;\n\t} else {\n\t\tx = *eax;\n\t\tcfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;\n\t\tcfgoff = x & PCI_REGMAX;\n\t\tcfgfunc = (x >> 8) & PCI_FUNCMAX;\n\t\tcfgslot = (x >> 11) & PCI_SLOTMAX;\n\t\tcfgbus = (x >> 16) & PCI_BUSMAX;\n\t}\n\n\treturn (0);\n}\nINOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr);\n\nstatic int\npci_emul_cfgdata(int vcpu, int in, int port, int bytes, uint32_t *eax,\n\tUNUSED void *arg)\n{\n\tint coff;\n\n\tassert(bytes == 1 || bytes == 2 || bytes == 4);\n\n\tcoff = cfgoff + (port - CONF1_DATA_PORT0);\n\tif (cfgenable) {\n\t\tpci_cfgrw(vcpu, in, cfgbus, cfgslot, cfgfunc, coff, bytes,\n\t\t    eax);\n\t} else {\n\t\t/* Ignore accesses to cfgdata if not enabled by cfgaddr */\n\t\tif (in)\n\t\t\t*eax = 0xffffffff;\n\t}\n\treturn (0);\n}\n\nINOUT_PORT(pci_cfgdata, CONF1_DATA_PORT0, IOPORT_F_INOUT, pci_emul_cfgdata);\nINOUT_PORT(pci_cfgdata, CONF1_DATA_PORT1, IOPORT_F_INOUT, pci_emul_cfgdata);\nINOUT_PORT(pci_cfgdata, CONF1_DATA_PORT2, IOPORT_F_INOUT, pci_emul_cfgdata);\nINOUT_PORT(pci_cfgdata, CONF1_DATA_PORT3, IOPORT_F_INOUT, pci_emul_cfgdata);\n\n#define PCI_EMUL_TEST\n#ifdef PCI_EMUL_TEST\n/*\n * Define a dummy test device\n */\n#define DIOSZ 8\n#define DMEMSZ 4096\nstruct pci_emul_dsoftc {\n\tuint8_t   ioregs[DIOSZ];\n\tuint8_t\t  memregs[2][DMEMSZ];\n};\n\n#define\tPCI_EMUL_MSI_MSGS 4\n\nstatic int\npci_emul_dinit(struct pci_devinst *pi, UNUSED char *opts)\n{\n\tint error;\n\tstruct pci_emul_dsoftc *sc;\n\n\tsc = calloc(1, sizeof(struct pci_emul_dsoftc));\n\n\tpi->pi_arg = sc;\n\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, 0x0001);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, 0x10DD);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, 0x02);\n\n\terror = pci_emul_add_msicap(pi, PCI_EMUL_MSI_MSGS);\n\tassert(error == 0);\n\n\terror = pci_emul_alloc_bar(pi, 0, PCIBAR_IO, DIOSZ);\n\tassert(error == 0);\n\n\terror = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, DMEMSZ);\n\tassert(error == 0);\n\n\terror = pci_emul_alloc_bar(pi, 2, PCIBAR_MEM32, DMEMSZ);\n\tassert(error == 0);\n\n\treturn (0);\n}\n\nstatic void\npci_emul_diow(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size, uint64_t value)\n{\n\tint i;\n\tstruct pci_emul_dsoftc *sc = pi->pi_arg;\n\n\tif (baridx == 0) {\n\t\tif (offset + ((uint64_t) size) > DIOSZ) {\n\t\t\tprintf(\"diow: iow too large, offset %llu size %d\\n\",\n\t\t\t       offset, size);\n\t\t\treturn;\n\t\t}\n\n\t\tif (size == 1) {\n\t\t\tsc->ioregs[offset] = value & 0xff;\n\t\t} else if (size == 2) {\n\t\t\t*(uint16_t *)((void *) &sc->ioregs[offset]) = value & 0xffff;\n\t\t} else if (size == 4) {\n\t\t\t*(uint32_t *)((void *) &sc->ioregs[offset]) = (uint32_t) value;\n\t\t} else {\n\t\t\tprintf(\"diow: iow unknown size %d\\n\", size);\n\t\t}\n\n\t\t/*\n\t\t * Special magic value to generate an interrupt\n\t\t */\n\t\tif (offset == 4 && size == 4 && pci_msi_enabled(pi))\n\t\t\tpci_generate_msi(pi, ((int) (value %\n\t\t\t\t((uint64_t) pci_msi_maxmsgnum(pi)))));\n\n\t\tif (value == 0xabcdef) {\n\t\t\tfor (i = 0; i < pci_msi_maxmsgnum(pi); i++)\n\t\t\t\tpci_generate_msi(pi, i);\n\t\t}\n\t}\n\n\tif (baridx == 1 || baridx == 2) {\n\t\tif (offset + ((uint16_t) size) > DMEMSZ) {\n\t\t\tprintf(\"diow: memw too large, offset %llu size %d\\n\",\n\t\t\t       offset, size);\n\t\t\treturn;\n\t\t}\n\n\t\ti = baridx - 1;\t\t/* 'memregs' index */\n\n\t\tif (size == 1) {\n\t\t\tsc->memregs[i][offset] = (uint8_t) value;\n\n\t\t} else if (size == 2) {\n\t\t\t*(uint16_t *)((void *) &sc->memregs[i][offset]) = (uint16_t) value;\n\t\t} else if (size == 4) {\n\t\t\t*(uint32_t *)((void *) &sc->memregs[i][offset]) = (uint32_t) value;\n\t\t} else if (size == 8) {\n\t\t\t*(uint64_t *)((void *) &sc->memregs[i][offset]) = value;\n\t\t} else {\n\t\t\tprintf(\"diow: memw unknown size %d\\n\", size);\n\t\t}\n\t\t\n\t\t/*\n\t\t * magic interrupt ??\n\t\t */\n\t}\n\n\tif (baridx > 2) {\n\t\tprintf(\"diow: unknown bar idx %d\\n\", baridx);\n\t}\n}\n\nstatic uint64_t\npci_emul_dior(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size)\n{\n\tstruct pci_emul_dsoftc *sc = pi->pi_arg;\n\tuint32_t value;\n\tint i;\n\n\tvalue = 0;\n\n\tif (baridx == 0) {\n\t\tif (offset + ((uint64_t) size) > DIOSZ) {\n\t\t\tprintf(\"dior: ior too large, offset %llu size %d\\n\",\n\t\t\t       offset, size);\n\t\t\treturn (0);\n\t\t}\n\t\n\t\tif (size == 1) {\n\t\t\tvalue = sc->ioregs[offset];\n\t\t} else if (size == 2) {\n\t\t\tvalue = *(uint16_t *)((void *) &sc->ioregs[offset]);\n\t\t} else if (size == 4) {\n\t\t\tvalue = *(uint32_t *)((void *) &sc->ioregs[offset]);\n\t\t} else {\n\t\t\tprintf(\"dior: ior unknown size %d\\n\", size);\n\t\t}\n\t}\n\n\tif (baridx == 1 || baridx == 2) {\n\t\tif (offset + ((uint64_t) size) > DMEMSZ) {\n\t\t\tprintf(\"dior: memr too large, offset %llu size %d\\n\",\n\t\t\t       offset, size);\n\t\t\treturn (0);\n\t\t}\n\t\t\n\t\ti = baridx - 1;\t\t/* 'memregs' index */\n\n\t\tif (size == 1) {\n\t\t\tvalue = sc->memregs[i][offset];\n\t\t} else if (size == 2) {\n\t\t\tvalue = *(uint16_t *) ((void *) &sc->memregs[i][offset]);\n\t\t} else if (size == 4) {\n\t\t\tvalue = *(uint32_t *) ((void *) &sc->memregs[i][offset]);\n\t\t} else if (size == 8) {\n\t\t\tvalue = (uint32_t) *(uint64_t *) ((void *) &sc->memregs[i][offset]);\n\t\t} else {\n\t\t\tprintf(\"dior: ior unknown size %d\\n\", size);\n\t\t}\n\t}\n\n\n\tif (baridx > 2) {\n\t\tprintf(\"dior: unknown bar idx %d\\n\", baridx);\n\t\treturn (0);\n\t}\n\n\treturn (value);\n}\n\nstatic struct pci_devemu pci_dummy = {\n\t.pe_emu = \"dummy\",\n\t.pe_init = pci_emul_dinit,\n\t.pe_barwrite = pci_emul_diow,\n\t.pe_barread = pci_emul_dior\n};\nPCI_EMUL_SET(pci_dummy);\n\n#endif /* PCI_EMUL_TEST */\n"
  },
  {
    "path": "src/pci_fbuf.c",
    "content": "/*-\n * Copyright (c) 2015 Nahanni Systems, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n#include <sys/mman.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <errno.h>\n#include <unistd.h>\n\n#include <xhyve/support/misc.h>\n\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_api.h>\n\n#include <xhyve/bhyvegc.h>\n#include <xhyve/console.h>\n#include <xhyve/inout.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/rfb.h>\n#include <xhyve/vga.h>\n\n/*\n * bhyve Framebuffer device emulation.\n * BAR0 points to the current mode information.\n * BAR1 is the 32-bit framebuffer address.\n *\n *  -s <b>,fbuf,wait,vga=on|io|off,rfb=<ip>:port,w=width,h=height\n */\n\nstatic int fbuf_debug = 1;\n#define\tDEBUG_INFO\t1\n#define\tDEBUG_VERBOSE\t4\n#define\tDPRINTF(level, params)  if (level <= fbuf_debug) printf params\n\n\n#define\tKB\t(1024UL)\n#define\tMB\t(1024UL * KB)\n\n#define\tDMEMSZ\t128\n\n#define\tFB_SIZE\t\t(16*MB)\n\n#define COLS_MAX\t1920\n#define\tROWS_MAX\t1200\n\n#define COLS_DEFAULT\t1024\n#define ROWS_DEFAULT\t768\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-macros\"\n\n#define COLS_MIN\t640\n#define ROWS_MIN\t480\n\n#pragma clang diagnostic pop\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct pci_fbuf_softc {\n\tstruct pci_devinst *fsc_pi;\n\tstruct {\n\t\tuint32_t fbsize;\n\t\tuint16_t width;\n\t\tuint16_t height;\n\t\tuint16_t depth;\n\t\tuint16_t refreshrate;\n\t\tuint8_t  reserved[116];\n\t} memregs;\n\n\t/* rfb server */\n\tchar      *rfb_host;\n\tchar      *rfb_password;\n\tint       rfb_port;\n\tint       rfb_wait;\n\tint       vga_enabled;\n\tint\t  vga_full;\n\n\tuint64_t  fbaddr;\n\tchar      *fb_base;\n\tuint16_t  gc_width;\n\tuint16_t  gc_height;\n\tvoid      *vgasc;\n\tstruct bhyvegc_image *gc_image;\n};\n\n#pragma clang diagnostic pop\n\nstatic struct pci_fbuf_softc *fbuf_sc;\n\n#define\tPCI_FBUF_MSI_MSGS\t 4\n\nstatic void\npci_fbuf_usage(char *opt)\n{\n\n\tfprintf(stderr, \"Invalid fbuf emulation \\\"%s\\\"\\r\\n\", opt);\n\tfprintf(stderr, \"fbuf: {wait,}{vga=on|io|off,}rfb=<ip>:port\\r\\n\");\n}\n\nstatic void\npci_fbuf_write(UNUSED int vcpu, struct pci_devinst *pi,\n\t       int baridx, uint64_t offset, int size, uint64_t value)\n{\n\tstruct pci_fbuf_softc *sc;\n\tuint8_t *p;\n\n    assert(baridx == 0);\n    assert(size >= 0);\n\n\tsc = pi->pi_arg;\n\n\tDPRINTF(DEBUG_VERBOSE,\n\t    (\"fbuf wr: offset 0x%llx, size: %d, value: 0x%llx\\n\",\n\t    offset, size, value));\n\n\tif (offset + (unsigned int)size > DMEMSZ) {\n\t\tprintf(\"fbuf: write too large, offset %lld size %d\\n\",\n\t\t       offset, size);\n\t\treturn;\n\t}\n\n\tp = (uint8_t *)&sc->memregs + offset;\n\n\tswitch (size) {\n\tcase 1:\n\t\t*p = (uint8_t)value;\n\t\tbreak;\n\tcase 2:\n        write_uint16_unaligned(p, (uint16_t)value);\n\t\tbreak;\n\tcase 4:\n        write_uint32_unaligned(p, (uint32_t)value);\n\t\tbreak;\n\tcase 8:\n        write_uint64_unaligned(p, value);\n\t\tbreak;\n\tdefault:\n\t\tprintf(\"fbuf: write unknown size %d\\n\", size);\n\t\tbreak;\n\t}\n\n\tif (!sc->gc_image->vgamode && sc->memregs.width == 0 &&\n\t    sc->memregs.height == 0) {\n\t\tDPRINTF(DEBUG_INFO, (\"switching to VGA mode\\r\\n\"));\n\t\tsc->gc_image->vgamode = 1;\n\t\tsc->gc_width = 0;\n\t\tsc->gc_height = 0;\n\t} else if (sc->gc_image->vgamode && sc->memregs.width != 0 &&\n\t    sc->memregs.height != 0) {\n\t\tDPRINTF(DEBUG_INFO, (\"switching to VESA mode\\r\\n\"));\n\t\tsc->gc_image->vgamode = 0;\n\t}\n}\n\nstatic uint64_t\npci_fbuf_read(UNUSED int vcpu, struct pci_devinst *pi,\n\t      int baridx, uint64_t offset, int size)\n{\n\tstruct pci_fbuf_softc *sc;\n\tuint8_t *p;\n\tuint64_t value;\n\n\tassert(baridx == 0);\n    assert(size >= 0);\n\n\tsc = pi->pi_arg;\n\n\n\tif (offset + (unsigned int)size > DMEMSZ) {\n\t\tprintf(\"fbuf: read too large, offset %lld size %d\\n\",\n\t\t       offset, size);\n\t\treturn (0);\n\t}\n\n\tp = (uint8_t *)&sc->memregs + offset;\n\tvalue = 0;\n\tswitch (size) {\n\tcase 1:\n\t\tvalue = *p;\n\t\tbreak;\n\tcase 2:\n        value = read_uint16_unaligned(p);\n\t\tbreak;\n\tcase 4:\n        value = read_uint32_unaligned(p);\n\t\tbreak;\n\tcase 8:\n        value = read_uint64_unaligned(p);\n\t\tbreak;\n\tdefault:\n\t\tprintf(\"fbuf: read unknown size %d\\n\", size);\n\t\tbreak;\n\t}\n\n\tDPRINTF(DEBUG_VERBOSE,\n\t    (\"fbuf rd: offset 0x%llx, size: %d, value: 0x%llx\\n\",\n\t     offset, size, value));\n\n\treturn (value);\n}\n\nstatic int\npci_fbuf_parse_opts(struct pci_fbuf_softc *sc, char *opts)\n{\n\tchar\t*uopts, *xopts, *config;\n\tchar\t*tmpstr;\n\tint\tret;\n\n\tret = 0;\n\tuopts = strdup(opts);\n\tfor (xopts = strtok(uopts, \",\");\n\t     xopts != NULL;\n\t     xopts = strtok(NULL, \",\")) {\n\t\tif (strcmp(xopts, \"wait\") == 0) {\n\t\t\tsc->rfb_wait = 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ((config = strchr(xopts, '=')) == NULL) {\n\t\t\tpci_fbuf_usage(xopts);\n\t\t\tret = -1;\n\t\t\tgoto done;\n\t\t}\n\n\t\t*config++ = '\\0';\n\n\t\tDPRINTF(DEBUG_VERBOSE, (\"pci_fbuf option %s = %s\\r\\n\",\n\t\t   xopts, config));\n\n\t\tif (!strcmp(xopts, \"tcp\") || !strcmp(xopts, \"rfb\")) {\n\t\t\t/* parse host-ip:port */\n\t\t        tmpstr = strsep(&config, \":\");\n\t\t\tif (!config)\n\t\t\t\tsc->rfb_port = atoi(tmpstr);\n\t\t\telse {\n\t\t\t\tsc->rfb_port = atoi(config);\n\t\t\t\tsc->rfb_host = tmpstr;\n\t\t\t}\n\t        } else if (!strcmp(xopts, \"vga\")) {\n\t\t\tif (!strcmp(config, \"off\")) {\n\t\t\t\tsc->vga_enabled = 0;\n\t\t\t} else if (!strcmp(config, \"io\")) {\n\t\t\t\tsc->vga_enabled = 1;\n\t\t\t\tsc->vga_full = 0;\n\t\t\t} else if (!strcmp(config, \"on\")) {\n\t\t\t\tsc->vga_enabled = 1;\n\t\t\t\tsc->vga_full = 1;\n\t\t\t} else {\n\t\t\t\tpci_fbuf_usage(opts);\n\t\t\t\tret = -1;\n\t\t\t\tgoto done;\n\t\t\t}\n\t        } else if (!strcmp(xopts, \"w\")) {\n\t\t        sc->memregs.width = (uint16_t)atoi(config);\n\t\t\tif (sc->memregs.width > COLS_MAX) {\n\t\t\t\tpci_fbuf_usage(xopts);\n\t\t\t\tret = -1;\n\t\t\t\tgoto done;\n\t\t\t} else if (sc->memregs.width == 0)\n\t\t\t\tsc->memregs.width = 1920;\n\t\t} else if (!strcmp(xopts, \"h\")) {\n\t\t\tsc->memregs.height = (uint16_t)atoi(config);\n\t\t\tif (sc->memregs.height > ROWS_MAX) {\n\t\t\t\tpci_fbuf_usage(xopts);\n\t\t\t\tret = -1;\n\t\t\t\tgoto done;\n\t\t\t} else if (sc->memregs.height == 0)\n\t\t\t\tsc->memregs.height = 1080;\n\t\t} else if (!strcmp(xopts, \"password\")) {\n\t\t\tsc->rfb_password = config;\n\t\t} else {\n\t\t\tpci_fbuf_usage(xopts);\n\t\t\tret = -1;\n\t\t\tgoto done;\n\t\t}\n\t}\n\ndone:\n\treturn (ret);\n}\n\nstatic void\npci_fbuf_render(struct bhyvegc *gc, void *arg)\n{\n\tstruct pci_fbuf_softc *sc;\n\n\tsc = arg;\n\n\tif (sc->vga_full && sc->gc_image->vgamode) {\n\t\t/* TODO: mode switching to vga and vesa should use the special\n\t\t *      EFI-bhyve protocol port.\n\t\t */\n\t\tvga_render(gc, sc->vgasc);\n\t\treturn;\n\t}\n\tif (sc->gc_width != sc->memregs.width ||\n\t    sc->gc_height != sc->memregs.height) {\n\t\tbhyvegc_resize(gc, sc->memregs.width, sc->memregs.height);\n\t\tsc->gc_width = sc->memregs.width;\n\t\tsc->gc_height = sc->memregs.height;\n\t}\n\n\treturn;\n}\n\nstatic int\npci_fbuf_init(struct pci_devinst *pi, char *opts)\n{\n\tint error;\n\tstruct pci_fbuf_softc *sc;\n\n\tif (fbuf_sc != NULL) {\n\t\tfprintf(stderr, \"Only one frame buffer device is allowed.\\n\");\n\t\treturn (-1);\n\t}\n\n\tsc = calloc(1, sizeof(struct pci_fbuf_softc));\n\n\tpi->pi_arg = sc;\n\n\t/* initialize config space */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, 0x40FB);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, 0xFB5D);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_DISPLAY);\n\tpci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_DISPLAY_VGA);\n\n\terror = pci_emul_alloc_bar(pi, 0, PCIBAR_MEM32, DMEMSZ);\n\tassert(error == 0);\n\n\terror = pci_emul_alloc_bar(pi, 1, PCIBAR_MEM32, FB_SIZE);\n\tassert(error == 0);\n\n\terror = pci_emul_add_msicap(pi, PCI_FBUF_MSI_MSGS);\n\tassert(error == 0);\n\n\tsc->fbaddr = pi->pi_bar[1].addr;\n\tsc->memregs.fbsize = FB_SIZE;\n\tsc->memregs.width  = COLS_DEFAULT;\n\tsc->memregs.height = ROWS_DEFAULT;\n\tsc->memregs.depth  = 32;\n\n\tsc->vga_enabled = 1;\n\tsc->vga_full = 0;\n\n\tsc->fsc_pi = pi;\n\n\terror = pci_fbuf_parse_opts(sc, opts);\n\tif (error != 0)\n\t\tgoto done;\n\n\t/* XXX until VGA rendering is enabled */\n\tif (sc->vga_full != 0) {\n\t\tfprintf(stderr, \"pci_fbuf: VGA rendering not enabled\");\n\t\tgoto done;\n\t}\n\n\tDPRINTF(DEBUG_INFO, (\"fbuf frame buffer base: %p [sz %lu]\\r\\n\",\n\t        (void *)sc->fb_base, FB_SIZE));\n\n\t/*\n\t * Map the framebuffer into the guest address space.\n\t * XXX This may fail if the BAR is different than a prior\n\t * run. In this case flag the error. This will be fixed\n\t * when a change_memseg api is available.\n\t */\n\tif (xh_setup_video_memory(sc->fbaddr, FB_SIZE, (void **)&sc->fb_base) != 0) {\n\t\tfprintf(stderr, \"pci_fbuf: mapseg failed - try deleting VM and restarting\\n\");\n\t\terror = -1;\n\t\tgoto done;\n\t}\n\n\tconsole_init(sc->memregs.width, sc->memregs.height, sc->fb_base);\n\tconsole_fb_register(pci_fbuf_render, sc);\n\n\tif (sc->vga_enabled)\n\t\tsc->vgasc = vga_init(!sc->vga_full);\n\tsc->gc_image = console_get_image();\n\n\tfbuf_sc = sc;\n\n\tmemset((void *)sc->fb_base, 0, FB_SIZE);\n\n\terror = rfb_init(sc->rfb_host, sc->rfb_port, sc->rfb_wait, sc->rfb_password);\ndone:\n\tif (error)\n\t\tfree(sc);\n\n\treturn (error);\n}\n\nstatic struct pci_devemu pci_fbuf = {\n\t.pe_emu =\t\"fbuf\",\n\t.pe_init =\tpci_fbuf_init,\n\t.pe_barwrite =\tpci_fbuf_write,\n\t.pe_barread =\tpci_fbuf_read\n};\nPCI_EMUL_SET(pci_fbuf);\n"
  },
  {
    "path": "src/pci_hostbridge.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <xhyve/support/misc.h>\n#include <xhyve/pci_emul.h>\n\nstatic int\npci_hostbridge_init(struct pci_devinst *pi, UNUSED char *opts)\n{\n\t/* config space */\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, 0x1275);\t/* NetApp */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, 0x1275);\t/* NetApp */\n\tpci_set_cfgdata8(pi, PCIR_HDRTYPE, PCIM_HDRTYPE_NORMAL);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE);\n\tpci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_HOST);\n\n\tpci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_PORT);\n\n\treturn (0);\n}\n\nstatic int\npci_amd_hostbridge_init(struct pci_devinst *pi, char *opts)\n{\n\t(void) pci_hostbridge_init(pi, opts);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, 0x1022);\t/* AMD */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, 0x7432);\t/* made up */\n\n\treturn (0);\n}\n\nstatic struct pci_devemu pci_de_amd_hostbridge = {\n\t.pe_emu = \"amd_hostbridge\",\n\t.pe_init = pci_amd_hostbridge_init,\n};\nPCI_EMUL_SET(pci_de_amd_hostbridge);\n\nstatic struct pci_devemu pci_de_hostbridge = {\n\t.pe_emu = \"hostbridge\",\n\t.pe_init = pci_hostbridge_init,\n};\nPCI_EMUL_SET(pci_de_hostbridge);\n"
  },
  {
    "path": "src/pci_irq.c",
    "content": "/*-\n * Copyright (c) 2014 Hudson River Trading LLC\n * Written by: John H. Baldwin <jhb@FreeBSD.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <pthread.h>\n#include <errno.h>\n#include <assert.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/acpi.h>\n#include <xhyve/inout.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/pci_irq.h>\n#include <xhyve/pci_lpc.h>\n\n/*\n * Implement an 8 pin PCI interrupt router compatible with the router\n * present on Intel's ICH10 chip.\n */\n\n/* Fields in each PIRQ register. */\n#define\tPIRQ_DIS\t0x80\n#define\tPIRQ_IRQ\t0x0f\n\n/* Only IRQs 3-7, 9-12, and 14-15 are permitted. */\n#define\tPERMITTED_IRQS\t0xdef8\n#define\tIRQ_PERMITTED(irq)\t(((1U << (irq)) & PERMITTED_IRQS) != 0)\n\n/* IRQ count to disable an IRQ. */\n#define\tIRQ_DISABLED\t0xff\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstatic struct pirq {\n\tuint8_t reg;\n\tint use_count;\n\tint active_count;\n\tpthread_mutex_t lock;\n} pirqs[8];\n#pragma clang diagnostic pop\n\nstatic u_char irq_counts[16];\nstatic int pirq_cold = 1;\n\n/*\n * Returns true if this pin is enabled with a valid IRQ.  Setting the\n * register to a reserved IRQ causes interrupts to not be asserted as\n * if the pin was disabled.\n */\nstatic bool\npirq_valid_irq(int reg)\n{\n\tif (reg & PIRQ_DIS)\n\t\treturn (false);\n\treturn (IRQ_PERMITTED(reg & PIRQ_IRQ));\n}\n\nuint8_t\npirq_read(int pin)\n{\n\tassert((pin > 0) && (((unsigned) pin) <= nitems(pirqs)));\n\treturn (pirqs[pin - 1].reg);\n}\n\nvoid\npirq_write(int pin, uint8_t val)\n{\n\tstruct pirq *pirq;\n\n\tassert((pin > 0) && (((unsigned) pin) <= nitems(pirqs)));\n\tpirq = &pirqs[pin - 1];\n\tpthread_mutex_lock(&pirq->lock);\n\tif (pirq->reg != (val & (PIRQ_DIS | PIRQ_IRQ))) {\n\t\tif (pirq->active_count != 0 && pirq_valid_irq(pirq->reg))\n\t\t\txh_vm_isa_deassert_irq(pirq->reg & PIRQ_IRQ, -1);\n\t\tpirq->reg = val & (PIRQ_DIS | PIRQ_IRQ);\n\t\tif (pirq->active_count != 0 && pirq_valid_irq(pirq->reg))\n\t\t\txh_vm_isa_assert_irq(pirq->reg & PIRQ_IRQ, -1);\n\t}\n\tpthread_mutex_unlock(&pirq->lock);\n}\n\nvoid\npci_irq_reserve(int irq)\n{\n\tassert((irq >= 0) && (((unsigned) irq) < nitems(irq_counts)));\n\tassert(pirq_cold);\n\tassert(irq_counts[irq] == 0 || irq_counts[irq] == IRQ_DISABLED);\n\tirq_counts[irq] = IRQ_DISABLED;\n}\n\nvoid\npci_irq_use(int irq)\n{\n\tassert((irq >= 0) && (((unsigned) irq) < nitems(irq_counts)));\n\tassert(pirq_cold);\n\tassert(irq_counts[irq] != IRQ_DISABLED);\n\tirq_counts[irq]++;\n}\n\nvoid\npci_irq_init(void)\n{\n\tunsigned i;\n\n\tfor (i = 0; i < nitems(pirqs); i++) {\n\t\tpirqs[i].reg = PIRQ_DIS;\n\t\tpirqs[i].use_count = 0;\n\t\tpirqs[i].active_count = 0;\n\t\tpthread_mutex_init(&pirqs[i].lock, NULL);\n\t}\n\tfor (i = 0; i < nitems(irq_counts); i++) {\n\t\tif (IRQ_PERMITTED(i))\n\t\t\tirq_counts[i] = 0;\n\t\telse\n\t\t\tirq_counts[i] = IRQ_DISABLED;\n\t}\n}\n\nvoid\npci_irq_assert(struct pci_devinst *pi)\n{\n\tstruct pirq *pirq;\n\n\tif (pi->pi_lintr.pirq_pin > 0) {\n\t\tassert(((unsigned) pi->pi_lintr.pirq_pin) <= nitems(pirqs));\n\t\tpirq = &pirqs[pi->pi_lintr.pirq_pin - 1];\n\t\tpthread_mutex_lock(&pirq->lock);\n\t\tpirq->active_count++;\n\t\tif (pirq->active_count == 1 && pirq_valid_irq(pirq->reg)) {\n\t\t\txh_vm_isa_assert_irq(pirq->reg & PIRQ_IRQ, pi->pi_lintr.ioapic_irq);\n\t\t\tpthread_mutex_unlock(&pirq->lock);\n\t\t\treturn;\n\t\t}\n\t\tpthread_mutex_unlock(&pirq->lock);\n\t}\n\txh_vm_ioapic_assert_irq(pi->pi_lintr.ioapic_irq);\n}\n\nvoid\npci_irq_deassert(struct pci_devinst *pi)\n{\n\tstruct pirq *pirq;\n\n\tif (pi->pi_lintr.pirq_pin > 0) {\n\t\tassert(((unsigned) pi->pi_lintr.pirq_pin) <= nitems(pirqs));\n\t\tpirq = &pirqs[pi->pi_lintr.pirq_pin - 1];\n\t\tpthread_mutex_lock(&pirq->lock);\n\t\tpirq->active_count--;\n\t\tif (pirq->active_count == 0 && pirq_valid_irq(pirq->reg)) {\n\t\t\txh_vm_isa_deassert_irq(pirq->reg & PIRQ_IRQ,\n\t\t\t\tpi->pi_lintr.ioapic_irq);\n\t\t\tpthread_mutex_unlock(&pirq->lock);\n\t\t\treturn;\n\t\t}\n\t\tpthread_mutex_unlock(&pirq->lock);\n\t}\n\txh_vm_ioapic_deassert_irq(pi->pi_lintr.ioapic_irq);\n}\n\nint\npirq_alloc_pin(struct pci_devinst *pi)\n{\n\tint best_count, best_irq, best_pin, irq, pin;\n\n\tpirq_cold = 0;\n\n\t/* First, find the least-used PIRQ pin. */\n    if (lpc_bootrom()) {\n        /* For external bootrom use fixed mapping. */\n        best_pin = (4 + pi->pi_slot + pi->pi_lintr.pin) % 8;\n    } else {\n        best_pin = 0;\n        best_count = pirqs[0].use_count;\n        for (pin = 1; ((unsigned) pin) < nitems(pirqs); pin++) {\n            if (pirqs[pin].use_count < best_count) {\n                best_pin = pin;\n                best_count = pirqs[pin].use_count;\n            }\n        }\n    }\n\tpirqs[best_pin].use_count++;\n\n\t/* Second, route this pin to an IRQ. */\n\tif (pirqs[best_pin].reg == PIRQ_DIS) {\n\t\tbest_irq = -1;\n\t\tbest_count = 0;\n\t\tfor (irq = 0; ((unsigned) irq) < nitems(irq_counts); irq++) {\n\t\t\tif (irq_counts[irq] == IRQ_DISABLED)\n\t\t\t\tcontinue;\n\t\t\tif (best_irq == -1 || irq_counts[irq] < best_count) {\n\t\t\t\tbest_irq = irq;\n\t\t\t\tbest_count = irq_counts[irq];\n\t\t\t}\n\t\t}\n\t\tassert(best_irq >= 0);\n\t\tirq_counts[best_irq]++;\n\t\tpirqs[best_pin].reg = (uint8_t) best_irq;\n\t\txh_vm_isa_set_irq_trigger(best_irq, LEVEL_TRIGGER);\n\t}\n\n\treturn (best_pin + 1);\n}\n\nint\npirq_irq(int pin)\n{\n\tassert((pin > 0) && (((unsigned) pin) <= nitems(pirqs)));\n\treturn (pirqs[pin - 1].reg & PIRQ_IRQ);\n}\n\n/* XXX: Generate $PIR table. */\n\nstatic void\npirq_dsdt(void)\n{\n\tchar *irq_prs, *old;\n\tint irq, pin;\n\n\tirq_prs = NULL;\n\tfor (irq = 0; ((unsigned) irq) < nitems(irq_counts); irq++) {\n\t\tif (!IRQ_PERMITTED(irq))\n\t\t\tcontinue;\n\t\tif (irq_prs == NULL)\n\t\t\tasprintf(&irq_prs, \"%d\", irq);\n\t\telse {\n\t\t\told = irq_prs;\n\t\t\tasprintf(&irq_prs, \"%s,%d\", old, irq);\n\t\t\tfree(old);\n\t\t}\n\t}\n\n\t/*\n\t * A helper method to validate a link register's value.  This\n\t * duplicates pirq_valid_irq().\n\t */\n\tdsdt_line(\"\");\n\tdsdt_line(\"Method (PIRV, 1, NotSerialized)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  If (And (Arg0, 0x%02X))\", PIRQ_DIS);\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Return (0x00)\");\n\tdsdt_line(\"  }\");\n\tdsdt_line(\"  And (Arg0, 0x%02X, Local0)\", PIRQ_IRQ);\n\tdsdt_line(\"  If (LLess (Local0, 0x03))\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Return (0x00)\");\n\tdsdt_line(\"  }\");\n\tdsdt_line(\"  If (LEqual (Local0, 0x08))\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Return (0x00)\");\n\tdsdt_line(\"  }\");\n\tdsdt_line(\"  If (LEqual (Local0, 0x0D))\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Return (0x00)\");\n\tdsdt_line(\"  }\");\n\tdsdt_line(\"  Return (0x01)\");\n\tdsdt_line(\"}\");\n\n\tfor (pin = 0; ((unsigned) pin) < nitems(pirqs); pin++) {\n\t\tdsdt_line(\"\");\n\t\tdsdt_line(\"Device (LNK%c)\", 'A' + pin);\n\t\tdsdt_line(\"{\");\n\t\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0C0F\\\"))\");\n\t\tdsdt_line(\"  Name (_UID, 0x%02X)\", pin + 1);\n\t\tdsdt_line(\"  Method (_STA, 0, NotSerialized)\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    If (PIRV (PIR%c))\", 'A' + pin);\n\t\tdsdt_line(\"    {\");\n\t\tdsdt_line(\"       Return (0x0B)\");\n\t\tdsdt_line(\"    }\");\n\t\tdsdt_line(\"    Else\");\n\t\tdsdt_line(\"    {\");\n\t\tdsdt_line(\"       Return (0x09)\");\n\t\tdsdt_line(\"    }\");\n\t\tdsdt_line(\"  }\");\n\t\tdsdt_line(\"  Name (_PRS, ResourceTemplate ()\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    IRQ (Level, ActiveLow, Shared, )\");\n\t\tdsdt_line(\"      {%s}\", irq_prs);\n\t\tdsdt_line(\"  })\");\n\t\tdsdt_line(\"  Name (CB%02X, ResourceTemplate ()\", pin + 1);\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    IRQ (Level, ActiveLow, Shared, )\");\n\t\tdsdt_line(\"      {}\");\n\t\tdsdt_line(\"  })\");\n\t\tdsdt_line(\"  CreateWordField (CB%02X, 0x01, CIR%c)\",\n\t\t    pin + 1, 'A' + pin);\n\t\tdsdt_line(\"  Method (_CRS, 0, NotSerialized)\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    And (PIR%c, 0x%02X, Local0)\", 'A' + pin,\n\t\t    PIRQ_DIS | PIRQ_IRQ);\n\t\tdsdt_line(\"    If (PIRV (Local0))\");\n\t\tdsdt_line(\"    {\");\n\t\tdsdt_line(\"      ShiftLeft (0x01, Local0, CIR%c)\", 'A' + pin);\n\t\tdsdt_line(\"    }\");\n\t\tdsdt_line(\"    Else\");\n\t\tdsdt_line(\"    {\");\n\t\tdsdt_line(\"      Store (0x00, CIR%c)\", 'A' + pin);\n\t\tdsdt_line(\"    }\");\n\t\tdsdt_line(\"    Return (CB%02X)\", pin + 1);\n\t\tdsdt_line(\"  }\");\n\t\tdsdt_line(\"  Method (_DIS, 0, NotSerialized)\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    Store (0x80, PIR%c)\", 'A' + pin);\n\t\tdsdt_line(\"  }\");\n\t\tdsdt_line(\"  Method (_SRS, 1, NotSerialized)\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_line(\"    CreateWordField (Arg0, 0x01, SIR%c)\", 'A' + pin);\n\t\tdsdt_line(\"    FindSetRightBit (SIR%c, Local0)\", 'A' + pin);\n\t\tdsdt_line(\"    Store (Decrement (Local0), PIR%c)\", 'A' + pin);\n\t\tdsdt_line(\"  }\");\n\t\tdsdt_line(\"}\");\n\t}\n\tfree(irq_prs);\n}\nLPC_DSDT(pirq_dsdt);\n"
  },
  {
    "path": "src/pci_lpc.c",
    "content": "/*-\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/acpi.h>\n#include <xhyve/bootrom.h>\n#include <xhyve/inout.h>\n#include <xhyve/dbgport.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/pci_irq.h>\n#include <xhyve/pci_lpc.h>\n#include <xhyve/uart_emul.h>\n\n#define\tIO_ICU1\t\t0x20\n#define\tIO_ICU2\t\t0xA0\n\nSET_DECLARE(lpc_dsdt_set, struct lpc_dsdt);\nSET_DECLARE(lpc_sysres_set, struct lpc_sysres);\n\n#define\tELCR_PORT\t0x4d0\nSYSRES_IO(ELCR_PORT, 2);\n\n#define\tIO_TIMER1_PORT\t0x40\n\n#define\tNMISC_PORT\t0x61\nSYSRES_IO(NMISC_PORT, 1);\n\nstatic struct pci_devinst *lpc_bridge;\n\nstatic const char *romfile;\n\n#define\tLPC_UART_NUM\t2\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstatic struct lpc_uart_softc {\n\tstruct uart_softc *uart_softc;\n\tconst char *opts;\n\tconst char *name;\n\tint\tiobase;\n\tint\tirq;\n\tint\tenabled;\n} lpc_uart_softc[LPC_UART_NUM];\n#pragma clang diagnostic pop\n\nstatic const char *lpc_uart_names[LPC_UART_NUM] = { \"COM1\", \"COM2\" };\n\n/*\n * LPC device configuration is in the following form:\n * <lpc_device_name>[,<options>]\n * For e.g. \"com1,stdio\" or \"bootrom,/var/romfile\"\n */\nint\nlpc_device_parse(const char *opts)\n{\n\tint unit, error;\n\tchar *str, *cpy, *lpcdev;\n\n\terror = -1;\n\tstr = cpy = strdup(opts);\n\tlpcdev = strsep(&str, \",\");\n\tif (lpcdev != NULL) {\n        if (strcasecmp(lpcdev, \"bootrom\") == 0) {\n            romfile = str;\n            error = 0;\n            goto done;\n        }\n\t\tfor (unit = 0; unit < LPC_UART_NUM; unit++) {\n\t\t\tif (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) {\n\t\t\t\tlpc_uart_softc[unit].opts = str;\n\t\t\t\tlpc_uart_softc[unit].name = lpc_uart_names[unit];\n\t\t\t\terror = 0;\n\t\t\t\tgoto done;\n\t\t\t}\n\t\t}\n\t}\n\ndone:\n\tif (error)\n\t\tfree(cpy);\n\n\treturn (error);\n}\n\nconst char *\nlpc_bootrom(void)\n{\n    return romfile;\n}\n\n\nstatic void\nlpc_uart_intr_assert(void *arg)\n{\n\tstruct lpc_uart_softc *sc = arg;\n\n\tassert(sc->irq >= 0);\n\n\txh_vm_isa_pulse_irq(sc->irq, sc->irq);\n}\n\nstatic void\nlpc_uart_intr_deassert(UNUSED void *arg)\n{\n\t/*\n\t * The COM devices on the LPC bus generate edge triggered interrupts,\n\t * so nothing more to do here.\n\t */\n}\n\nstatic int\nlpc_uart_io_handler(UNUSED int vcpu, int in, int port, int bytes, uint32_t *eax,\n\tvoid *arg)\n{\n\tint offset;\n\tstruct lpc_uart_softc *sc = arg;\n\n\toffset = port - sc->iobase;\n\n\tswitch (bytes) {\n\tcase 1:\n\t\tif (in)\n\t\t\t*eax = uart_read(sc->uart_softc, offset);\n\t\telse\n\t\t\tuart_write(sc->uart_softc, offset, ((uint8_t) *eax));\n\t\tbreak;\n\tcase 2:\n\t\tif (in) {\n\t\t\t*eax = (uint32_t) uart_read(sc->uart_softc, offset);\n\t\t\t*eax |= (uint32_t) (uart_read(sc->uart_softc, offset + 1) << 8);\n\t\t} else {\n\t\t\tuart_write(sc->uart_softc, offset, ((uint8_t) *eax));\n\t\t\tuart_write(sc->uart_softc, offset + 1, ((uint8_t) (*eax >> 8)));\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\treturn (-1);\n\t}\n\n\treturn (0);\n}\n\nstatic int\nlpc_init(void)\n{\n\tstruct lpc_uart_softc *sc;\n\tstruct inout_port iop;\n\tint unit, error;\n\n    if (romfile != NULL) {\n        error = bootrom_init(romfile);\n        if (error)\n            return error;\n    }\n\n\t/* COM1 and COM2 */\n\tfor (unit = 0; unit < LPC_UART_NUM; unit++) {\n\t\tsc = &lpc_uart_softc[unit];\n\n\t\tif (uart_legacy_alloc(unit, &sc->iobase, &sc->irq) != 0) {\n\t\t\tfprintf(stderr, \"Unable to allocate resources for \"\n\t\t\t    \"LPC device %s\\n\", sc->name);\n\t\t\treturn (-1);\n\t\t}\n\t\tpci_irq_reserve(sc->irq);\n\n\t\tsc->uart_softc = uart_init(lpc_uart_intr_assert,\n\t\t\t\t    lpc_uart_intr_deassert, sc);\n\n\t\tif (uart_set_backend(sc->uart_softc, sc->opts, sc->name) != 0) {\n\t\t\tfprintf(stderr, \"Unable to initialize backend '%s' \"\n\t\t\t    \"for LPC device %s\\n\", sc->opts, sc->name);\n\t\t\treturn (-1);\n\t\t}\n\n\t\tbzero(&iop, sizeof(struct inout_port));\n\t\tiop.name = sc->name;\n\t\tiop.port = sc->iobase;\n\t\tiop.size = UART_IO_BAR_SIZE;\n\t\tiop.flags = IOPORT_F_INOUT;\n\t\tiop.handler = lpc_uart_io_handler;\n\t\tiop.arg = sc;\n\n\t\terror = register_inout(&iop);\n\t\tassert(error == 0);\n\t\tsc->enabled = 1;\n\t}\n\n\treturn (0);\n}\n\nstatic void\npci_lpc_write_dsdt(struct pci_devinst *pi)\n{\n\tstruct lpc_dsdt **ldpp, *ldp;\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (ISA)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_ADR, 0x%04X%04X)\", pi->pi_slot, pi->pi_func);\n\tdsdt_line(\"  OperationRegion (LPCR, PCI_Config, 0x00, 0x100)\");\n\tdsdt_line(\"  Field (LPCR, AnyAcc, NoLock, Preserve)\");\n\tdsdt_line(\"  {\");\n\tdsdt_line(\"    Offset (0x60),\");\n\tdsdt_line(\"    PIRA,   8,\");\n\tdsdt_line(\"    PIRB,   8,\");\n\tdsdt_line(\"    PIRC,   8,\");\n\tdsdt_line(\"    PIRD,   8,\");\n\tdsdt_line(\"    Offset (0x68),\");\n\tdsdt_line(\"    PIRE,   8,\");\n\tdsdt_line(\"    PIRF,   8,\");\n\tdsdt_line(\"    PIRG,   8,\");\n\tdsdt_line(\"    PIRH,   8\");\n\tdsdt_line(\"  }\");\n\tdsdt_line(\"\");\n\n\tdsdt_indent(1);\n\tSET_FOREACH(ldpp, lpc_dsdt_set) {\n\t\tldp = *ldpp;\n\t\tldp->handler();\n\t}\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (PIC)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0000\\\"))\");\n\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_indent(2);\n\tdsdt_fixed_ioport(IO_ICU1, 2);\n\tdsdt_fixed_ioport(IO_ICU2, 2);\n\tdsdt_fixed_irq(2);\n\tdsdt_unindent(2);\n\tdsdt_line(\"  })\");\n\tdsdt_line(\"}\");\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (TIMR)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0100\\\"))\");\n\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_indent(2);\n\tdsdt_fixed_ioport(IO_TIMER1_PORT, 4);\n\tdsdt_fixed_irq(0);\n\tdsdt_unindent(2);\n\tdsdt_line(\"  })\");\n\tdsdt_line(\"}\");\n\tdsdt_unindent(1);\n\n\tdsdt_line(\"}\");\n}\n\nstatic void\npci_lpc_sysres_dsdt(void)\n{\n\tstruct lpc_sysres **lspp, *lsp;\n\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (SIO)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0C02\\\"))\");\n\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"  {\");\n\n\tdsdt_indent(2);\n\tSET_FOREACH(lspp, lpc_sysres_set) {\n\t\tlsp = *lspp;\n\t\tswitch (lsp->type) {\n\t\tcase LPC_SYSRES_IO:\n\t\t\tdsdt_fixed_ioport(((uint16_t) lsp->base), ((uint16_t) lsp->length));\n\t\t\tbreak;\n\t\tcase LPC_SYSRES_MEM:\n\t\t\tdsdt_fixed_mem32(lsp->base, lsp->length);\n\t\t\tbreak;\n\t\t}\n\t}\n\tdsdt_unindent(2);\n\n\tdsdt_line(\"  })\");\n\tdsdt_line(\"}\");\n}\nLPC_DSDT(pci_lpc_sysres_dsdt);\n\nstatic void\npci_lpc_uart_dsdt(void)\n{\n\tstruct lpc_uart_softc *sc;\n\tint unit;\n\n\tfor (unit = 0; unit < LPC_UART_NUM; unit++) {\n\t\tsc = &lpc_uart_softc[unit];\n\t\tif (!sc->enabled)\n\t\t\tcontinue;\n\t\tdsdt_line(\"\");\n\t\tdsdt_line(\"Device (%s)\", lpc_uart_names[unit]);\n\t\tdsdt_line(\"{\");\n\t\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0501\\\"))\");\n\t\tdsdt_line(\"  Name (_UID, %d)\", unit + 1);\n\t\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\t\tdsdt_line(\"  {\");\n\t\tdsdt_indent(2);\n\t\tdsdt_fixed_ioport(((uint16_t) sc->iobase), UART_IO_BAR_SIZE);\n\t\tdsdt_fixed_irq(((uint8_t) sc->irq));\n\t\tdsdt_unindent(2);\n\t\tdsdt_line(\"  })\");\n\t\tdsdt_line(\"}\");\n\t}\n}\nLPC_DSDT(pci_lpc_uart_dsdt);\n\nstatic int\npci_lpc_cfgwrite(UNUSED int vcpu, struct pci_devinst *pi, int coff, int bytes,\n\tuint32_t val)\n{\n\tint pirq_pin;\n\n\tif (bytes == 1) {\n\t\tpirq_pin = 0;\n\t\tif (coff >= 0x60 && coff <= 0x63)\n\t\t\tpirq_pin = coff - 0x60 + 1;\n\t\tif (coff >= 0x68 && coff <= 0x6b)\n\t\t\tpirq_pin = coff - 0x68 + 5;\n\t\tif (pirq_pin != 0) {\n\t\t\tpirq_write(pirq_pin, ((uint8_t) val));\n\t\t\tpci_set_cfgdata8(pi, coff, pirq_read(pirq_pin));\n\t\t\treturn (0);\n\t\t}\n\t}\n\treturn (-1);\n}\n\nstatic void\npci_lpc_write(UNUSED int vcpu, UNUSED struct pci_devinst *pi, UNUSED int baridx,\n\tUNUSED uint64_t offset, UNUSED int size, UNUSED uint64_t value)\n{\n}\n\nstatic uint64_t\npci_lpc_read(UNUSED int vcpu, UNUSED struct pci_devinst *pi, UNUSED int baridx,\n\tUNUSED uint64_t offset, UNUSED int size)\n{\n\treturn (0);\n}\n\n#define\tLPC_DEV\t\t0x7000\n#define\tLPC_VENDOR\t0x8086\n\nstatic int\npci_lpc_init(struct pci_devinst *pi, UNUSED char *opts)\n{\n\n\t/*\n\t * Do not allow more than one LPC bridge to be configured.\n\t */\n\tif (lpc_bridge != NULL) {\n\t\tfprintf(stderr, \"Only one LPC bridge is allowed.\\n\");\n\t\treturn (-1);\n\t}\n\n\t/*\n\t * Enforce that the LPC can only be configured on bus 0. This\n\t * simplifies the ACPI DSDT because it can provide a decode for\n\t * all legacy i/o ports behind bus 0.\n\t */\n\tif (pi->pi_bus != 0) {\n\t\tfprintf(stderr, \"LPC bridge can be present only on bus 0.\\n\");\n\t\treturn (-1);\n\t}\n\n\tif (lpc_init() != 0)\n\t\treturn (-1);\n\n\t/* initialize config space */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, LPC_DEV);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, LPC_VENDOR);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE);\n\tpci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA);\n\n\tlpc_bridge = pi;\n\n\treturn (0);\n}\n\nchar *\nlpc_pirq_name(int pin)\n{\n\tchar *name;\n\n\tif (lpc_bridge == NULL)\n\t\treturn (NULL);\n\tasprintf(&name, \"\\\\_SB.PC00.ISA.LNK%c,\", 'A' + pin - 1);\n\treturn (name);\n}\n\nvoid\nlpc_pirq_routed(void)\n{\n\tint pin;\n\n\tif (lpc_bridge == NULL)\n\t\treturn;\n\n \tfor (pin = 0; pin < 4; pin++)\n\t\tpci_set_cfgdata8(lpc_bridge, 0x60 + pin, pirq_read(pin + 1));\n\tfor (pin = 0; pin < 4; pin++)\n\t\tpci_set_cfgdata8(lpc_bridge, 0x68 + pin, pirq_read(pin + 5));\n}\n\nstatic struct pci_devemu pci_de_lpc = {\n\t.pe_emu =\t\"lpc\",\n\t.pe_init =\tpci_lpc_init,\n\t.pe_write_dsdt = pci_lpc_write_dsdt,\n\t.pe_cfgwrite =\tpci_lpc_cfgwrite,\n\t.pe_barwrite =\tpci_lpc_write,\n\t.pe_barread =\tpci_lpc_read\n};\nPCI_EMUL_SET(pci_de_lpc);\n"
  },
  {
    "path": "src/pci_uart.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/uart_emul.h>\n\n/*\n * Pick a PCI vid/did of a chip with a single uart at\n * BAR0, that most versions of FreeBSD can understand:\n * Siig CyberSerial 1-port.\n */\n#define COM_VENDOR\t0x131f\n#define COM_DEV\t\t0x2000\n\nstatic void\npci_uart_intr_assert(void *arg)\n{\n\tstruct pci_devinst *pi = arg;\n\n\tpci_lintr_assert(pi);\n}\n\nstatic void\npci_uart_intr_deassert(void *arg)\n{\n\tstruct pci_devinst *pi = arg;\n\n\tpci_lintr_deassert(pi);\n}\n\nstatic void\npci_uart_write(UNUSED int vcpu, struct pci_devinst *pi, int baridx, uint64_t offset,\n\tint size, uint64_t value)\n{\n\n\tassert(baridx == 0);\n\tassert(size == 1);\n\n\tuart_write(pi->pi_arg, ((int) offset), ((uint8_t) value));\n}\n\nstatic uint64_t\npci_uart_read(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size)\n{\n\tuint8_t val;\n\n\tassert(baridx == 0);\n\tassert(size == 1);\n\n\tval = uart_read(pi->pi_arg, ((int) offset));\n\treturn (val);\n}\n\nstatic int\npci_uart_init(struct pci_devinst *pi, char *opts)\n{\n\tstruct uart_softc *sc;\n\tchar *name;\n\n\tpci_emul_alloc_bar(pi, 0, PCIBAR_IO, UART_IO_BAR_SIZE);\n\tpci_lintr_request(pi);\n\n\t/* initialize config space */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, COM_DEV);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, COM_VENDOR);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_SIMPLECOMM);\n\n\tsc = uart_init(pci_uart_intr_assert, pci_uart_intr_deassert, pi);\n\tpi->pi_arg = sc;\n\n\tasprintf(&name, \"pci uart at %d:%d\", pi->pi_slot, pi->pi_func);\n\tif (uart_set_backend(sc, opts, name) != 0) {\n\t\tfprintf(stderr, \"Unable to initialize backend '%s' for %s\\n\", opts, name);\n\t\tfree(name);\n\t\treturn (-1);\n\t}\n\n\tfree(name);\n\treturn (0);\n}\n\nstatic struct pci_devemu pci_de_com = {\n\t.pe_emu =\t\"uart\",\n\t.pe_init =\tpci_uart_init,\n\t.pe_barwrite =\tpci_uart_write,\n\t.pe_barread =\tpci_uart_read\n};\nPCI_EMUL_SET(pci_de_com);\n"
  },
  {
    "path": "src/pci_virtio_block.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <strings.h>\n#include <pthread.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <assert.h>\n#include <sys/param.h>\n#include <sys/stat.h>\n#include <sys/uio.h>\n#include <sys/ioctl.h>\n#include <sys/disk.h>\n\n#include <CommonCrypto/CommonDigest.h>\n\n#include <xhyve/support/misc.h>\n#include <xhyve/support/linker_set.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/virtio.h>\n#include <xhyve/block_if.h>\n\n#define VTBLK_RINGSZ 64\n\n#define VTBLK_S_OK 0\n#define VTBLK_S_IOERR 1\n#define\tVTBLK_S_UNSUPP 2\n\n#define\tVTBLK_BLK_ID_BYTES 20 + 1\n\n/* Capability bits */\n#define\tVTBLK_F_SEG_MAX (1 << 2) /* Maximum request segments */\n#define\tVTBLK_F_BLK_SIZE (1 << 6) /* cfg block size valid */\n#define\tVTBLK_F_FLUSH (1 << 9) /* Cache flush support */\n#define\tVTBLK_F_TOPOLOGY (1 << 10) /* Optimal I/O alignment */\n\n/*\n * Host capabilities\n */\n#define VTBLK_S_HOSTCAPS \\\n\t(VTBLK_F_SEG_MAX  | \\\n\t VTBLK_F_BLK_SIZE | \\\n\t VTBLK_F_FLUSH    | \\\n\t VTBLK_F_TOPOLOGY | \\\n\t VIRTIO_RING_F_INDIRECT_DESC) /* indirect descriptors */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\n/*\n * Config space \"registers\"\n */\nstruct vtblk_config {\n\tuint64_t vbc_capacity;\n\tuint32_t vbc_size_max;\n\tuint32_t vbc_seg_max;\n\tstruct {\n\t\tuint16_t cylinders;\n\t\tuint8_t heads;\n\t\tuint8_t sectors;\n\t} vbc_geometry;\n\tuint32_t vbc_blk_size;\n\tstruct {\n\t\tuint8_t physical_block_exp;\n\t\tuint8_t alignment_offset;\n\t\tuint16_t min_io_size;\n\t\tuint32_t opt_io_size;\n\t} vbc_topology;\n\tuint8_t vbc_writeback;\n} __packed;\n\n/*\n * Fixed-size block header\n */\nstruct virtio_blk_hdr {\n#define\tVBH_OP_READ\t\t0\n#define\tVBH_OP_WRITE\t\t1\n#define\tVBH_OP_FLUSH\t\t4\n#define\tVBH_OP_FLUSH_OUT\t5\n#define\tVBH_OP_IDENT\t\t8\t\t\n#define\tVBH_FLAG_BARRIER\t0x80000000\t/* OR'ed into vbh_type */\n\tuint32_t vbh_type;\n\tuint32_t vbh_ioprio;\n\tuint64_t vbh_sector;\n} __packed;\n\n#pragma clang diagnostic pop\n\n/*\n * Debug printf\n */\nstatic int pci_vtblk_debug;\n#define DPRINTF(params) if (pci_vtblk_debug) printf params\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct pci_vtblk_ioreq {\n\tstruct blockif_req io_req;\n\tstruct pci_vtblk_softc *io_sc;\n\tuint8_t *io_status;\n\tuint16_t io_idx;\n};\n\n/*\n * Per-device softc\n */\nstruct pci_vtblk_softc {\n\tstruct virtio_softc vbsc_vs;\n\tpthread_mutex_t vsc_mtx;\n\tstruct vqueue_info vbsc_vq;\n\tstruct vtblk_config vbsc_cfg;\n\tstruct blockif_ctxt *bc;\n\tchar vbsc_ident[VTBLK_BLK_ID_BYTES];\n\tstruct pci_vtblk_ioreq vbsc_ios[VTBLK_RINGSZ];\n};\n\n#pragma clang diagnostic pop\n\nstatic void pci_vtblk_reset(void *);\nstatic void pci_vtblk_notify(void *, struct vqueue_info *);\nstatic int pci_vtblk_cfgread(void *, int, int, uint32_t *);\nstatic int pci_vtblk_cfgwrite(void *, int, int, uint32_t);\n\nstatic struct virtio_consts vtblk_vi_consts = {\n\t\"vtblk\", /* our name */\n\t1, /* we support 1 virtqueue */\n\tsizeof(struct vtblk_config), /* config reg size */\n\tpci_vtblk_reset, /* reset */\n\tpci_vtblk_notify, /* device-wide qnotify */\n\tpci_vtblk_cfgread, /* read PCI config */\n\tpci_vtblk_cfgwrite, /* write PCI config */\n\tNULL, /* apply negotiated features */\n\tVTBLK_S_HOSTCAPS, /* our capabilities */\n};\n\nstatic void\npci_vtblk_reset(void *vsc)\n{\n\tstruct pci_vtblk_softc *sc = vsc;\n\n\tDPRINTF((\"vtblk: device reset requested !\\n\"));\n\tvi_reset_dev(&sc->vbsc_vs);\n}\n\n/* xhyve: FIXME\n *\n * pci_vtblk_done seems to deadlock when called from pci_vtblk_proc?\n */\nstatic void\npci_vtblk_done_locked(struct blockif_req *br, int err)\n{\n\tstruct pci_vtblk_ioreq *io = br->br_param;\n\tstruct pci_vtblk_softc *sc = io->io_sc;\n\n\t/* convert errno into a virtio block error return */\n\tif (err == EOPNOTSUPP || err == ENOSYS)\n\t\t*io->io_status = VTBLK_S_UNSUPP;\n\telse if (err != 0)\n\t\t*io->io_status = VTBLK_S_IOERR;\n\telse\n\t\t*io->io_status = VTBLK_S_OK;\n\n\t/*\n\t * Return the descriptor back to the host.\n\t * We wrote 1 byte (our status) to host.\n\t */\n\t//pthread_mutex_lock(&sc->vsc_mtx);\n\tvq_relchain(&sc->vbsc_vq, io->io_idx, 1);\n\tvq_endchains(&sc->vbsc_vq, 0);\n\t//pthread_mutex_unlock(&sc->vsc_mtx);\n}\n\nstatic void\npci_vtblk_done(struct blockif_req *br, int err) {\n\tstruct pci_vtblk_ioreq *io = br->br_param;\n\tstruct pci_vtblk_softc *sc = io->io_sc;\n\n\tpthread_mutex_lock(&sc->vsc_mtx);\n\tpci_vtblk_done_locked(br, err);\n\tpthread_mutex_unlock(&sc->vsc_mtx);\n}\n\nstatic void\npci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)\n{\n\tstruct virtio_blk_hdr *vbh;\n\tstruct pci_vtblk_ioreq *io;\n\tint i, n;\n\tint err;\n\tssize_t iolen;\n\tint writeop, type;\n\tstruct iovec iov[BLOCKIF_IOV_MAX + 2];\n\tuint16_t idx, flags[BLOCKIF_IOV_MAX + 2];\n\n\tn = vq_getchain(vq, &idx, iov, BLOCKIF_IOV_MAX + 2, flags);\n\n\t/*\n\t * The first descriptor will be the read-only fixed header,\n\t * and the last is for status (hence +2 above and below).\n\t * The remaining iov's are the actual data I/O vectors.\n\t *\n\t * XXX - note - this fails on crash dump, which does a\n\t * VIRTIO_BLK_T_FLUSH with a zero transfer length\n\t */\n\tassert(n >= 2 && n <= BLOCKIF_IOV_MAX + 2);\n\n\tio = &sc->vbsc_ios[idx];\n\tassert((flags[0] & VRING_DESC_F_WRITE) == 0);\n\tassert(iov[0].iov_len == sizeof(struct virtio_blk_hdr));\n\tvbh = iov[0].iov_base;\n\tmemcpy(&io->io_req.br_iov, &iov[1],\n\t\tsizeof(struct iovec) * (((size_t) n) - 2));\n\tio->io_req.br_iovcnt = n - 2;\n\tio->io_req.br_offset = (off_t) (vbh->vbh_sector * DEV_BSIZE);\n\tio->io_status = iov[--n].iov_base;\n\tassert(iov[n].iov_len == 1);\n\tassert(flags[n] & VRING_DESC_F_WRITE);\n\n\t/*\n\t * XXX\n\t * The guest should not be setting the BARRIER flag because\n\t * we don't advertise the capability.\n\t */\n\ttype = vbh->vbh_type & ~VBH_FLAG_BARRIER;\n\twriteop = (type == VBH_OP_WRITE);\n\n\tiolen = 0;\n\tfor (i = 1; i < n; i++) {\n\t\t/*\n\t\t * - write op implies read-only descriptor,\n\t\t * - read/ident op implies write-only descriptor,\n\t\t * therefore test the inverse of the descriptor bit\n\t\t * to the op.\n\t\t */\n\t\tassert(((flags[i] & VRING_DESC_F_WRITE) == 0) == writeop);\n\t\tiolen += iov[i].iov_len;\n\t}\n\tio->io_req.br_resid = iolen;\n\n\tDPRINTF((\"virtio-block: %s op, %zd bytes, %d segs\\n\\r\", \n\t\t writeop ? \"write\" : \"read/ident\", iolen, i - 1));\n\n\tswitch (type) {\n\tcase VBH_OP_READ:\n\t\terr = blockif_read(sc->bc, &io->io_req);\n\t\tbreak;\n\tcase VBH_OP_WRITE:\n\t\terr = blockif_write(sc->bc, &io->io_req);\n\t\tbreak;\n\tcase VBH_OP_FLUSH:\n\tcase VBH_OP_FLUSH_OUT:\n\t\terr = blockif_flush(sc->bc, &io->io_req);\n\t\tbreak;\n\tcase VBH_OP_IDENT:\n\t\t/* Assume a single buffer */\n\t\t/* S/n equal to buffer is not zero-terminated. */\n\t\tmemset(iov[1].iov_base, 0, iov[1].iov_len);\n\t\tstrncpy(iov[1].iov_base, sc->vbsc_ident,\n\t\t    MIN(iov[1].iov_len, sizeof(sc->vbsc_ident)));\n\t\t/* xhyve: FIXME */\n\t\tpci_vtblk_done_locked(&io->io_req, 0);\n\t\treturn;\n\tdefault:\n\t\t/* xhyve: FIXME */\n\t\tpci_vtblk_done_locked(&io->io_req, EOPNOTSUPP);\n\t\treturn;\n\t}\n\tassert(err == 0);\n}\n\nstatic void\npci_vtblk_notify(void *vsc, struct vqueue_info *vq)\n{\n\tstruct pci_vtblk_softc *sc = vsc;\n\n\twhile (vq_has_descs(vq))\n\t\tpci_vtblk_proc(sc, vq);\n}\n\nstatic int\npci_vtblk_init(struct pci_devinst *pi, char *opts)\n{\n\tchar bident[sizeof(\"XX:X:X\")];\n\tstruct blockif_ctxt *bctxt;\n\tu_char digest[CC_SHA256_DIGEST_LENGTH];\n\tstruct pci_vtblk_softc *sc;\n\toff_t size;\n\tint i, sectsz, sts, sto;\n\n\tif (opts == NULL) {\n\t\tprintf(\"virtio-block: backing device required\\n\");\n\t\treturn (1);\n\t}\n\n\t/*\n\t * The supplied backing file has to exist\n\t */\n\tsnprintf(bident, sizeof(bident), \"%d:%d\", pi->pi_slot, pi->pi_func);\n\tbctxt = blockif_open(opts, bident);\n\tif (bctxt == NULL) {       \t\n\t\tperror(\"Could not open backing file\");\n\t\treturn (1);\n\t}\n\n\tsize = blockif_size(bctxt);\n\tsectsz = blockif_sectsz(bctxt);\n\tblockif_psectsz(bctxt, &sts, &sto);\n\n\tsc = calloc(1, sizeof(struct pci_vtblk_softc));\n\tsc->bc = bctxt;\n\tfor (i = 0; i < VTBLK_RINGSZ; i++) {\n\t\tstruct pci_vtblk_ioreq *io = &sc->vbsc_ios[i];\n\t\tio->io_req.br_callback = pci_vtblk_done;\n\t\tio->io_req.br_param = io;\n\t\tio->io_sc = sc;\n\t\tio->io_idx = (uint16_t) i;\n\t}\n\n\tpthread_mutex_init(&sc->vsc_mtx, NULL);\n\n\t/* init virtio softc and virtqueues */\n\tvi_softc_linkup(&sc->vbsc_vs, &vtblk_vi_consts, sc, pi, &sc->vbsc_vq);\n\tsc->vbsc_vs.vs_mtx = &sc->vsc_mtx;\n\n\tsc->vbsc_vq.vq_qsize = VTBLK_RINGSZ;\n\t/* sc->vbsc_vq.vq_notify = we have no per-queue notify */\n\n\t/*\n\t * Create an identifier for the backing file. Use parts of the\n\t * md5 sum of the filename\n\t */\n    CC_SHA256(opts, (CC_LONG)strlen(opts), digest);\n\tsnprintf(sc->vbsc_ident, VTBLK_BLK_ID_BYTES, \"BHYVE-%02X%02X-%02X%02X-%02X%02X\",\n\t    digest[0], digest[1], digest[2], digest[3], digest[4], digest[5]);\n\n\t/* setup virtio block config space */\n\tsc->vbsc_cfg.vbc_capacity =\n\t\t(uint64_t) (size / DEV_BSIZE); /* 512-byte units */\n\tsc->vbsc_cfg.vbc_size_max = 0;\t/* not negotiated */\n\tsc->vbsc_cfg.vbc_seg_max = BLOCKIF_IOV_MAX;\n\tsc->vbsc_cfg.vbc_geometry.cylinders = 0;\t/* no geometry */\n\tsc->vbsc_cfg.vbc_geometry.heads = 0;\n\tsc->vbsc_cfg.vbc_geometry.sectors = 0;\n\tsc->vbsc_cfg.vbc_blk_size = (uint32_t) sectsz;\n\tsc->vbsc_cfg.vbc_topology.physical_block_exp =\n\t    (uint8_t) ((sts > sectsz) ? (ffsll(sts / sectsz) - 1) : 0);\n\tsc->vbsc_cfg.vbc_topology.alignment_offset =\n\t    (uint8_t) ((sto != 0) ? ((sts - sto) / sectsz) : 0);\n\tsc->vbsc_cfg.vbc_topology.min_io_size = 0;\n\tsc->vbsc_cfg.vbc_topology.opt_io_size = 0;\n\tsc->vbsc_cfg.vbc_writeback = 0;\n\n\t/*\n\t * Should we move some of this into virtio.c?  Could\n\t * have the device, class, and subdev_0 as fields in\n\t * the virtio constants structure.\n\t */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_BLOCK);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_STORAGE);\n\tpci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_BLOCK);\n\tpci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);\n\n\tif (vi_intr_init(&sc->vbsc_vs, 1, fbsdrun_virtio_msix())) {\n\t\tblockif_close(sc->bc);\n\t\tfree(sc);\n\t\treturn (1);\n\t}\n\tvi_set_io_bar(&sc->vbsc_vs, 0);\n\treturn (0);\n}\n\nstatic int\npci_vtblk_cfgwrite(UNUSED void *vsc, int offset, UNUSED int size,\n\tUNUSED uint32_t value)\n{\n\tDPRINTF((\"vtblk: write to readonly reg %d\\n\\r\", offset));\n\treturn (1);\n}\n\nstatic int\npci_vtblk_cfgread(void *vsc, int offset, int size, uint32_t *retval)\n{\n\tstruct pci_vtblk_softc *sc = vsc;\n\tvoid *ptr;\n\n\t/* our caller has already verified offset and size */\n\tptr = (uint8_t *)&sc->vbsc_cfg + offset;\n\tmemcpy(retval, ptr, size);\n\treturn (0);\n}\n\nstatic struct pci_devemu pci_de_vblk = {\n\t.pe_emu =\t\"virtio-blk\",\n\t.pe_init =\tpci_vtblk_init,\n\t.pe_barwrite =\tvi_pci_write,\n\t.pe_barread =\tvi_pci_read\n};\nPCI_EMUL_SET(pci_de_vblk);\n"
  },
  {
    "path": "src/pci_virtio_net_tap.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <strings.h>\n#include <pthread.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <assert.h>\n#include <sys/time.h>\n#include <sys/select.h>\n#include <sys/param.h>\n#include <sys/uio.h>\n#include <sys/ioctl.h>\n#include <net/ethernet.h>\n\n#include <CommonCrypto/CommonDigest.h>\n\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/linker_set.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/mevent.h>\n#include <xhyve/virtio.h>\n\n#define USE_MEVENT 0\n\n#define VTNET_RINGSZ 1024\n#define VTNET_MAXSEGS 32\n\n/*\n * Host capabilities.  Note that we only offer a few of these.\n */\n// #define VIRTIO_NET_F_CSUM (1 << 0) /* host handles partial cksum */\n// #define VIRTIO_NET_F_GUEST_CSUM (1 << 1) /* guest handles partial cksum */\n#define VIRTIO_NET_F_MAC (1 << 5) /* host supplies MAC */\n// #define VIRTIO_NET_F_GSO_DEPREC (1 << 6) /* deprecated: host handles GSO */\n// #define VIRTIO_NET_F_GUEST_TSO4 (1 << 7) /* guest can rcv TSOv4 */\n// #define VIRTIO_NET_F_GUEST_TSO6 (1 << 8) /* guest can rcv TSOv6 */\n// #define VIRTIO_NET_F_GUEST_ECN (1 << 9) /* guest can rcv TSO with ECN */\n// #define VIRTIO_NET_F_GUEST_UFO (1 << 10) /* guest can rcv UFO */\n// #define VIRTIO_NET_F_HOST_TSO4 (1 << 11) /* host can rcv TSOv4 */\n// #define VIRTIO_NET_F_HOST_TSO6 (1 << 12) /* host can rcv TSOv6 */\n// #define VIRTIO_NET_F_HOST_ECN (1 << 13) /* host can rcv TSO with ECN */\n// #define VIRTIO_NET_F_HOST_UFO (1 << 14) /* host can rcv UFO */\n#define VIRTIO_NET_F_MRG_RXBUF (1 << 15) /* host can merge RX buffers */\n#define VIRTIO_NET_F_STATUS (1 << 16) /* config status field available */\n// #define VIRTIO_NET_F_CTRL_VQ (1 << 17) /* control channel available */\n// #define VIRTIO_NET_F_CTRL_RX (1 << 18) /* control channel RX mode support */\n// #define VIRTIO_NET_F_CTRL_VLAN (1 << 19) /* control channel VLAN filtering */\n// #define VIRTIO_NET_F_GUEST_ANNOUNCE (1 << 21) /* guest can send gratuit. pkts */\n\n#define VTNET_S_HOSTCAPS \\\n\t(VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_STATUS | \\\n\tVIRTIO_F_NOTIFY_ON_EMPTY)\n\n#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\n\n/*\n * PCI config-space \"registers\"\n */\nstruct virtio_net_config {\n\tuint8_t mac[6];\n\tuint16_t status;\n} __packed;\n\n/*\n * Queue definitions.\n */\n#define VTNET_RXQ 0\n#define VTNET_TXQ 1\n// #define VTNET_CTLQ 2 /* NB: not yet supported */\n#define VTNET_MAXQ 3\n\n/*\n * Fixed network header size\n */\nstruct virtio_net_rxhdr {\n\tuint8_t vrh_flags;\n\tuint8_t vrh_gso_type;\n\tuint16_t vrh_hdr_len;\n\tuint16_t vrh_gso_size;\n\tuint16_t vrh_csum_start;\n\tuint16_t vrh_csum_offset;\n\tuint16_t vrh_bufs;\n} __packed;\n\n#pragma clang diagnostic pop\n\n/*\n * Debug printf\n */\nstatic int pci_vtnet_debug;\n#define DPRINTF(params) if (pci_vtnet_debug) printf params\n#define WPRINTF(params) printf params\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n/*\n * Per-device softc\n */\nstruct pci_vtnet_softc {\n\tstruct virtio_softc vsc_vs;\n\tstruct vqueue_info vsc_queues[VTNET_MAXQ - 1];\n\tpthread_mutex_t vsc_mtx;\n\tstruct mevent *vsc_mevp;\n\tint vsc_tapfd;\n\tint vsc_rx_ready;\n\tvolatile int resetting;/* set and checked outside lock */\n\tuint64_t vsc_features; /* negotiated features */\n\tstruct virtio_net_config vsc_config;\n\tpthread_mutex_t rx_mtx;\n\tint rx_in_progress;\n\tint rx_vhdrlen;\n\tint rx_merge; /* merged rx bufs in use */\n\tpthread_t tx_tid;\n\tpthread_mutex_t tx_mtx;\n\tpthread_cond_t tx_cond;\n\tint tx_in_progress;\n};\n#pragma clang diagnostic pop\n\nstatic void pci_vtnet_reset(void *);\n/* static void pci_vtnet_notify(void *, struct vqueue_info *); */\nstatic int pci_vtnet_cfgread(void *, int, int, uint32_t *);\nstatic int pci_vtnet_cfgwrite(void *, int, int, uint32_t);\nstatic void pci_vtnet_neg_features(void *, uint64_t);\n\nstatic struct virtio_consts vtnet_vi_consts = {\n\t\"vtnet\",\t\t/* our name */\n\tVTNET_MAXQ - 1,\t\t/* we currently support 2 virtqueues */\n\tsizeof(struct virtio_net_config), /* config reg size */\n\tpci_vtnet_reset,\t/* reset */\n\tNULL,\t\t\t/* device-wide qnotify -- not used */\n\tpci_vtnet_cfgread,\t/* read PCI config */\n\tpci_vtnet_cfgwrite,\t/* write PCI config */\n\tpci_vtnet_neg_features,\t/* apply negotiated features */\n\tVTNET_S_HOSTCAPS,\t/* our capabilities */\n};\n\n/*\n * If the transmit thread is active then stall until it is done.\n */\nstatic void\npci_vtnet_txwait(struct pci_vtnet_softc *sc)\n{\n\n\tpthread_mutex_lock(&sc->tx_mtx);\n\twhile (sc->tx_in_progress) {\n\t\tpthread_mutex_unlock(&sc->tx_mtx);\n\t\tusleep(10000);\n\t\tpthread_mutex_lock(&sc->tx_mtx);\n\t}\n\tpthread_mutex_unlock(&sc->tx_mtx);\n}\n\n/*\n * If the receive thread is active then stall until it is done.\n */\nstatic void\npci_vtnet_rxwait(struct pci_vtnet_softc *sc)\n{\n\n\tpthread_mutex_lock(&sc->rx_mtx);\n\twhile (sc->rx_in_progress) {\n\t\tpthread_mutex_unlock(&sc->rx_mtx);\n\t\tusleep(10000);\n\t\tpthread_mutex_lock(&sc->rx_mtx);\n\t}\n\tpthread_mutex_unlock(&sc->rx_mtx);\n}\n\nstatic void\npci_vtnet_reset(void *vsc)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\tDPRINTF((\"vtnet: device reset requested !\\n\"));\n\n\tsc->resetting = 1;\n\n\t/*\n\t * Wait for the transmit and receive threads to finish their\n\t * processing.\n\t */\n\tpci_vtnet_txwait(sc);\n\tpci_vtnet_rxwait(sc);\n\n\tsc->vsc_rx_ready = 0;\n\tsc->rx_merge = 1;\n\tsc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);\n\n\t/* now reset rings, MSI-X vectors, and negotiated capabilities */\n\tvi_reset_dev(&sc->vsc_vs);\n\n\tsc->resetting = 0;\n}\n\n/*\n * Called to send a buffer chain out to the tap device\n */\nstatic void\npci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,\n\t\t int len)\n{\n\tstatic char pad[60]; /* all zero bytes */\n\n\tif (sc->vsc_tapfd == -1)\n\t\treturn;\n\n\t/*\n\t * If the length is < 60, pad out to that and add the\n\t * extra zero'd segment to the iov. It is guaranteed that\n\t * there is always an extra iov available by the caller.\n\t */\n\tif (len < 60) {\n\t\tiov[iovcnt].iov_base = pad;\n\t\tiov[iovcnt].iov_len = (size_t) (60 - len);\n\t\tiovcnt++;\n\t}\n\t(void) writev(sc->vsc_tapfd, iov, iovcnt);\n}\n\n/*\n *  Called when there is read activity on the tap file descriptor.\n * Each buffer posted by the guest is assumed to be able to contain\n * an entire ethernet frame + rx header.\n *  MP note: the dummybuf is only used for discarding frames, so there\n * is no need for it to be per-vtnet or locked.\n */\nstatic uint8_t dummybuf[2048];\n\nstatic __inline struct iovec *\nrx_iov_trim(struct iovec *iov, int *niov, int tlen)\n{\n\tstruct iovec *riov;\n\n\t/* XXX short-cut: assume first segment is >= tlen */\n\tassert(iov[0].iov_len >= ((size_t) tlen));\n\n\tiov[0].iov_len -= ((size_t) tlen);\n\tif (iov[0].iov_len == 0) {\n\t\tassert(*niov > 1);\n\t\t*niov -= 1;\n\t\triov = &iov[1];\n\t} else {\n\t\tiov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base +\n\t\t\t((size_t) tlen));\n\t\triov = &iov[0];\n\t}\n\n\treturn (riov);\n}\n\nstatic void\npci_vtnet_tap_rx(struct pci_vtnet_softc *sc)\n{\n\tstruct iovec iov[VTNET_MAXSEGS], *riov;\n\tstruct vqueue_info *vq;\n\tvoid *vrx;\n\tint len, n;\n\tuint16_t idx;\n\n\t/*\n\t * Should never be called without a valid tap fd\n\t */\n\tassert(sc->vsc_tapfd != -1);\n\n\t/*\n\t * But, will be called when the rx ring hasn't yet\n\t * been set up or the guest is resetting the device.\n\t */\n\tif (!sc->vsc_rx_ready || sc->resetting) {\n\t\t/*\n\t\t * Drop the packet and try later.\n\t\t */\n\t\t(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));\n\t\treturn;\n\t}\n\n\t/*\n\t * Check for available rx buffers\n\t */\n\tvq = &sc->vsc_queues[VTNET_RXQ];\n\tif (!vq_has_descs(vq)) {\n\t\t/*\n\t\t * Drop the packet and try later.  Interrupt on\n\t\t * empty, if that's negotiated.\n\t\t */\n\t\t(void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));\n\t\tvq_endchains(vq, 1);\n\t\treturn;\n\t}\n\n\tdo {\n\t\t/*\n\t\t * Get descriptor chain.\n\t\t */\n\t\tn = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);\n\t\tassert(n >= 1 && n <= VTNET_MAXSEGS);\n\n\t\t/*\n\t\t * Get a pointer to the rx header, and use the\n\t\t * data immediately following it for the packet buffer.\n\t\t */\n\t\tvrx = iov[0].iov_base;\n\t\triov = rx_iov_trim(iov, &n, sc->rx_vhdrlen);\n\n\t\tlen = (int) readv(sc->vsc_tapfd, riov, n);\n\n\t\tif (len < 0 && errno == EWOULDBLOCK) {\n\t\t\t/*\n\t\t\t * No more packets, but still some avail ring\n\t\t\t * entries.  Interrupt if needed/appropriate.\n\t\t\t */\n\t\t\tvq_retchain(vq);\n\t\t\tvq_endchains(vq, 0);\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t * The only valid field in the rx packet header is the\n\t\t * number of buffers if merged rx bufs were negotiated.\n\t\t */\n\t\tmemset(vrx, 0, sc->rx_vhdrlen);\n\n\t\tif (sc->rx_merge) {\n\t\t\tstruct virtio_net_rxhdr *vrxh;\n\n\t\t\tvrxh = vrx;\n\t\t\tvrxh->vrh_bufs = 1;\n\t\t}\n\n\t\t/*\n\t\t * Release this chain and handle more chains.\n\t\t */\n\t\tvq_relchain(vq, idx, ((uint32_t) (len + sc->rx_vhdrlen)));\n\t} while (vq_has_descs(vq));\n\n\t/* Interrupt if needed, including for NOTIFY_ON_EMPTY. */\n\tvq_endchains(vq, 1);\n}\n\n#if USE_MEVENT\nstatic void\npci_vtnet_tap_callback(UNUSED int fd, UNUSED enum ev_type type, void *param)\n{\n\tstruct pci_vtnet_softc *sc = param;\n\n\tpthread_mutex_lock(&sc->rx_mtx);\n\tsc->rx_in_progress = 1;\n\tpci_vtnet_tap_rx(sc);\n\tsc->rx_in_progress = 0;\n\tpthread_mutex_unlock(&sc->rx_mtx);\n\n}\n\n#else /* !USE_MEVENT */\n\nstatic void *\npci_vtnet_tap_select_func(void *vsc) {\n\tstruct pci_vtnet_softc *sc;\n\tfd_set rfd;\n\n\tsc = vsc;\n\n\tassert(sc);\n\tassert(sc->vsc_tapfd != -1);\n\n\tFD_ZERO(&rfd);\n\tFD_SET(sc->vsc_tapfd, &rfd);\n\n\twhile (1) {\n\t\tif (select((sc->vsc_tapfd + 1), &rfd, NULL, NULL, NULL) == -1) {\n\t\t\tabort();\n\t\t}\n\n\t\tpthread_mutex_lock(&sc->rx_mtx);\n\t\tsc->rx_in_progress = 1;\n\t\tpci_vtnet_tap_rx(sc);\n\t\tsc->rx_in_progress = 0;\n\t\tpthread_mutex_unlock(&sc->rx_mtx);\n\t}\n\n\treturn (NULL);\n}\n#endif\n\nstatic void\npci_vtnet_ping_rxq(void *vsc, struct vqueue_info *vq)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\t/*\n\t * A qnotify means that the rx process can now begin\n\t */\n\tif (sc->vsc_rx_ready == 0) {\n\t\tsc->vsc_rx_ready = 1;\n\t\tvq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;\n\t}\n}\n\nstatic void\npci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vqueue_info *vq)\n{\n\tstruct iovec iov[VTNET_MAXSEGS + 1];\n\tint i, n;\n\tint plen, tlen;\n\tuint16_t idx;\n\n\t/*\n\t * Obtain chain of descriptors.  The first one is\n\t * really the header descriptor, so we need to sum\n\t * up two lengths: packet length and transfer length.\n\t */\n\tn = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);\n\tassert(n >= 1 && n <= VTNET_MAXSEGS);\n\tplen = 0;\n\ttlen = (int) iov[0].iov_len;\n\tfor (i = 1; i < n; i++) {\n\t\tplen += iov[i].iov_len;\n\t\ttlen += iov[i].iov_len;\n\t}\n\n\tDPRINTF((\"virtio: packet send, %d bytes, %d segs\\n\\r\", plen, n));\n\tpci_vtnet_tap_tx(sc, &iov[1], n - 1, plen);\n\n\t/* chain is processed, release it and set tlen */\n\tvq_relchain(vq, idx, ((uint32_t) tlen));\n}\n\nstatic void\npci_vtnet_ping_txq(void *vsc, struct vqueue_info *vq)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\t/*\n\t * Any ring entries to process?\n\t */\n\tif (!vq_has_descs(vq))\n\t\treturn;\n\n\t/* Signal the tx thread for processing */\n\tpthread_mutex_lock(&sc->tx_mtx);\n\tvq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;\n\tif (sc->tx_in_progress == 0)\n\t\tpthread_cond_signal(&sc->tx_cond);\n\tpthread_mutex_unlock(&sc->tx_mtx);\n}\n\n/*\n * Thread which will handle processing of TX desc\n */\nstatic void *\npci_vtnet_tx_thread(void *param)\n{\n\tstruct pci_vtnet_softc *sc = param;\n\tstruct vqueue_info *vq;\n\tint error;\n\n\tvq = &sc->vsc_queues[VTNET_TXQ];\n\n\t/*\n\t * Let us wait till the tx queue pointers get initialised &\n\t * first tx signaled\n\t */\n\tpthread_mutex_lock(&sc->tx_mtx);\n\terror = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);\n\tassert(error == 0);\n\n\tfor (;;) {\n\t\t/* note - tx mutex is locked here */\n\t\twhile (sc->resetting || !vq_has_descs(vq)) {\n\t\t\tvq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY;\n\t\t\tmb();\n\t\t\tif (!sc->resetting && vq_has_descs(vq))\n\t\t\t\tbreak;\n\n\t\t\tsc->tx_in_progress = 0;\n\t\t\terror = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);\n\t\t\tassert(error == 0);\n\t\t}\n\t\tvq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;\n\t\tsc->tx_in_progress = 1;\n\t\tpthread_mutex_unlock(&sc->tx_mtx);\n\n\t\tdo {\n\t\t\t/*\n\t\t\t * Run through entries, placing them into\n\t\t\t * iovecs and sending when an end-of-packet\n\t\t\t * is found\n\t\t\t */\n\t\t\tpci_vtnet_proctx(sc, vq);\n\t\t} while (vq_has_descs(vq));\n\n\t\t/*\n\t\t * Generate an interrupt if needed.\n\t\t */\n\t\tvq_endchains(vq, 1);\n\n\t\tpthread_mutex_lock(&sc->tx_mtx);\n\t}\n}\n\n#ifdef notyet\nstatic void\npci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq)\n{\n\n\tDPRINTF((\"vtnet: control qnotify!\\n\\r\"));\n}\n#endif\n\nstatic int\npci_vtnet_parsemac(char *mac_str, uint8_t *mac_addr)\n{\n        struct ether_addr *ea;\n        char *tmpstr;\n        char zero_addr[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };\n\n        tmpstr = strsep(&mac_str,\"=\");\n       \n        if ((mac_str != NULL) && (!strcmp(tmpstr,\"mac\"))) {\n                ea = ether_aton(mac_str);\n\n                if (ea == NULL || ETHER_IS_MULTICAST(ea->octet) ||\n                    memcmp(ea->octet, zero_addr, ETHER_ADDR_LEN) == 0) {\n\t\t\tfprintf(stderr, \"Invalid MAC %s\\n\", mac_str);\n                        return (EINVAL);\n                } else\n                        memcpy(mac_addr, ea->octet, ETHER_ADDR_LEN);\n        }\n\n        return (0);\n}\n\n\nstatic int\npci_vtnet_init(struct pci_devinst *pi, char *opts)\n{\n\tunsigned char digest[CC_SHA256_DIGEST_LENGTH];\n\tchar nstr[80];\n\tstruct pci_vtnet_softc *sc;\n\tchar *devname;\n\tchar *vtopts;\n\tint mac_provided;\n#if !USE_MEVENT\n\tpthread_t sthrd;\n#endif\n\n\tsc = calloc(1, sizeof(struct pci_vtnet_softc));\n\n\tpthread_mutex_init(&sc->vsc_mtx, NULL);\n\n\tvi_softc_linkup(&sc->vsc_vs, &vtnet_vi_consts, sc, pi, sc->vsc_queues);\n\tsc->vsc_vs.vs_mtx = &sc->vsc_mtx;\n\n\tsc->vsc_queues[VTNET_RXQ].vq_qsize = VTNET_RINGSZ;\n\tsc->vsc_queues[VTNET_RXQ].vq_notify = pci_vtnet_ping_rxq;\n\tsc->vsc_queues[VTNET_TXQ].vq_qsize = VTNET_RINGSZ;\n\tsc->vsc_queues[VTNET_TXQ].vq_notify = pci_vtnet_ping_txq;\n#ifdef notyet\n\tsc->vsc_queues[VTNET_CTLQ].vq_qsize = VTNET_RINGSZ;\n        sc->vsc_queues[VTNET_CTLQ].vq_notify = pci_vtnet_ping_ctlq;\n#endif\n \n\t/*\n\t * Attempt to open the tap device and read the MAC address\n\t * if specified\n\t */\n\tmac_provided = 0;\n\tsc->vsc_tapfd = -1;\n\tif (opts != NULL) {\n\t\tchar tbuf[80];\n\t\tint err;\n\n\t\tdevname = vtopts = strdup(opts);\n\t\t(void) strsep(&vtopts, \",\");\n\n\t\tif (vtopts != NULL) {\n\t\t\terr = pci_vtnet_parsemac(vtopts, sc->vsc_config.mac);\n\t\t\tif (err != 0) {\n\t\t\t\tfree(devname);\n\t\t\t\treturn (err);\n\t\t\t}\n\t\t\tmac_provided = 1;\n\t\t}\n\n\t\tstrcpy(tbuf, \"/dev/\");\n\t\tstrlcat(tbuf, devname, sizeof(tbuf));\n\n\t\tfree(devname);\n\n\t\tsc->vsc_tapfd = open(tbuf, O_RDWR);\n\t\tif (sc->vsc_tapfd == -1) {\n\t\t\tWPRINTF((\"open of tap device %s failed\\n\", tbuf));\n\t\t} else {\n\t\t\t/*\n\t\t\t * Set non-blocking and register for read\n\t\t\t * notifications with the event loop\n\t\t\t */\n\t\t\tint opt = 1;\n\t\t\tif (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) {\n\t\t\t\tWPRINTF((\"tap device O_NONBLOCK failed\\n\"));\n\t\t\t\tclose(sc->vsc_tapfd);\n\t\t\t\tsc->vsc_tapfd = -1;\n\t\t\t}\n\n#if USE_MEVENT\n\t\t\tsc->vsc_mevp = mevent_add(sc->vsc_tapfd,\n\t\t\t\t\t\t  EVF_READ,\n\t\t\t\t\t\t  pci_vtnet_tap_callback,\n\t\t\t\t\t\t  sc);\n\t\t\tif (sc->vsc_mevp == NULL) {\n\t\t\t\tWPRINTF((\"Could not register event\\n\"));\n\t\t\t\tclose(sc->vsc_tapfd);\n\t\t\t\tsc->vsc_tapfd = -1;\n\t\t\t}\n\n#else /* !USE_MEVENT */\n\t\t\tif (pthread_create(&sthrd, NULL, pci_vtnet_tap_select_func, sc)) {\n\t\t\t\tWPRINTF((\"Could not create tap receive thread\\n\"));\n\t\t\t\tclose(sc->vsc_tapfd);\n\t\t\t\tsc->vsc_tapfd = -1;\n\t\t\t}\n#endif\n\t\t}\n\t}\n\n\t/*\n\t * The default MAC address is the standard NetApp OUI of 00-a0-98,\n\t * followed by an MD5 of the PCI slot/func number and dev name\n\t */\n\tif (!mac_provided) {\n\t\tsnprintf(nstr, sizeof(nstr), \"%d-%d-%s\", pi->pi_slot,\n\t\t    pi->pi_func, vmname);\n\n        CC_SHA256(nstr, (CC_LONG)strlen(nstr), digest);\n\n\t\tsc->vsc_config.mac[0] = 0x00;\n\t\tsc->vsc_config.mac[1] = 0xa0;\n\t\tsc->vsc_config.mac[2] = 0x98;\n\t\tsc->vsc_config.mac[3] = digest[0];\n\t\tsc->vsc_config.mac[4] = digest[1];\n\t\tsc->vsc_config.mac[5] = digest[2];\n\t}\n\n\t/* initialize config space */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);\n\tpci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);\n\tpci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);\n\n\t/* Link is up if we managed to open tap device. */\n\tsc->vsc_config.status = (opts == NULL || sc->vsc_tapfd >= 0);\n\t\n\t/* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */\n\tif (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))\n\t\treturn (1);\n\n\t/* use BAR 0 to map config regs in IO space */\n\tvi_set_io_bar(&sc->vsc_vs, 0);\n\n\tsc->resetting = 0;\n\n\tsc->rx_merge = 1;\n\tsc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);\n\tsc->rx_in_progress = 0;\n\tpthread_mutex_init(&sc->rx_mtx, NULL); \n\n\t/* \n\t * Initialize tx semaphore & spawn TX processing thread.\n\t * As of now, only one thread for TX desc processing is\n\t * spawned. \n\t */\n\tsc->tx_in_progress = 0;\n\tpthread_mutex_init(&sc->tx_mtx, NULL);\n\tpthread_cond_init(&sc->tx_cond, NULL);\n\tpthread_create(&sc->tx_tid, NULL, pci_vtnet_tx_thread, (void *)sc);\n\treturn (0);\n}\n\nstatic int\npci_vtnet_cfgwrite(void *vsc, int offset, int size, uint32_t value)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\tvoid *ptr;\n\n\tif (offset < 6) {\n\t\tassert(offset + size <= 6);\n\t\t/*\n\t\t * The driver is allowed to change the MAC address\n\t\t */\n\t\tptr = &sc->vsc_config.mac[offset];\n\t\tmemcpy(ptr, &value, size);\n\t} else {\n\t\t/* silently ignore other writes */\n\t\tDPRINTF((\"vtnet: write to readonly reg %d\\n\\r\", offset));\n\t}\n\n\treturn (0);\n}\n\nstatic int\npci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\tvoid *ptr;\n\n\tptr = (uint8_t *)&sc->vsc_config + offset;\n\tmemcpy(retval, ptr, size);\n\treturn (0);\n}\n\nstatic void\npci_vtnet_neg_features(void *vsc, uint64_t negotiated_features)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\tsc->vsc_features = negotiated_features;\n\n\tif (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) {\n\t\tsc->rx_merge = 0;\n\t\t/* non-merge rx header is 2 bytes shorter */\n\t\tsc->rx_vhdrlen -= 2;\n\t}\n}\n\nstatic struct pci_devemu pci_de_vnet_tap = {\n\t.pe_emu = \t\"virtio-tap\",\n\t.pe_init =\tpci_vtnet_init,\n\t.pe_barwrite =\tvi_pci_write,\n\t.pe_barread =\tvi_pci_read\n};\nPCI_EMUL_SET(pci_de_vnet_tap);\n"
  },
  {
    "path": "src/pci_virtio_net_vmnet.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n/*\n *\n * The vmnet support is ported from the MirageOS project:\n *\n * https://github.com/mirage/ocaml-vmnet\n *\n *      Copyright (C) 2014 Anil Madhavapeddy <anil@recoil.org>\n *\n *      Permission to use, copy, modify, and distribute this software for any\n *      purpose with or without fee is hereby granted, provided that the above\n *      copyright notice and this permission notice appear in all copies.\n *\n *      THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n *      WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n *      MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n *      ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n *      WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n *      ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n *      OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <strings.h>\n#include <pthread.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <assert.h>\n#include <sys/select.h>\n#include <sys/param.h>\n#include <sys/uio.h>\n#include <sys/ioctl.h>\n#include <net/ethernet.h>\n#include <dispatch/dispatch.h>\n#include <vmnet/vmnet.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/linker_set.h>\n#include <xhyve/support/uuid.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/mevent.h>\n#include <xhyve/virtio.h>\n\n#define VTNET_RINGSZ 1024\n#define VTNET_MAXSEGS 32\n\n/*\n * Host capabilities.  Note that we only offer a few of these.\n */\n// #define VIRTIO_NET_F_CSUM (1 << 0) /* host handles partial cksum */\n// #define VIRTIO_NET_F_GUEST_CSUM (1 << 1) /* guest handles partial cksum */\n#define VIRTIO_NET_F_MAC (1 << 5) /* host supplies MAC */\n// #define VIRTIO_NET_F_GSO_DEPREC (1 << 6) /* deprecated: host handles GSO */\n// #define VIRTIO_NET_F_GUEST_TSO4 (1 << 7) /* guest can rcv TSOv4 */\n// #define VIRTIO_NET_F_GUEST_TSO6 (1 << 8) /* guest can rcv TSOv6 */\n// #define VIRTIO_NET_F_GUEST_ECN (1 << 9) /* guest can rcv TSO with ECN */\n// #define VIRTIO_NET_F_GUEST_UFO (1 << 10) /* guest can rcv UFO */\n// #define VIRTIO_NET_F_HOST_TSO4 (1 << 11) /* host can rcv TSOv4 */\n// #define VIRTIO_NET_F_HOST_TSO6 (1 << 12) /* host can rcv TSOv6 */\n// #define VIRTIO_NET_F_HOST_ECN (1 << 13) /* host can rcv TSO with ECN */\n// #define VIRTIO_NET_F_HOST_UFO (1 << 14) /* host can rcv UFO */\n#define VIRTIO_NET_F_MRG_RXBUF (1 << 15) /* host can merge RX buffers */\n#define VIRTIO_NET_F_STATUS (1 << 16) /* config status field available */\n// #define VIRTIO_NET_F_CTRL_VQ (1 << 17) /* control channel available */\n// #define VIRTIO_NET_F_CTRL_RX (1 << 18) /* control channel RX mode support */\n// #define VIRTIO_NET_F_CTRL_VLAN (1 << 19) /* control channel VLAN filtering */\n// #define VIRTIO_NET_F_GUEST_ANNOUNCE (1 << 21) /* guest can send gratuit. pkts */\n\n#define VTNET_S_HOSTCAPS \\\n\t(VIRTIO_NET_F_MAC | VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_STATUS | \\\n\tVIRTIO_F_NOTIFY_ON_EMPTY)\n\n// #define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\n\n/*\n * PCI config-space \"registers\"\n */\nstruct virtio_net_config {\n\tuint8_t mac[6];\n\tuint16_t status;\n} __packed;\n\n/*\n * Queue definitions.\n */\n#define VTNET_RXQ 0\n#define VTNET_TXQ 1\n// #define VTNET_CTLQ 2 /* NB: not yet supported */\n#define VTNET_MAXQ 3\n\n/*\n * Fixed network header size\n */\nstruct virtio_net_rxhdr {\n\tuint8_t vrh_flags;\n\tuint8_t vrh_gso_type;\n\tuint16_t vrh_hdr_len;\n\tuint16_t vrh_gso_size;\n\tuint16_t vrh_csum_start;\n\tuint16_t vrh_csum_offset;\n\tuint16_t vrh_bufs;\n} __packed;\n\n#pragma clang diagnostic pop\n\n/*\n * Debug printf\n */\nstatic int pci_vtnet_debug;\n#define DPRINTF(params) if (pci_vtnet_debug) printf params\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n/*\n * Per-device softc\n */\nstruct pci_vtnet_softc {\n\tstruct virtio_softc vsc_vs;\n\tstruct vqueue_info vsc_queues[VTNET_MAXQ - 1];\n\tpthread_mutex_t vsc_mtx;\n\tstruct vmnet_state *vms;\n\tint vsc_rx_ready;\n\tvolatile int resetting;/* set and checked outside lock */\n\tuint64_t vsc_features; /* negotiated features */\n\tstruct virtio_net_config vsc_config;\n\tpthread_mutex_t rx_mtx;\n\tint rx_in_progress;\n\tint rx_vhdrlen;\n\tint rx_merge; /* merged rx bufs in use */\n\tpthread_t tx_tid;\n\tpthread_mutex_t tx_mtx;\n\tpthread_cond_t tx_cond;\n\tint tx_in_progress;\n};\n\nstatic void pci_vtnet_reset(void *);\n/* static void pci_vtnet_notify(void *, struct vqueue_info *); */\nstatic int pci_vtnet_cfgread(void *, int, int, uint32_t *);\nstatic int pci_vtnet_cfgwrite(void *, int, int, uint32_t);\nstatic void pci_vtnet_neg_features(void *, uint64_t);\n\nstatic struct virtio_consts vtnet_vi_consts = {\n\t\"vtnet\",\t\t/* our name */\n\tVTNET_MAXQ - 1,\t\t/* we currently support 2 virtqueues */\n\tsizeof(struct virtio_net_config), /* config reg size */\n\tpci_vtnet_reset,\t/* reset */\n\tNULL,\t\t\t/* device-wide qnotify -- not used */\n\tpci_vtnet_cfgread,\t/* read PCI config */\n\tpci_vtnet_cfgwrite,\t/* write PCI config */\n\tpci_vtnet_neg_features,\t/* apply negotiated features */\n\tVTNET_S_HOSTCAPS,\t/* our capabilities */\n};\n\nstruct vmnet_state {\n\tinterface_ref iface;\n\tuint8_t mac[6];\n\tunsigned int mtu;\n\tunsigned int max_packet_size;\n};\n\n#pragma clang diagnostic pop\n\nstatic void pci_vtnet_tap_callback(struct pci_vtnet_softc *sc);\n\n/*\n * Drop privileges according to the CERT Secure C Coding Standard section\n * POS36-C\n * https://www.securecoding.cert.org/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges\n*/\nstatic int drop_privileges(void) {\n\t// If we are not effectively root, don't drop privileges\n\tif (geteuid() != 0 && getegid() != 0) {\n\t\treturn 0;\n\t}\n\tif (setgid(getgid()) == -1) {\n\t\treturn -1;\n\t}\n\tif (setuid(getuid()) == -1) {\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\n/*\n * Create an interface for the guest using Apple's vmnet framework.\n *\n * The interface works in VMNET_SHARED_MODE which allows for packets\n * of the guest to reach other guests and the Internet.\n *\n * See also: https://developer.apple.com/library/mac/documentation/vmnet/Reference/vmnet_Reference/index.html\n */\nstatic int\nvmn_create(struct pci_vtnet_softc *sc)\n{\n\txpc_object_t interface_desc;\n\tuuid_t uuid;\n\t__block interface_ref iface;\n\t__block vmnet_return_t iface_status;\n\tdispatch_semaphore_t iface_created;\n\tdispatch_queue_t if_create_q;\n\tdispatch_queue_t if_q;\n\tstruct vmnet_state *vms;\n\tuint32_t uuid_status;\n\n\tinterface_desc = xpc_dictionary_create(NULL, NULL, 0);\n\txpc_dictionary_set_uint64(interface_desc, vmnet_operation_mode_key,\n\t\tVMNET_SHARED_MODE);\n\n\tif (guest_uuid_str != NULL) {\n\t\tuuid_from_string(guest_uuid_str, &uuid, &uuid_status);\n\t\tif (uuid_status != uuid_s_ok) {\n\t\t\treturn (-1);\n\t\t}\n\t} else {\n\t\tuuid_generate_random(uuid);\n\t}\n\n\txpc_dictionary_set_uuid(interface_desc, vmnet_interface_id_key, uuid);\n\tiface = NULL;\n\tiface_status = 0;\n\n\tvms = malloc(sizeof(struct vmnet_state));\n\n\tif (!vms) {\n\t\treturn (-1);\n\t}\n\n\tif_create_q = dispatch_queue_create(\"org.xhyve.vmnet.create\",\n\t\tDISPATCH_QUEUE_SERIAL);\n\n\tiface_created = dispatch_semaphore_create(0);\n\n\tiface = vmnet_start_interface(interface_desc, if_create_q,\n\t\t^(vmnet_return_t status, xpc_object_t interface_param)\n\t{\n\t\tiface_status = status;\n\t\tif (status != VMNET_SUCCESS || !interface_param) {\n\t\t\tdispatch_semaphore_signal(iface_created);\n\t\t\treturn;\n\t\t}\n\n\t\tif (sscanf(xpc_dictionary_get_string(interface_param,\n\t\t\tvmnet_mac_address_key),\n\t\t\t\"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n\t\t\t&vms->mac[0], &vms->mac[1], &vms->mac[2], &vms->mac[3],\n\t\t\t&vms->mac[4], &vms->mac[5]) != 6)\n\t\t{\n\t\t\tassert(0);\n\t\t}\n\n\t\tvms->mtu = (unsigned)\n\t\t\txpc_dictionary_get_uint64(interface_param, vmnet_mtu_key);\n\t\tvms->max_packet_size = (unsigned)\n\t\t\txpc_dictionary_get_uint64(interface_param,\n\t\t\t\tvmnet_max_packet_size_key);\n\t\tdispatch_semaphore_signal(iface_created);\n\t});\n\n\tdispatch_semaphore_wait(iface_created, DISPATCH_TIME_FOREVER);\n\tdispatch_release(if_create_q);\n\n\tif (iface == NULL || iface_status != VMNET_SUCCESS) {\n\t\tfprintf(stderr, \"virtio_net: Could not create vmnet interface, \"\n\t\t\t\"permission denied or no entitlement?\\n\");\n\t\tfree(vms);\n\t\treturn (-1);\n\t}\n\n\tvms->iface = iface;\n\tsc->vms = vms;\n\n\tif_q = dispatch_queue_create(\"org.xhyve.vmnet.iface_q\", 0);\n\n\tvmnet_interface_set_event_callback(iface, VMNET_INTERFACE_PACKETS_AVAILABLE,\n\t\tif_q, ^(UNUSED interface_event_t event_id, UNUSED xpc_object_t event)\n\t{\n\t\tpci_vtnet_tap_callback(sc);\n\t});\n\tif (drop_privileges() == -1) {\n\t\tperror(\"Dropping privileges after networking was enabled.\");\n\t\tfree(vms);\n\t\treturn (-1);\n\t}\n\n\treturn (0);\n}\n\nstatic ssize_t\nvmn_read(struct vmnet_state *vms, struct iovec *iov, int n) {\n\tvmnet_return_t r;\n\tstruct vmpktdesc v;\n\tint pktcnt;\n\tint i;\n\n\tv.vm_pkt_size = 0;\n\n\tfor (i = 0; i < n; i++) {\n\t\tv.vm_pkt_size += iov[i].iov_len;\n\t}\n\n\tassert(v.vm_pkt_size >= vms->max_packet_size);\n\n\tv.vm_pkt_iov = iov;\n\tv.vm_pkt_iovcnt = (uint32_t) n;\n\tv.vm_flags = 0; /* TODO no clue what this is */\n\n\tpktcnt = 1;\n\n\tr = vmnet_read(vms->iface, &v, &pktcnt);\n\n\tassert(r == VMNET_SUCCESS);\n\n\tif (pktcnt < 1) {\n\t\treturn (-1);\n\t}\n\n\treturn ((ssize_t) v.vm_pkt_size);\n}\n\nstatic void\nvmn_write(struct vmnet_state *vms, struct iovec *iov, int n) {\n\tvmnet_return_t r;\n\tstruct vmpktdesc v;\n\tint pktcnt;\n\tint i;\n\n\tv.vm_pkt_size = 0;\n\n\tfor (i = 0; i < n; i++) {\n\t\tv.vm_pkt_size += iov[i].iov_len;\n\t}\n\n\tassert(v.vm_pkt_size <= vms->max_packet_size);\n\n\tv.vm_pkt_iov = iov;\n\tv.vm_pkt_iovcnt = (uint32_t) n;\n\tv.vm_flags = 0; /* TODO no clue what this is */\n\n\tpktcnt = 1;\n\n\tr = vmnet_write(vms->iface, &v, &pktcnt);\n\n\tassert(r == VMNET_SUCCESS);\n}\n\n/*\n * If the transmit thread is active then stall until it is done.\n */\nstatic void\npci_vtnet_txwait(struct pci_vtnet_softc *sc)\n{\n\n\tpthread_mutex_lock(&sc->tx_mtx);\n\twhile (sc->tx_in_progress) {\n\t\tpthread_mutex_unlock(&sc->tx_mtx);\n\t\tusleep(10000);\n\t\tpthread_mutex_lock(&sc->tx_mtx);\n\t}\n\tpthread_mutex_unlock(&sc->tx_mtx);\n}\n\n/*\n * If the receive thread is active then stall until it is done.\n */\nstatic void\npci_vtnet_rxwait(struct pci_vtnet_softc *sc)\n{\n\n\tpthread_mutex_lock(&sc->rx_mtx);\n\twhile (sc->rx_in_progress) {\n\t\tpthread_mutex_unlock(&sc->rx_mtx);\n\t\tusleep(10000);\n\t\tpthread_mutex_lock(&sc->rx_mtx);\n\t}\n\tpthread_mutex_unlock(&sc->rx_mtx);\n}\n\nstatic void\npci_vtnet_reset(void *vsc)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\tDPRINTF((\"vtnet: device reset requested !\\n\"));\n\n\tsc->resetting = 1;\n\n\t/*\n\t * Wait for the transmit and receive threads to finish their\n\t * processing.\n\t */\n\tpci_vtnet_txwait(sc);\n\tpci_vtnet_rxwait(sc);\n\n\tsc->vsc_rx_ready = 0;\n\tsc->rx_merge = 1;\n\tsc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);\n\n\t/* now reset rings, MSI-X vectors, and negotiated capabilities */\n\tvi_reset_dev(&sc->vsc_vs);\n\n\tsc->resetting = 0;\n}\n\n/*\n * Called to send a buffer chain out to the tap device\n */\nstatic void\npci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,\n\t\t int len)\n{\n\tstatic char pad[60]; /* all zero bytes */\n\n\tif (!sc->vms)\n\t\treturn;\n\n\t/*\n\t * If the length is < 60, pad out to that and add the\n\t * extra zero'd segment to the iov. It is guaranteed that\n\t * there is always an extra iov available by the caller.\n\t */\n\tif (len < 60) {\n\t\tiov[iovcnt].iov_base = pad;\n\t\tiov[iovcnt].iov_len = (size_t) (60 - len);\n\t\tiovcnt++;\n\t}\n\tvmn_write(sc->vms, iov, iovcnt);\n}\n\n/*\n *  Called when there is read activity on the tap file descriptor.\n * Each buffer posted by the guest is assumed to be able to contain\n * an entire ethernet frame + rx header.\n *  MP note: the dummybuf is only used for discarding frames, so there\n * is no need for it to be per-vtnet or locked.\n */\nstatic uint8_t dummybuf[2048];\n\nstatic __inline struct iovec *\nrx_iov_trim(struct iovec *iov, int *niov, int tlen)\n{\n\tstruct iovec *riov;\n\n\t/* XXX short-cut: assume first segment is >= tlen */\n\tassert(iov[0].iov_len >= ((size_t) tlen));\n\n\tiov[0].iov_len -= ((size_t) tlen);\n\tif (iov[0].iov_len == 0) {\n\t\tassert(*niov > 1);\n\t\t*niov -= 1;\n\t\triov = &iov[1];\n\t} else {\n\t\tiov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base +\n\t\t\t((size_t) tlen));\n\t\triov = &iov[0];\n\t}\n\n\treturn (riov);\n}\n\nstatic void\npci_vtnet_tap_rx(struct pci_vtnet_softc *sc)\n{\n\tstruct iovec iov[VTNET_MAXSEGS], *riov;\n\tstruct vqueue_info *vq;\n\tvoid *vrx;\n\tint len, n;\n\tuint16_t idx;\n\n\t/*\n\t * Should never be called without a valid tap fd\n\t */\n\tassert(sc->vms);\n\n\t/*\n\t * But, will be called when the rx ring hasn't yet\n\t * been set up or the guest is resetting the device.\n\t */\n\tif (!sc->vsc_rx_ready || sc->resetting) {\n\t\t/*\n\t\t * Drop the packet and try later.\n\t\t */\n\t\tiov[0].iov_base = dummybuf;\n\t\tiov[0].iov_len = sizeof(dummybuf);\n\t\t(void) vmn_read(sc->vms, iov, 1);\n\t\treturn;\n\t}\n\n\t/*\n\t * Check for available rx buffers\n\t */\n\tvq = &sc->vsc_queues[VTNET_RXQ];\n\tif (!vq_has_descs(vq)) {\n\t\t/*\n\t\t * Drop the packet and try later.  Interrupt on\n\t\t * empty, if that's negotiated.\n\t\t */\n\t\tiov[0].iov_base = dummybuf;\n\t\tiov[0].iov_len = sizeof(dummybuf);\n\t\t(void) vmn_read(sc->vms, iov, 1);\n\t\tvq_endchains(vq, 1);\n\t\treturn;\n\t}\n\n\tdo {\n\t\t/*\n\t\t * Get descriptor chain.\n\t\t */\n\t\tn = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);\n\t\tassert(n >= 1 && n <= VTNET_MAXSEGS);\n\n\t\t/*\n\t\t * Get a pointer to the rx header, and use the\n\t\t * data immediately following it for the packet buffer.\n\t\t */\n\t\tvrx = iov[0].iov_base;\n\t\triov = rx_iov_trim(iov, &n, sc->rx_vhdrlen);\n\n\t\tlen = (int) vmn_read(sc->vms, riov, n);\n\n\t\tif (len < 0 && errno == EWOULDBLOCK) {\n\t\t\t/*\n\t\t\t * No more packets, but still some avail ring\n\t\t\t * entries.  Interrupt if needed/appropriate.\n\t\t\t */\n\t\t\tvq_retchain(vq);\n\t\t\tvq_endchains(vq, 0);\n\t\t\treturn;\n\t\t}\n\n\t\t/*\n\t\t * The only valid field in the rx packet header is the\n\t\t * number of buffers if merged rx bufs were negotiated.\n\t\t */\n\t\tmemset(vrx, 0, sc->rx_vhdrlen);\n\n\t\tif (sc->rx_merge) {\n\t\t\tstruct virtio_net_rxhdr *vrxh;\n\n\t\t\tvrxh = vrx;\n\t\t\tvrxh->vrh_bufs = 1;\n\t\t}\n\n\t\t/*\n\t\t * Release this chain and handle more chains.\n\t\t */\n\t\tvq_relchain(vq, idx, ((uint32_t) (len + sc->rx_vhdrlen)));\n\t} while (vq_has_descs(vq));\n\n\t/* Interrupt if needed, including for NOTIFY_ON_EMPTY. */\n\tvq_endchains(vq, 1);\n}\n\nstatic void\npci_vtnet_tap_callback(struct pci_vtnet_softc *sc)\n{\n\tpthread_mutex_lock(&sc->rx_mtx);\n\tsc->rx_in_progress = 1;\n\tpci_vtnet_tap_rx(sc);\n\tsc->rx_in_progress = 0;\n\tpthread_mutex_unlock(&sc->rx_mtx);\n\n}\n\nstatic void\npci_vtnet_ping_rxq(void *vsc, struct vqueue_info *vq)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\t/*\n\t * A qnotify means that the rx process can now begin\n\t */\n\tif (sc->vsc_rx_ready == 0) {\n\t\tsc->vsc_rx_ready = 1;\n\t\tvq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;\n\t}\n}\n\nstatic void\npci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vqueue_info *vq)\n{\n\tstruct iovec iov[VTNET_MAXSEGS + 1];\n\tint i, n;\n\tint plen, tlen;\n\tuint16_t idx;\n\n\t/*\n\t * Obtain chain of descriptors.  The first one is\n\t * really the header descriptor, so we need to sum\n\t * up two lengths: packet length and transfer length.\n\t */\n\tn = vq_getchain(vq, &idx, iov, VTNET_MAXSEGS, NULL);\n\tassert(n >= 1 && n <= VTNET_MAXSEGS);\n\tplen = 0;\n\ttlen = (int) iov[0].iov_len;\n\tfor (i = 1; i < n; i++) {\n\t\tplen += iov[i].iov_len;\n\t\ttlen += iov[i].iov_len;\n\t}\n\n\tDPRINTF((\"virtio: packet send, %d bytes, %d segs\\n\\r\", plen, n));\n\tpci_vtnet_tap_tx(sc, &iov[1], n - 1, plen);\n\n\t/* chain is processed, release it and set tlen */\n\tvq_relchain(vq, idx, ((uint32_t) tlen));\n}\n\nstatic void\npci_vtnet_ping_txq(void *vsc, struct vqueue_info *vq)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\t/*\n\t * Any ring entries to process?\n\t */\n\tif (!vq_has_descs(vq))\n\t\treturn;\n\n\t/* Signal the tx thread for processing */\n\tpthread_mutex_lock(&sc->tx_mtx);\n\tvq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;\n\tif (sc->tx_in_progress == 0)\n\t\tpthread_cond_signal(&sc->tx_cond);\n\tpthread_mutex_unlock(&sc->tx_mtx);\n}\n\n/*\n * Thread which will handle processing of TX desc\n */\nstatic void *\npci_vtnet_tx_thread(void *param)\n{\n\tstruct pci_vtnet_softc *sc = param;\n\tstruct vqueue_info *vq;\n\tint error;\n\n\tvq = &sc->vsc_queues[VTNET_TXQ];\n\n\t/*\n\t * Let us wait till the tx queue pointers get initialised &\n\t * first tx signaled\n\t */\n\tpthread_mutex_lock(&sc->tx_mtx);\n\terror = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);\n\tassert(error == 0);\n\n\tfor (;;) {\n\t\t/* note - tx mutex is locked here */\n\t\twhile (sc->resetting || !vq_has_descs(vq)) {\n\t\t\tvq->vq_used->vu_flags &= ~VRING_USED_F_NO_NOTIFY;\n\t\t\tmb();\n\t\t\tif (!sc->resetting && vq_has_descs(vq))\n\t\t\t\tbreak;\n\n\t\t\tsc->tx_in_progress = 0;\n\t\t\terror = pthread_cond_wait(&sc->tx_cond, &sc->tx_mtx);\n\t\t\tassert(error == 0);\n\t\t}\n\t\tvq->vq_used->vu_flags |= VRING_USED_F_NO_NOTIFY;\n\t\tsc->tx_in_progress = 1;\n\t\tpthread_mutex_unlock(&sc->tx_mtx);\n\n\t\tdo {\n\t\t\t/*\n\t\t\t * Run through entries, placing them into\n\t\t\t * iovecs and sending when an end-of-packet\n\t\t\t * is found\n\t\t\t */\n\t\t\tpci_vtnet_proctx(sc, vq);\n\t\t} while (vq_has_descs(vq));\n\n\t\t/*\n\t\t * Generate an interrupt if needed.\n\t\t */\n\t\tvq_endchains(vq, 1);\n\n\t\tpthread_mutex_lock(&sc->tx_mtx);\n\t}\n}\n\n#ifdef notyet\nstatic void\npci_vtnet_ping_ctlq(void *vsc, struct vqueue_info *vq)\n{\n\tDPRINTF((\"vtnet: control qnotify!\\n\\r\"));\n}\n#endif\n\nstatic int\npci_vtnet_init(struct pci_devinst *pi, UNUSED char *opts)\n{\n\tstruct pci_vtnet_softc *sc;\n\tint mac_provided;\n\n\tsc = calloc(1, sizeof(struct pci_vtnet_softc));\n\n\tpthread_mutex_init(&sc->vsc_mtx, NULL);\n\n\tvi_softc_linkup(&sc->vsc_vs, &vtnet_vi_consts, sc, pi, sc->vsc_queues);\n\tsc->vsc_vs.vs_mtx = &sc->vsc_mtx;\n\n\tsc->vsc_queues[VTNET_RXQ].vq_qsize = VTNET_RINGSZ;\n\tsc->vsc_queues[VTNET_RXQ].vq_notify = pci_vtnet_ping_rxq;\n\tsc->vsc_queues[VTNET_TXQ].vq_qsize = VTNET_RINGSZ;\n\tsc->vsc_queues[VTNET_TXQ].vq_notify = pci_vtnet_ping_txq;\n#ifdef notyet\n\tsc->vsc_queues[VTNET_CTLQ].vq_qsize = VTNET_RINGSZ;\n        sc->vsc_queues[VTNET_CTLQ].vq_notify = pci_vtnet_ping_ctlq;\n#endif\n \n\t/*\n\t * Attempt to open the tap device and read the MAC address\n\t * if specified\n\t */\n\tmac_provided = 0;\n\n\tif (vmn_create(sc) == -1) {\n\t\treturn (-1);\n\t}\n\n    if (print_mac == 1)\n    {\n\t\tprintf(\"MAC: %02x:%02x:%02x:%02x:%02x:%02x\\n\",\n\t\t\tsc->vms->mac[0], sc->vms->mac[1], sc->vms->mac[2],\n\t\t\tsc->vms->mac[3], sc->vms->mac[4], sc->vms->mac[5]);\n\t\texit(0);\n    }\n\n\tsc->vsc_config.mac[0] = sc->vms->mac[0];\n\tsc->vsc_config.mac[1] = sc->vms->mac[1];\n\tsc->vsc_config.mac[2] = sc->vms->mac[2];\n\tsc->vsc_config.mac[3] = sc->vms->mac[3];\n\tsc->vsc_config.mac[4] = sc->vms->mac[4];\n\tsc->vsc_config.mac[5] = sc->vms->mac[5];\n\n\t/* initialize config space */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);\n\tpci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);\n\tpci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);\n\n\t/* Link is up if we managed to open tap device. */\n\tsc->vsc_config.status = 1;\n\t\n\t/* use BAR 1 to map MSI-X table and PBA, if we're using MSI-X */\n\tif (vi_intr_init(&sc->vsc_vs, 1, fbsdrun_virtio_msix()))\n\t\treturn (1);\n\n\t/* use BAR 0 to map config regs in IO space */\n\tvi_set_io_bar(&sc->vsc_vs, 0);\n\n\tsc->resetting = 0;\n\n\tsc->rx_merge = 1;\n\tsc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);\n\tsc->rx_in_progress = 0;\n\tpthread_mutex_init(&sc->rx_mtx, NULL); \n\n\t/* \n\t * Initialize tx semaphore & spawn TX processing thread.\n\t * As of now, only one thread for TX desc processing is\n\t * spawned. \n\t */\n\tsc->tx_in_progress = 0;\n\tpthread_mutex_init(&sc->tx_mtx, NULL);\n\tpthread_cond_init(&sc->tx_cond, NULL);\n\tpthread_create(&sc->tx_tid, NULL, pci_vtnet_tx_thread, (void *)sc);\n\treturn (0);\n}\n\nstatic int\npci_vtnet_cfgwrite(void *vsc, int offset, int size, uint32_t value)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\tvoid *ptr;\n\n\tif (offset < 6) {\n\t\tassert(offset + size <= 6);\n\t\t/*\n\t\t * The driver is allowed to change the MAC address\n\t\t */\n\t\tptr = &sc->vsc_config.mac[offset];\n\t\tmemcpy(ptr, &value, size);\n\t} else {\n\t\t/* silently ignore other writes */\n\t\tDPRINTF((\"vtnet: write to readonly reg %d\\n\\r\", offset));\n\t}\n\n\treturn (0);\n}\n\nstatic int\npci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\tvoid *ptr;\n\n\tptr = (uint8_t *)&sc->vsc_config + offset;\n\tmemcpy(retval, ptr, size);\n\treturn (0);\n}\n\nstatic void\npci_vtnet_neg_features(void *vsc, uint64_t negotiated_features)\n{\n\tstruct pci_vtnet_softc *sc = vsc;\n\n\tsc->vsc_features = negotiated_features;\n\n\tif (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) {\n\t\tsc->rx_merge = 0;\n\t\t/* non-merge rx header is 2 bytes shorter */\n\t\tsc->rx_vhdrlen -= 2;\n\t}\n}\n\nstatic struct pci_devemu pci_de_vnet_vmnet = {\n\t.pe_emu = \t\"virtio-net\",\n\t.pe_init =\tpci_vtnet_init,\n\t.pe_barwrite =\tvi_pci_write,\n\t.pe_barread =\tvi_pci_read\n};\nPCI_EMUL_SET(pci_de_vnet_vmnet);\n"
  },
  {
    "path": "src/pci_virtio_rnd.c",
    "content": "/*-\n * Copyright (c) 2014 Nahanni Systems Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer\n *    in this position and unchanged.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/*\n * virtio entropy device emulation.\n * Randomness is sourced from /dev/random which does not block\n * once it has been seeded at bootup.\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <pthread.h>\n#include <fcntl.h>\n#include <unistd.h>\n#include <errno.h>\n#include <assert.h>\n#include <sys/param.h>\n#include <sys/uio.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/linker_set.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/virtio.h>\n\n#define VTRND_RINGSZ 64\n\n\nstatic int pci_vtrnd_debug;\n#define DPRINTF(params) if (pci_vtrnd_debug) printf params\n#define WPRINTF(params) printf params\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n/*\n * Per-device softc\n */\nstruct pci_vtrnd_softc {\n\tstruct virtio_softc vrsc_vs;\n\tstruct vqueue_info vrsc_vq;\n\tpthread_mutex_t vrsc_mtx;\n\tuint64_t vrsc_cfg;\n\tint vrsc_fd;\n};\n#pragma clang diagnostic pop\n\nstatic void pci_vtrnd_reset(void *);\nstatic void pci_vtrnd_notify(void *, struct vqueue_info *);\n\nstatic struct virtio_consts vtrnd_vi_consts = {\n\t\"vtrnd\", /* our name */\n\t1, /* we support 1 virtqueue */\n\t0, /* config reg size */\n\tpci_vtrnd_reset, /* reset */\n\tpci_vtrnd_notify, /* device-wide qnotify */\n\tNULL, /* read virtio config */\n\tNULL, /* write virtio config */\n\tNULL, /* apply negotiated features */\n\t0, /* our capabilities */\n};\n\n\nstatic void\npci_vtrnd_reset(void *vsc)\n{\n\tstruct pci_vtrnd_softc *sc;\n\n\tsc = vsc;\n\n\tDPRINTF((\"vtrnd: device reset requested !\\n\"));\n\tvi_reset_dev(&sc->vrsc_vs);\n}\n\n\nstatic void\npci_vtrnd_notify(void *vsc, struct vqueue_info *vq)\n{\n\tstruct iovec iov;\n\tstruct pci_vtrnd_softc *sc;\n\tint len;\n\tuint16_t idx;\n\n\tsc = vsc;\n\n\tif (sc->vrsc_fd < 0) {\n\t\tvq_endchains(vq, 0);\n\t\treturn;\n\t}\n\n\twhile (vq_has_descs(vq)) {\n\t\tvq_getchain(vq, &idx, &iov, 1, NULL);\n\n\t\tlen = (int) read(sc->vrsc_fd, iov.iov_base, iov.iov_len);\n\n\t\tDPRINTF((\"vtrnd: vtrnd_notify(): %d\\r\\n\", len));\n\n\t\t/* Catastrophe if unable to read from /dev/random */\n\t\tassert(len > 0);\n\n\t\t/*\n\t\t * Release this chain and handle more\n\t\t */\n\t\tvq_relchain(vq, idx, ((uint32_t) len));\n\t}\n\tvq_endchains(vq, 1);\t/* Generate interrupt if appropriate. */\n}\n\n\nstatic int\npci_vtrnd_init(struct pci_devinst *pi, UNUSED char *opts)\n{\n\tstruct pci_vtrnd_softc *sc;\n\tint fd;\n\tint len;\n\tuint8_t v;\n\n\t/*\n\t * Should always be able to open /dev/random.\n\t */\n\tfd = open(\"/dev/random\", O_RDONLY | O_NONBLOCK);\n\n\tassert(fd >= 0);\n\n\t/*\n\t * Check that device is seeded and non-blocking.\n\t */\n\tlen = (int) read(fd, &v, sizeof(v));\n\tif (len <= 0) {\n\t\tWPRINTF((\"vtrnd: /dev/random not ready, read(): %d\", len));\n\t\treturn (1);\n\t}\n\n\tsc = calloc(1, sizeof(struct pci_vtrnd_softc));\n\n\tvi_softc_linkup(&sc->vrsc_vs, &vtrnd_vi_consts, sc, pi, &sc->vrsc_vq);\n\tsc->vrsc_vs.vs_mtx = &sc->vrsc_mtx;\n\n\tsc->vrsc_vq.vq_qsize = VTRND_RINGSZ;\n\n\t/* keep /dev/random opened while emulating */\n\tsc->vrsc_fd = fd;\n\n\t/* initialize config space */\n\tpci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_RANDOM);\n\tpci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);\n\tpci_set_cfgdata8(pi, PCIR_CLASS, PCIC_CRYPTO);\n\tpci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_ENTROPY);\n\tpci_set_cfgdata16(pi, PCIR_SUBVEND_0, VIRTIO_VENDOR);\n\n\tif (vi_intr_init(&sc->vrsc_vs, 1, fbsdrun_virtio_msix()))\n\t\treturn (1);\n\tvi_set_io_bar(&sc->vrsc_vs, 0);\n\n\treturn (0);\n}\n\n\nstatic struct pci_devemu pci_de_vrnd = {\n\t.pe_emu =\t\"virtio-rnd\",\n\t.pe_init =\tpci_vtrnd_init,\n\t.pe_barwrite =\tvi_pci_write,\n\t.pe_barread =\tvi_pci_read\n};\nPCI_EMUL_SET(pci_de_vrnd);\n"
  },
  {
    "path": "src/pm.c",
    "content": "/*-\n * Copyright (c) 2013 Hudson River Trading LLC\n * Written by: John H. Baldwin <jhb@FreeBSD.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <assert.h>\n#include <errno.h>\n#include <pthread.h>\n#include <signal.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/acpi.h>\n#include <xhyve/inout.h>\n#include <xhyve/mevent.h>\n#include <xhyve/pci_irq.h>\n#include <xhyve/pci_lpc.h>\n\nstatic pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER;\nstatic struct mevent *power_button;\nstatic sig_t old_power_handler;\n\n/*\n * Reset Control register at I/O port 0xcf9.  Bit 2 forces a system\n * reset when it transitions from 0 to 1.  Bit 1 selects the type of\n * reset to attempt: 0 selects a \"soft\" reset, and 1 selects a \"hard\"\n * reset.\n */\nstatic int\nreset_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tint error;\n\n\tstatic uint8_t reset_control;\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\tif (in)\n\t\t*eax = reset_control;\n\telse {\n\t\treset_control = (uint8_t) *eax;\n\n\t\t/* Treat hard and soft resets the same. */\n\t\tif (reset_control & 0x4) {\n\t\t\terror = xh_vm_suspend(VM_SUSPEND_RESET);\n\t\t\tassert(error == 0 || errno == EALREADY);\n\t\t}\n\t}\n\treturn (0);\n}\nINOUT_PORT(reset_reg, 0xCF9, IOPORT_F_INOUT, reset_handler);\n\n/*\n * ACPI's SCI is a level-triggered interrupt.\n */\nstatic int sci_active;\n\nstatic void\nsci_assert(void)\n{\n\tif (sci_active)\n\t\treturn;\n\txh_vm_isa_assert_irq(SCI_INT, SCI_INT);\n\tsci_active = 1;\n}\n\nstatic void\nsci_deassert(void)\n{\n\tif (!sci_active)\n\t\treturn;\n\txh_vm_isa_deassert_irq(SCI_INT, SCI_INT);\n\tsci_active = 0;\n}\n\n/*\n * Power Management 1 Event Registers\n *\n * The only power management event supported is a power button upon\n * receiving SIGTERM.\n */\nstatic uint16_t pm1_enable, pm1_status;\n\n#define\tPM1_TMR_STS\t\t0x0001\n#define\tPM1_BM_STS\t\t0x0010\n#define\tPM1_GBL_STS\t\t0x0020\n#define\tPM1_PWRBTN_STS\t\t0x0100\n#define\tPM1_SLPBTN_STS\t\t0x0200\n#define\tPM1_RTC_STS\t\t0x0400\n#define\tPM1_WAK_STS\t\t0x8000\n\n#define\tPM1_TMR_EN\t\t0x0001\n#define\tPM1_GBL_EN\t\t0x0020\n#define\tPM1_PWRBTN_EN\t\t0x0100\n#define\tPM1_SLPBTN_EN\t\t0x0200\n#define\tPM1_RTC_EN\t\t0x0400\n\nstatic void\nsci_update(void)\n{\n\tint need_sci;\n\n\t/* See if the SCI should be active or not. */\n\tneed_sci = 0;\n\tif ((pm1_enable & PM1_TMR_EN) && (pm1_status & PM1_TMR_STS))\n\t\tneed_sci = 1;\n\tif ((pm1_enable & PM1_GBL_EN) && (pm1_status & PM1_GBL_STS))\n\t\tneed_sci = 1;\n\tif ((pm1_enable & PM1_PWRBTN_EN) && (pm1_status & PM1_PWRBTN_STS))\n\t\tneed_sci = 1;\n\tif ((pm1_enable & PM1_SLPBTN_EN) && (pm1_status & PM1_SLPBTN_STS))\n\t\tneed_sci = 1;\n\tif ((pm1_enable & PM1_RTC_EN) && (pm1_status & PM1_RTC_STS))\n\t\tneed_sci = 1;\n\tif (need_sci)\n\t\tsci_assert();\n\telse\n\t\tsci_deassert();\n}\n\nstatic int\npm1_status_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\n\tif (bytes != 2)\n\t\treturn (-1);\n\n\tpthread_mutex_lock(&pm_lock);\n\tif (in)\n\t\t*eax = pm1_status;\n\telse {\n\t\t/*\n\t\t * Writes are only permitted to clear certain bits by\n\t\t * writing 1 to those flags.\n\t\t */\n\t\tpm1_status &= ~(*eax & (PM1_WAK_STS | PM1_RTC_STS |\n\t\t    PM1_SLPBTN_STS | PM1_PWRBTN_STS | PM1_BM_STS));\n\t\tsci_update();\n\t}\n\tpthread_mutex_unlock(&pm_lock);\n\treturn (0);\n}\n\nstatic int\npm1_enable_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\n\tif (bytes != 2)\n\t\treturn (-1);\n\n\tpthread_mutex_lock(&pm_lock);\n\tif (in)\n\t\t*eax = pm1_enable;\n\telse {\n\t\t/*\n\t\t * Only permit certain bits to be set.  We never use\n\t\t * the global lock, but ACPI-CA whines profusely if it\n\t\t * can't set GBL_EN.\n\t\t */\n\t\tpm1_enable = *eax & (PM1_PWRBTN_EN | PM1_GBL_EN);\n\t\tsci_update();\n\t}\n\tpthread_mutex_unlock(&pm_lock);\n\treturn (0);\n}\nINOUT_PORT(pm1_status, PM1A_EVT_ADDR, IOPORT_F_INOUT, pm1_status_handler);\nINOUT_PORT(pm1_enable, PM1A_EVT_ADDR2, IOPORT_F_INOUT, pm1_enable_handler);\n\nstatic void\npower_button_handler(UNUSED int signal, UNUSED enum ev_type type,\n\tUNUSED void *arg)\n{\n\tpthread_mutex_lock(&pm_lock);\n\tif (!(pm1_status & PM1_PWRBTN_STS)) {\n\t\tpm1_status |= PM1_PWRBTN_STS;\n\t\tsci_update();\n\t}\n\tpthread_mutex_unlock(&pm_lock);\n}\n\n/*\n * Power Management 1 Control Register\n *\n * This is mostly unimplemented except that we wish to handle writes that\n * set SPL_EN to handle S5 (soft power off).\n */\nstatic uint16_t pm1_control;\n\n#define\tPM1_SCI_EN\t0x0001\n#define\tPM1_SLP_TYP\t0x1c00\n#define\tPM1_SLP_EN\t0x2000\n#define\tPM1_ALWAYS_ZERO\t0xc003\n\nstatic int\npm1_control_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tint error;\n\n\tif (bytes != 2)\n\t\treturn (-1);\n\tif (in)\n\t\t*eax = pm1_control;\n\telse {\n\t\t/*\n\t\t * Various bits are write-only or reserved, so force them\n\t\t * to zero in pm1_control.  Always preserve SCI_EN as OSPM\n\t\t * can never change it.\n\t\t */\n\t\tpm1_control = (uint16_t) ((pm1_control & PM1_SCI_EN) |\n\t\t\t(*eax & ~((unsigned) (PM1_SLP_EN | PM1_ALWAYS_ZERO))));\n\n\t\t/*\n\t\t * If SLP_EN is set, check for S5.  Bhyve's _S5_ method\n\t\t * says that '5' should be stored in SLP_TYP for S5.\n\t\t */\n\t\tif (*eax & PM1_SLP_EN) {\n\t\t\tif ((pm1_control & PM1_SLP_TYP) >> 10 == 5) {\n\t\t\t\terror = xh_vm_suspend(VM_SUSPEND_POWEROFF);\n\t\t\t\tassert(error == 0 || errno == EALREADY);\n\t\t\t}\n\t\t}\n\t}\n\treturn (0);\n}\nINOUT_PORT(pm1_control, PM1A_CNT_ADDR, IOPORT_F_INOUT, pm1_control_handler);\nSYSRES_IO(PM1A_EVT_ADDR, 8);\n\n/*\n * ACPI SMI Command Register\n *\n * This write-only register is used to enable and disable ACPI.\n */\nstatic int\nsmi_cmd_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tassert(!in);\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tpthread_mutex_lock(&pm_lock);\n\tswitch (*eax) {\n\tcase BHYVE_ACPI_ENABLE:\n\t\tpm1_control |= PM1_SCI_EN;\n\t\tif (power_button == NULL) {\n\t\t\tpower_button = mevent_add(SIGTERM, EVF_SIGNAL,\n\t\t\t\tpower_button_handler, NULL);\n\t\t\told_power_handler = signal(SIGTERM, SIG_IGN);\n\t\t}\n\t\tbreak;\n\tcase BHYVE_ACPI_DISABLE:\n\t\tpm1_control &= ~PM1_SCI_EN;\n\t\tif (power_button != NULL) {\n\t\t\tmevent_delete(power_button);\n\t\t\tpower_button = NULL;\n\t\t\tsignal(SIGTERM, old_power_handler);\n\t\t}\n\t\tbreak;\n\t}\n\tpthread_mutex_unlock(&pm_lock);\n\treturn (0);\n}\nINOUT_PORT(smi_cmd, SMI_CMD, IOPORT_F_OUT, smi_cmd_handler);\nSYSRES_IO(SMI_CMD, 1);\n\nvoid\nsci_init(void)\n{\n\t/*\n\t * Mark ACPI's SCI as level trigger and bump its use count\n\t * in the PIRQ router.\n\t */\n\tpci_irq_use(SCI_INT);\n\txh_vm_isa_set_irq_trigger(SCI_INT, LEVEL_TRIGGER);\n}\n"
  },
  {
    "path": "src/post.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <assert.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/inout.h>\n#include <xhyve/pci_lpc.h>\n\nstatic int\npost_data_handler(UNUSED int vcpu, int in, UNUSED int port, int bytes,\n\tuint32_t *eax, UNUSED void *arg)\n{\n\tassert(in == 1);\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\t*eax = 0xff;\t\t/* return some garbage */\n\treturn (0);\n}\n\nINOUT_PORT(post, 0x84, IOPORT_F_IN, post_data_handler);\nSYSRES_IO(0x84, 1);\n"
  },
  {
    "path": "src/ps2kbd.c",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 Nahanni Systems Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <strings.h>\n#include <pthread.h>\n\n#include <xhyve/atkbdc.h>\n#include <xhyve/console.h>\n#include <xhyve/ps2kbd.h>\n\n/* keyboard device commands */\n#define\tPS2KC_RESET_DEV\t\t0xff\n#define\tPS2KC_DISABLE\t\t0xf5\n#define\tPS2KC_ENABLE\t\t0xf4\n#define\tPS2KC_SET_TYPEMATIC\t0xf3\n#define\tPS2KC_SEND_DEV_ID\t0xf2\n#define\tPS2KC_SET_SCANCODE_SET\t0xf0\n#define\tPS2KC_ECHO\t\t0xee\n#define\tPS2KC_SET_LEDS\t\t0xed\n\n#define\tPS2KC_BAT_SUCCESS\t0xaa\n#define\tPS2KC_ACK\t\t0xfa\n\n#define\tPS2KBD_FIFOSZ\t\t16\n\nstruct fifo {\n\tuint8_t\tbuf[PS2KBD_FIFOSZ];\n\tint\trindex;\t\t/* index to read from */\n\tint\twindex;\t\t/* index to write to */\n\tint\tnum;\t\t/* number of bytes in the fifo */\n\tint\tsize;\t\t/* size of the fifo */\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct ps2kbd_softc {\n\tstruct atkbdc_softc\t*atkbdc_sc;\n\tpthread_mutex_t\t\tmtx;\n\n\tbool\t\t\tenabled;\n\tstruct fifo\t\tfifo;\n\n\tuint8_t\t\t\tcurcmd;\t/* current command for next byte */\n};\n\n#pragma clang diagnostic pop\n\nstatic void\nfifo_init(struct ps2kbd_softc *sc)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tfifo->size = sizeof(((struct fifo *)0)->buf);\n}\n\nstatic void\nfifo_reset(struct ps2kbd_softc *sc)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tbzero(fifo, sizeof(struct fifo));\n\tfifo->size = sizeof(((struct fifo *)0)->buf);\n}\n\nstatic void\nfifo_put(struct ps2kbd_softc *sc, uint8_t val)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tif (fifo->num < fifo->size) {\n\t\tfifo->buf[fifo->windex] = val;\n\t\tfifo->windex = (fifo->windex + 1) % fifo->size;\n\t\tfifo->num++;\n\t}\n}\n\nstatic int\nfifo_get(struct ps2kbd_softc *sc, uint8_t *val)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tif (fifo->num > 0) {\n\t\t*val = fifo->buf[fifo->rindex];\n\t\tfifo->rindex = (fifo->rindex + 1) % fifo->size;\n\t\tfifo->num--;\n\t\treturn (0);\n\t}\n\n\treturn (-1);\n}\n\nint\nps2kbd_read(struct ps2kbd_softc *sc, uint8_t *val)\n{\n\tint retval;\n\n\tpthread_mutex_lock(&sc->mtx);\n\tretval = fifo_get(sc, val);\n\tpthread_mutex_unlock(&sc->mtx);\n\n\treturn (retval);\n}\n\nvoid\nps2kbd_write(struct ps2kbd_softc *sc, uint8_t val)\n{\n\tpthread_mutex_lock(&sc->mtx);\n\tif (sc->curcmd) {\n\t\tswitch (sc->curcmd) {\n\t\tcase PS2KC_SET_TYPEMATIC:\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_SET_SCANCODE_SET:\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_SET_LEDS:\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tfprintf(stderr, \"Unhandled ps2 keyboard current \"\n\t\t\t    \"command byte 0x%02x\\n\", val);\n\t\t\tbreak;\n\t\t}\n\t\tsc->curcmd = 0;\n\t} else {\n\t\tswitch (val) {\n\t\tcase 0x00:\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_RESET_DEV:\n\t\t\tfifo_reset(sc);\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tfifo_put(sc, PS2KC_BAT_SUCCESS);\n\t\t\tbreak;\n\t\tcase PS2KC_DISABLE:\n\t\t\tsc->enabled = false;\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_ENABLE:\n\t\t\tsc->enabled = true;\n\t\t\tfifo_reset(sc);\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_SET_TYPEMATIC:\n\t\t\tsc->curcmd = val;\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_SEND_DEV_ID:\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tfifo_put(sc, 0xab);\n\t\t\tfifo_put(sc, 0x83);\n\t\t\tbreak;\n\t\tcase PS2KC_SET_SCANCODE_SET:\n\t\t\tsc->curcmd = val;\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tcase PS2KC_ECHO:\n\t\t\tfifo_put(sc, PS2KC_ECHO);\n\t\t\tbreak;\n\t\tcase PS2KC_SET_LEDS:\n\t\t\tsc->curcmd = val;\n\t\t\tfifo_put(sc, PS2KC_ACK);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tfprintf(stderr, \"Unhandled ps2 keyboard command \"\n\t\t\t    \"0x%02x\\n\", val);\n\t\t\tbreak;\n\t\t}\n\t}\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\n/*\n * Translate keysym to type 2 scancode and insert into keyboard buffer.\n */\nstatic void\nps2kbd_keysym_queue(struct ps2kbd_softc *sc,\n    int down, uint32_t keysym)\n{\n\t/* ASCII to type 2 scancode lookup table */\n\tconst uint8_t translation[128] = {\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t0x29, 0x16, 0x52, 0x26, 0x25, 0x2e, 0x3d, 0x52,\n\t\t0x46, 0x45, 0x3e, 0x55, 0x41, 0x4e, 0x49, 0x4a,\n\t\t0x45, 0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d,\n\t\t0x3e, 0x46, 0x4c, 0x4c, 0x41, 0x55, 0x49, 0x4a,\n\t\t0x1e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,\n\t\t0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,\n\t\t0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,\n\t\t0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x36, 0x4e,\n\t\t0x0e, 0x1c, 0x32, 0x21, 0x23, 0x24, 0x2b, 0x34,\n\t\t0x33, 0x43, 0x3b, 0x42, 0x4b, 0x3a, 0x31, 0x44,\n\t\t0x4d, 0x15, 0x2d, 0x1b, 0x2c, 0x3c, 0x2a, 0x1d,\n\t\t0x22, 0x35, 0x1a, 0x54, 0x5d, 0x5b, 0x0e, 0x00,\n\t};\n\n    if (keysym <= 0x7f) {\n        if (!down)\n            fifo_put(sc, 0xf0);\n        fifo_put(sc, translation[keysym]);\n    } else {\n        switch (keysym) {\n        case 0xff08:\t/* Back space */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x66);\n            break;\n        case 0xff09:\t/* Tab */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x0d);\n            break;\n        case 0xff0d:\t/* Return  */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x5a);\n            break;\n        case 0xff1b:\t/* Escape */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x76);\n            break;\n        case 0xff50:\t/* Home */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x6c);\n            break;\n        case 0xff51:\t/* Left arrow */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x6b);\n            break;\n        case 0xff52:\t/* Up arrow */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x75);\n            break;\n        case 0xff53:\t/* Right arrow */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x74);\n            break;\n        case 0xff54:\t/* Down arrow */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x72);\n            break;\n        case 0xff55:\t/* PgUp */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x7d);\n            break;\n        case 0xff56:\t/* PgDwn */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x7a);\n            break;\n        case 0xff57:\t/* End */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x69);\n            break;\n        case 0xff63:\t/* Ins */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x70);\n            break;\n        case 0xff8d:\t/* Keypad Enter */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x5a);\n            break;\n        case 0xffe1:\t/* Left shift */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x12);\n            break;\n        case 0xffe2:\t/* Right shift */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x59);\n            break;\n        case 0xffe3:\t/* Left control */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x14);\n            break;\n        case 0xffe4:\t/* Right control */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x14);\n            break;\n        case 0xffe7:\t/* Left meta */\n            /* XXX */\n            break;\n        case 0xffe8:\t/* Right meta */\n            /* XXX */\n            break;\n        case 0xffe9:\t/* Left alt */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x11);\n            break;\n        case 0xfe03:\t/* AltGr */\n        case 0xffea:\t/* Right alt */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x11);\n            break;\n        case 0xffeb:\t/* Left Windows */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x1f);\n            break;\n        case 0xffec:\t/* Right Windows */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x27);\n            break;\n        case 0xffbe:    /* F1 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x05);\n            break;\n        case 0xffbf:    /* F2 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x06);\n            break;\n        case 0xffc0:    /* F3 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x04);\n            break;\n        case 0xffc1:    /* F4 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x0C);\n            break;\n        case 0xffc2:    /* F5 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x03);\n            break;\n        case 0xffc3:    /* F6 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x0B);\n            break;\n        case 0xffc4:    /* F7 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x83);\n            break;\n        case 0xffc5:    /* F8 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x0A);\n            break;\n        case 0xffc6:    /* F9 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x01);\n            break;\n        case 0xffc7:    /* F10 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x09);\n            break;\n        case 0xffc8:    /* F11 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x78);\n            break;\n        case 0xffc9:    /* F12 */\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x07);\n            break;\n        case 0xffff:    /* Del */\n            fifo_put(sc, 0xe0);\n            if (!down)\n                fifo_put(sc, 0xf0);\n            fifo_put(sc, 0x71);\n            break;\n        default:\n            fprintf(stderr, \"Unhandled ps2 keyboard keysym 0x%x\\n\",\n                 keysym);\n            break;\n        }\n    }\n}\n\nstatic void\nps2kbd_event(int down, uint32_t keysym, void *arg)\n{\n\tstruct ps2kbd_softc *sc = arg;\n\tint fifo_full;\n\n\tpthread_mutex_lock(&sc->mtx);\n\tif (!sc->enabled) {\n\t\tpthread_mutex_unlock(&sc->mtx);\n\t\treturn;\n\t}\n\tfifo_full = sc->fifo.num == PS2KBD_FIFOSZ;\n\tps2kbd_keysym_queue(sc, down, keysym);\n\tpthread_mutex_unlock(&sc->mtx);\n\n\tif (!fifo_full)\n\t\tatkbdc_event(sc->atkbdc_sc, 1);\n}\n\nstruct ps2kbd_softc *\nps2kbd_init(struct atkbdc_softc *atkbdc_sc)\n{\n\tstruct ps2kbd_softc *sc;\n\n\tsc = calloc(1, sizeof (struct ps2kbd_softc));\n\tpthread_mutex_init(&sc->mtx, NULL);\n\tfifo_init(sc);\n\tsc->atkbdc_sc = atkbdc_sc;\n\n\tconsole_kbd_register(ps2kbd_event, sc, 1);\n\n\treturn (sc);\n}\n\n"
  },
  {
    "path": "src/ps2mouse.c",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 Nahanni Systems Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n\n#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <strings.h>\n#include <pthread.h>\n\n#include <xhyve/atkbdc.h>\n#include <xhyve/console.h>\n#include <xhyve/ps2mouse.h>\n\n/* mouse device commands */\n#define\tPS2MC_RESET_DEV\t\t0xff\n#define\tPS2MC_SET_DEFAULTS\t0xf6\n#define\tPS2MC_DISABLE\t\t0xf5\n#define\tPS2MC_ENABLE\t\t0xf4\n#define\tPS2MC_SET_SAMPLING_RATE\t0xf3\n#define\tPS2MC_SEND_DEV_ID\t0xf2\n#define\tPS2MC_SET_REMOTE_MODE\t0xf0\n#define\tPS2MC_SEND_DEV_DATA\t0xeb\n#define\tPS2MC_SET_STREAM_MODE\t0xea\n#define\tPS2MC_SEND_DEV_STATUS\t0xe9\n#define\tPS2MC_SET_RESOLUTION\t0xe8\n#define\tPS2MC_SET_SCALING1\t0xe7\n#define\tPS2MC_SET_SCALING2\t0xe6\n\n#define\tPS2MC_BAT_SUCCESS\t0xaa\n#define\tPS2MC_ACK\t\t0xfa\n\n/* mouse device id */\n#define\tPS2MOUSE_DEV_ID\t\t0x0\n\n/* mouse data bits */\n#define\tPS2M_DATA_Y_OFLOW\t0x80\n#define\tPS2M_DATA_X_OFLOW\t0x40\n#define\tPS2M_DATA_Y_SIGN\t0x20\n#define\tPS2M_DATA_X_SIGN\t0x10\n#define\tPS2M_DATA_AONE\t\t0x08\n#define\tPS2M_DATA_MID_BUTTON\t0x04\n#define\tPS2M_DATA_RIGHT_BUTTON\t0x02\n#define\tPS2M_DATA_LEFT_BUTTON\t0x01\n\n/* mouse status bits */\n#define\tPS2M_STS_REMOTE_MODE\t0x40\n#define\tPS2M_STS_ENABLE_DEV\t0x20\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wunused-macros\"\n\n#define\tPS2M_STS_SCALING_21\t0x10\n\n#pragma clang diagnostic pop\n\n#define\tPS2M_STS_MID_BUTTON\t0x04\n#define\tPS2M_STS_RIGHT_BUTTON\t0x02\n#define\tPS2M_STS_LEFT_BUTTON\t0x01\n\n#define\tPS2MOUSE_FIFOSZ\t\t16\n\nstruct fifo {\n\tuint8_t\tbuf[PS2MOUSE_FIFOSZ];\n\tint\trindex;\t\t/* index to read from */\n\tint\twindex;\t\t/* index to write to */\n\tint\tnum;\t\t/* number of bytes in the fifo */\n\tint\tsize;\t\t/* size of the fifo */\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct ps2mouse_softc {\n\tstruct atkbdc_softc\t*atkbdc_sc;\n\tpthread_mutex_t\t\tmtx;\n\n\tuint8_t\t\tstatus;\n\tuint8_t\t\tresolution;\n\tuint8_t\t\tsampling_rate;\n\tint\t\tctrlenable;\n\tstruct fifo\tfifo;\n\n\tuint8_t\t\tcurcmd;\t/* current command for next byte */\n\n\tint\t\tcur_x, cur_y;\n\tint\t\tdelta_x, delta_y;\n};\n\n#pragma clang diagnostic pop\n\nstatic void\nfifo_init(struct ps2mouse_softc *sc)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tfifo->size = sizeof(((struct fifo *)0)->buf);\n}\n\nstatic void\nfifo_reset(struct ps2mouse_softc *sc)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tbzero(fifo, sizeof(struct fifo));\n\tfifo->size = sizeof(((struct fifo *)0)->buf);\n}\n\nstatic void\nfifo_put(struct ps2mouse_softc *sc, uint8_t val)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tif (fifo->num < fifo->size) {\n\t\tfifo->buf[fifo->windex] = val;\n\t\tfifo->windex = (fifo->windex + 1) % fifo->size;\n\t\tfifo->num++;\n\t}\n}\n\nstatic int\nfifo_get(struct ps2mouse_softc *sc, uint8_t *val)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->fifo;\n\tif (fifo->num > 0) {\n\t\t*val = fifo->buf[fifo->rindex];\n\t\tfifo->rindex = (fifo->rindex + 1) % fifo->size;\n\t\tfifo->num--;\n\t\treturn (0);\n\t}\n\n\treturn (-1);\n}\n\nstatic void\nmovement_reset(struct ps2mouse_softc *sc)\n{\n\tsc->delta_x = 0;\n\tsc->delta_y = 0;\n}\n\nstatic void\nmovement_update(struct ps2mouse_softc *sc, int x, int y)\n{\n\tsc->delta_x += x - sc->cur_x;\n\tsc->delta_y += sc->cur_y - y;\n\tsc->cur_x = x;\n\tsc->cur_y = y;\n}\n\nstatic void\nmovement_get(struct ps2mouse_softc *sc)\n{\n\tuint8_t val0, val1, val2;\n\n\tval0 = PS2M_DATA_AONE;\n\tval0 |= sc->status & (PS2M_DATA_LEFT_BUTTON |\n\t    PS2M_DATA_RIGHT_BUTTON | PS2M_DATA_MID_BUTTON);\n\n\tif (sc->delta_x >= 0) {\n\t\tif (sc->delta_x > 255) {\n\t\t\tval0 |= PS2M_DATA_X_OFLOW;\n\t\t\tval1 = 255;\n\t\t} else\n\t\t\tval1 = (uint8_t)sc->delta_x;\n\t} else {\n\t\tval0 |= PS2M_DATA_X_SIGN;\n\t\tif (sc->delta_x < -255) {\n\t\t\tval0 |= PS2M_DATA_X_OFLOW;\n\t\t\tval1 = 255;\n\t\t} else\n\t\t\tval1 = (uint8_t)sc->delta_x;\n\t}\n\tsc->delta_x = 0;\n\n\tif (sc->delta_y >= 0) {\n\t\tif (sc->delta_y > 255) {\n\t\t\tval0 |= PS2M_DATA_Y_OFLOW;\n\t\t\tval2 = 255;\n\t\t} else\n\t\t\tval2 = (uint8_t)sc->delta_y;\n\t} else {\n\t\tval0 |= PS2M_DATA_Y_SIGN;\n\t\tif (sc->delta_y < -255) {\n\t\t\tval0 |= PS2M_DATA_Y_OFLOW;\n\t\t\tval2 = 255;\n\t\t} else\n\t\t\tval2 = (uint8_t)sc->delta_y;\n\t}\n\tsc->delta_y = 0;\n\n\tif (sc->fifo.num < (sc->fifo.size - 3)) {\n\t\tfifo_put(sc, val0);\n\t\tfifo_put(sc, val1);\n\t\tfifo_put(sc, val2);\n\t}\n}\n\nstatic void\nps2mouse_reset(struct ps2mouse_softc *sc)\n{\n\tfifo_reset(sc);\n\tmovement_reset(sc);\n\tsc->status = PS2M_STS_ENABLE_DEV;\n\tsc->resolution = 4;\n\tsc->sampling_rate = 100;\n\n\tsc->cur_x = 0;\n\tsc->cur_y = 0;\n\tsc->delta_x = 0;\n\tsc->delta_y = 0;\n}\n\nint\nps2mouse_read(struct ps2mouse_softc *sc, uint8_t *val)\n{\n\tint retval;\n\n\tpthread_mutex_lock(&sc->mtx);\n\tretval = fifo_get(sc, val);\n\tpthread_mutex_unlock(&sc->mtx);\n\n\treturn (retval);\n}\n\nint\nps2mouse_fifocnt(struct ps2mouse_softc *sc)\n{\n\treturn (sc->fifo.num);\n}\n\nvoid\nps2mouse_toggle(struct ps2mouse_softc *sc, int enable)\n{\n\tpthread_mutex_lock(&sc->mtx);\n\tif (enable)\n\t\tsc->ctrlenable = 1;\n\telse {\n\t\tsc->ctrlenable = 0;\n\t\tsc->fifo.rindex = 0;\n\t\tsc->fifo.windex = 0;\n\t\tsc->fifo.num = 0;\n\t}\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\nvoid\nps2mouse_write(struct ps2mouse_softc *sc, uint8_t val, int insert)\n{\n\tpthread_mutex_lock(&sc->mtx);\n\tfifo_reset(sc);\n\tif (sc->curcmd) {\n\t\tswitch (sc->curcmd) {\n\t\tcase PS2MC_SET_SAMPLING_RATE:\n\t\t\tsc->sampling_rate = val;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_RESOLUTION:\n\t\t\tsc->resolution = val;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tfprintf(stderr, \"Unhandled ps2 mouse current \"\n\t\t\t    \"command byte 0x%02x\\n\", val);\n\t\t\tbreak;\n\t\t}\n\t\tsc->curcmd = 0;\n\n\t} else if (insert) {\n\t\tfifo_put(sc, val);\n\t} else {\n\t\tswitch (val) {\n\t\tcase 0x00:\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_RESET_DEV:\n\t\t\tps2mouse_reset(sc);\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tfifo_put(sc, PS2MC_BAT_SUCCESS);\n\t\t\tfifo_put(sc, PS2MOUSE_DEV_ID);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_DEFAULTS:\n\t\t\tps2mouse_reset(sc);\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_DISABLE:\n\t\t\tfifo_reset(sc);\n\t\t\tsc->status &= ~PS2M_STS_ENABLE_DEV;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_ENABLE:\n\t\t\tfifo_reset(sc);\n\t\t\tsc->status |= PS2M_STS_ENABLE_DEV;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_SAMPLING_RATE:\n\t\t\tsc->curcmd = val;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_SEND_DEV_ID:\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tfifo_put(sc, PS2MOUSE_DEV_ID);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_REMOTE_MODE:\n\t\t\tsc->status |= PS2M_STS_REMOTE_MODE;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_SEND_DEV_DATA:\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tmovement_get(sc);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_STREAM_MODE:\n\t\t\tsc->status &= ~PS2M_STS_REMOTE_MODE;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_SEND_DEV_STATUS:\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tfifo_put(sc, sc->status);\n\t\t\tfifo_put(sc, sc->resolution);\n\t\t\tfifo_put(sc, sc->sampling_rate);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_RESOLUTION:\n\t\t\tsc->curcmd = val;\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tcase PS2MC_SET_SCALING1:\n\t\tcase PS2MC_SET_SCALING2:\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tfifo_put(sc, PS2MC_ACK);\n\t\t\tfprintf(stderr, \"Unhandled ps2 mouse command \"\n\t\t\t    \"0x%02x\\n\", val);\n\t\t\tbreak;\n\t\t}\n\t}\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\nstatic void\nps2mouse_event(uint8_t button, int x, int y, void *arg)\n{\n\tstruct ps2mouse_softc *sc = arg;\n\n\tpthread_mutex_lock(&sc->mtx);\n\tmovement_update(sc, x, y);\n\n\tsc->status &= ~(PS2M_STS_LEFT_BUTTON |\n\t    PS2M_STS_RIGHT_BUTTON | PS2M_STS_MID_BUTTON);\n\tif (button & (1 << 0))\n\t\tsc->status |= PS2M_STS_LEFT_BUTTON;\n\tif (button & (1 << 1))\n\t\tsc->status |= PS2M_STS_MID_BUTTON;\n\tif (button & (1 << 2))\n\t\tsc->status |= PS2M_STS_RIGHT_BUTTON;\n\n\tif ((sc->status & PS2M_STS_ENABLE_DEV) == 0 || !sc->ctrlenable) {\n\t\t/* no data reporting */\n\t\tpthread_mutex_unlock(&sc->mtx);\n\t\treturn;\n\t}\n\n\tmovement_get(sc);\n\tpthread_mutex_unlock(&sc->mtx);\n\n\tif (sc->fifo.num > 0)\n\t\tatkbdc_event(sc->atkbdc_sc, 0);\n}\n\nstruct ps2mouse_softc *\nps2mouse_init(struct atkbdc_softc *atkbdc_sc)\n{\n\tstruct ps2mouse_softc *sc;\n\n\tsc = calloc(1, sizeof (struct ps2mouse_softc));\n\tpthread_mutex_init(&sc->mtx, NULL);\n\tfifo_init(sc);\n\tsc->atkbdc_sc = atkbdc_sc;\n\n\tpthread_mutex_lock(&sc->mtx);\n\tps2mouse_reset(sc);\n\tpthread_mutex_unlock(&sc->mtx);\n\n\tconsole_ptr_register(ps2mouse_event, sc, 1);\n\n\treturn (sc);\n}\n\n\n"
  },
  {
    "path": "src/rfb.c",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 Leon Dang\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/param.h>\n#include <sys/socket.h>\n#include <sys/select.h>\n#include <sys/time.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n\n#include <assert.h>\n#include <err.h>\n#include <errno.h>\n#include <pthread.h>\n#include <signal.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n#include <sysexits.h>\n#include <unistd.h>\n\n#include <zlib.h>\n\n#include <CommonCrypto/CommonCrypto.h>\n\n#include <xhyve/support/misc.h>\n\n#include <xhyve/support/specialreg.h>\n\n#include <xhyve/bhyvegc.h>\n#include <xhyve/console.h>\n#include <xhyve/rfb.h>\n#include <xhyve/sockstream.h>\n\nstatic int rfb_debug = 0;\n#define\tDPRINTF(params) if (rfb_debug) printf params\n#define\tWPRINTF(params) printf params\n\n#define AUTH_LENGTH\t16\n#define PASSWD_LENGTH\t8\n\n#define SECURITY_TYPE_NONE 1\n#define SECURITY_TYPE_VNC_AUTH 2\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct rfb_softc {\n\tint\t\tsfd;\n\tpthread_t\ttid;\n\n\tint\t\tcfd;\n\n\tint\t\twidth, height;\n\n\tchar\t\t*password;\n\n\tbool\tenc_raw_ok;\n\tbool\tenc_zlib_ok;\n\tbool\tenc_resize_ok;\n\n\tz_stream\tzstream;\n\tuint8_t\t\t*zbuf;\n\tint\t\tzbuflen;\n\n\tint\t\tconn_wait;\n\tint\t\tsending;\n\tpthread_mutex_t mtx;\n\tpthread_cond_t  cond;\n\n\tint\t\thw_crc;\n\tuint32_t\t*crc;\t\t/* WxH crc cells */\n\tuint32_t\t*crc_tmp;\t/* buffer to store single crc row */\n\tuint16_t\t\tcrc_width, crc_height;\n};\n\n#pragma clang diagnostic pop\n\nstruct rfb_pixfmt {\n\tuint8_t\t\tbpp;\n\tuint8_t\t\tdepth;\n\tuint8_t\t\tbigendian;\n\tuint8_t\t\ttruecolor;\n\tuint16_t\tred_max;\n\tuint16_t\tgreen_max;\n\tuint16_t\tblue_max;\n\tuint8_t\t\tred_shift;\n\tuint8_t\t\tgreen_shift;\n\tuint8_t\t\tblue_shift;\n\tuint8_t\t\tpad[3];\n};\n\nstruct rfb_srvr_info {\n\tuint16_t\t\twidth;\n\tuint16_t\t\theight;\n\tstruct rfb_pixfmt\tpixfmt;\n\tuint32_t\t\tnamelen;\n};\n\nstruct rfb_pixfmt_msg {\n\tuint8_t\t\t\ttype;\n\tuint8_t\t\t\tpad[3];\n\tstruct rfb_pixfmt\tpixfmt;\n};\n\n#define\tRFB_ENCODING_RAW\t\t((uint32_t)0)\n#define\tRFB_ENCODING_ZLIB\t\t((uint32_t)6)\n#define\tRFB_ENCODING_RESIZE\t\t((uint32_t)-223)\n\n#define RFB_MAX_WIDTH\t\t\t2000\n#define RFB_MAX_HEIGHT\t\t\t1200\n#define\tRFB_ZLIB_BUFSZ\t\t\tRFB_MAX_WIDTH*RFB_MAX_HEIGHT*4\n\n/* percentage changes to screen before sending the entire screen */\n#define RFB_SEND_ALL_THRESH             25\n\nstruct rfb_enc_msg {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tpad;\n\tuint16_t\tnumencs;\n};\n\nstruct rfb_updt_msg {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tincremental;\n\tuint16_t\tx;\n\tuint16_t\ty;\n\tuint16_t\twidth;\n\tuint16_t\theight;\n};\n\nstruct rfb_key_msg {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tdown;\n\tuint16_t\tpad;\n\tuint32_t\tcode;\n};\n\nstruct rfb_ptr_msg {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tbutton;\n\tuint16_t\tx;\n\tuint16_t\ty;\n};\n\nstruct rfb_srvr_updt_msg {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tpad;\n\tuint16_t\tnumrects;\n};\n\nstruct rfb_srvr_rect_hdr {\n\tuint16_t\tx;\n\tuint16_t\ty;\n\tuint16_t\twidth;\n\tuint16_t\theight;\n\tuint32_t\tencoding;\n};\n\nstruct rfb_cuttext_msg {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tpadding[3];\n\tuint32_t\tlength;\n};\n\n\nstatic void\nrfb_send_server_init_msg(int cfd)\n{\n\tstruct bhyvegc_image *gc_image;\n\tstruct rfb_srvr_info sinfo;\n\n\tgc_image = console_get_image();\n\n\tsinfo.width = htons(gc_image->width);\n\tsinfo.height = htons(gc_image->height);\n\tsinfo.pixfmt.bpp = 32;\n\tsinfo.pixfmt.depth = 32;\n\tsinfo.pixfmt.bigendian = 0;\n\tsinfo.pixfmt.truecolor = 1;\n\tsinfo.pixfmt.red_max = htons(255);\n\tsinfo.pixfmt.green_max = htons(255);\n\tsinfo.pixfmt.blue_max = htons(255);\n\tsinfo.pixfmt.red_shift = 16;\n\tsinfo.pixfmt.green_shift = 8;\n\tsinfo.pixfmt.blue_shift = 0;\n\tsinfo.namelen = htonl(strlen(\"bhyve\"));\n\t(void)stream_write(cfd, &sinfo, sizeof(sinfo));\n\t(void)stream_write(cfd, \"bhyve\", strlen(\"bhyve\"));\n}\n\nstatic void\nrfb_send_resize_update_msg(struct rfb_softc *rc, int cfd)\n{\n\tstruct rfb_srvr_updt_msg supdt_msg;\n\tstruct rfb_srvr_rect_hdr srect_hdr;\n\n\t/* Number of rectangles: 1 */\n\tsupdt_msg.type = 0;\n\tsupdt_msg.pad = 0;\n\tsupdt_msg.numrects = htons(1);\n\tstream_write(cfd, &supdt_msg, sizeof(struct rfb_srvr_updt_msg));\n\n\t/* Rectangle header */\n\tsrect_hdr.x = htons(0);\n\tsrect_hdr.y = htons(0);\n\tsrect_hdr.width = htons(rc->width);\n\tsrect_hdr.height = htons(rc->height);\n\tsrect_hdr.encoding = htonl(RFB_ENCODING_RESIZE);\n\tstream_write(cfd, &srect_hdr, sizeof(struct rfb_srvr_rect_hdr));\n}\n\nstatic void\nrfb_recv_set_pixfmt_msg(UNUSED struct rfb_softc *rc, int cfd)\n{\n\tstruct rfb_pixfmt_msg pixfmt_msg;\n\n\t(void)stream_read(cfd, ((uint8_t *)&pixfmt_msg)+1, sizeof(pixfmt_msg)-1);\n}\n\n\nstatic void\nrfb_recv_set_encodings_msg(struct rfb_softc *rc, int cfd)\n{\n\tstruct rfb_enc_msg enc_msg;\n\tint i;\n\tuint32_t encoding;\n\n\tassert((sizeof(enc_msg) - 1) == 3);\n\t(void)stream_read(cfd, ((uint8_t *)&enc_msg)+1, sizeof(enc_msg)-1);\n\n\tfor (i = 0; i < htons(enc_msg.numencs); i++) {\n\t\t(void)stream_read(cfd, &encoding, sizeof(encoding));\n\t\tswitch (htonl(encoding)) {\n\t\tcase RFB_ENCODING_RAW:\n\t\t\trc->enc_raw_ok = true;\n\t\t\tbreak;\n\t\tcase RFB_ENCODING_ZLIB:\n\t\t\trc->enc_zlib_ok = true;\n\t\t\tdeflateInit(&rc->zstream, Z_BEST_SPEED);\n\t\t\tbreak;\n\t\tcase RFB_ENCODING_RESIZE:\n\t\t\trc->enc_resize_ok = true;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n * Calculate CRC32 using SSE4.2; Intel or AMD Bulldozer+ CPUs only\n */\nstatic __inline uint32_t\nfast_crc32(void *buf, size_t len, uint32_t crcval)\n{\n\tuint32_t q = (uint32_t)len / sizeof(uint32_t);\n\tuint32_t *p = (uint32_t *)buf;\n\n\twhile (q--) {\n\t\t__asm__ __volatile__ (\n\t\t\t\".byte 0xf2, 0xf, 0x38, 0xf1, 0xf1;\"\n\t\t\t:\"=S\" (crcval)\n\t\t\t:\"0\" (crcval), \"c\" (*p)\n\t\t);\n\t\tp++;\n\t}\n\n\treturn (crcval);\n}\n\nstatic long\nrfb_send_rect(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc,\n              unsigned int x, unsigned int y, unsigned int w, unsigned int h)\n{\n\tstruct rfb_srvr_updt_msg supdt_msg;\n        struct rfb_srvr_rect_hdr srect_hdr;\n\tunsigned long zlen;\n\tssize_t nwrite, total;\n\tint err;\n\tuint32_t *p;\n\tuint8_t *zbufp;\n\n\t/*\n\t * Send a single rectangle of the given x, y, w h dimensions.\n\t */\n\n\t/* Number of rectangles: 1 */\n\tsupdt_msg.type = 0;\n\tsupdt_msg.pad = 0;\n\tsupdt_msg.numrects = htons(1);\n\tnwrite = stream_write(cfd, &supdt_msg,\n\t                      sizeof(struct rfb_srvr_updt_msg));\n\tif (nwrite <= 0)\n\t\treturn (nwrite);\n\n\n\t/* Rectangle header */\n\tsrect_hdr.x = htons(x);\n\tsrect_hdr.y = htons(y);\n\tsrect_hdr.width = htons(w);\n\tsrect_hdr.height = htons(h);\n\n\th = y + h;\n\tw *= sizeof(uint32_t);\n\tif (rc->enc_zlib_ok) {\n\t\tzbufp = rc->zbuf;\n\t\trc->zstream.total_in = 0;\n\t\trc->zstream.total_out = 0;\n\t\tfor (p = &gc->data[y * gc->width + x]; y < h; y++) {\n\t\t\trc->zstream.next_in = (Bytef *)p;\n\t\t\trc->zstream.avail_in = (uInt)w;\n\t\t\trc->zstream.next_out = (Bytef *)zbufp;\n\t\t\trc->zstream.avail_out = (uInt)(RFB_ZLIB_BUFSZ + 16 -\n\t\t\t                        rc->zstream.total_out);\n\t\t\trc->zstream.data_type = Z_BINARY;\n\n\t\t\t/* Compress with zlib */\n\t\t\terr = deflate(&rc->zstream, Z_SYNC_FLUSH);\n\t\t\tif (err != Z_OK) {\n\t\t\t\tWPRINTF((\"zlib[rect] deflate err: %d\\n\", err));\n\t\t\t\trc->enc_zlib_ok = false;\n\t\t\t\tdeflateEnd(&rc->zstream);\n\t\t\t\tgoto doraw;\n\t\t\t}\n\t\t\tzbufp = rc->zbuf + rc->zstream.total_out;\n\t\t\tp += gc->width;\n\t\t}\n\t\tsrect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);\n\t\tnwrite = stream_write(cfd, &srect_hdr,\n\t\t                      sizeof(struct rfb_srvr_rect_hdr));\n\t\tif (nwrite <= 0)\n\t\t\treturn (nwrite);\n\n\t\tzlen = htonl(rc->zstream.total_out);\n\t\tnwrite = stream_write(cfd, &zlen, sizeof(uint32_t));\n\t\tif (nwrite <= 0)\n\t\t\treturn (nwrite);\n\t\treturn (stream_write(cfd, rc->zbuf, (ssize_t)rc->zstream.total_out));\n\t}\n\ndoraw:\n\n\ttotal = 0;\n\tzbufp = rc->zbuf;\n\tfor (p = &gc->data[y * gc->width + x]; y < h; y++) {\n\t\tmemcpy(zbufp, p, w);\n\t\tzbufp += w;\n\t\ttotal += w;\n\t\tp += gc->width;\n\t}\n\n\tsrect_hdr.encoding = htonl(RFB_ENCODING_RAW);\n\tnwrite = stream_write(cfd, &srect_hdr,\n\t                      sizeof(struct rfb_srvr_rect_hdr));\n\tif (nwrite <= 0)\n\t\treturn (nwrite);\n\n\ttotal = stream_write(cfd, rc->zbuf, total);\n\n\treturn (total);\n}\n\nstatic long\nrfb_send_all(struct rfb_softc *rc, int cfd, struct bhyvegc_image *gc)\n{\n\tstruct rfb_srvr_updt_msg supdt_msg;\n        struct rfb_srvr_rect_hdr srect_hdr;\n\tssize_t nwrite;\n\tunsigned long zlen;\n\tint err;\n\n\t/*\n\t * Send the whole thing\n\t */\n\n\t/* Number of rectangles: 1 */\n\tsupdt_msg.type = 0;\n\tsupdt_msg.pad = 0;\n\tsupdt_msg.numrects = htons(1);\n\tnwrite = stream_write(cfd, &supdt_msg,\n\t                      sizeof(struct rfb_srvr_updt_msg));\n\tif (nwrite <= 0)\n\t\treturn (nwrite);\n\n\t/* Rectangle header */\n\tsrect_hdr.x = 0;\n\tsrect_hdr.y = 0;\n\tsrect_hdr.width = htons(gc->width);\n\tsrect_hdr.height = htons(gc->height);\n\tif (rc->enc_zlib_ok) {\n\t\trc->zstream.next_in = (Bytef *)gc->data;\n\t\trc->zstream.avail_in = gc->width * gc->height *\n\t\t                   sizeof(uint32_t);\n\t\trc->zstream.next_out = (Bytef *)rc->zbuf;\n\t\trc->zstream.avail_out = RFB_ZLIB_BUFSZ + 16;\n\t\trc->zstream.data_type = Z_BINARY;\n\n\t\trc->zstream.total_in = 0;\n\t\trc->zstream.total_out = 0;\n\n\t\t/* Compress with zlib */\n\t\terr = deflate(&rc->zstream, Z_SYNC_FLUSH);\n\t\tif (err != Z_OK) {\n\t\t\tWPRINTF((\"zlib deflate err: %d\\n\", err));\n\t\t\trc->enc_zlib_ok = false;\n\t\t\tdeflateEnd(&rc->zstream);\n\t\t\tgoto doraw;\n\t\t}\n\n\t\tsrect_hdr.encoding = htonl(RFB_ENCODING_ZLIB);\n\t\tnwrite = stream_write(cfd, &srect_hdr,\n\t\t                      sizeof(struct rfb_srvr_rect_hdr));\n\t\tif (nwrite <= 0)\n\t\t\treturn (nwrite);\n\n\t\tzlen = htonl(rc->zstream.total_out);\n\t\tnwrite = stream_write(cfd, &zlen, sizeof(uint32_t));\n\t\tif (nwrite <= 0)\n\t\t\treturn (nwrite);\n\t\treturn (stream_write(cfd, rc->zbuf, (ssize_t)rc->zstream.total_out));\n\t}\n\ndoraw:\n\tsrect_hdr.encoding = htonl(RFB_ENCODING_RAW);\n\tnwrite = stream_write(cfd, &srect_hdr,\n\t                      sizeof(struct rfb_srvr_rect_hdr));\n\tif (nwrite <= 0)\n\t\treturn (nwrite);\n\n\tnwrite = stream_write(cfd, gc->data,\n\t               gc->width * gc->height * sizeof(uint32_t));\n\n\treturn (nwrite);\n}\n\n#define PIX_PER_CELL\t32\n#define\tPIXCELL_SHIFT\t5\n#define PIXCELL_MASK\t0x1F\n\nstatic long\nrfb_send_screen(struct rfb_softc *rc, int cfd, int all)\n{\n\tstruct bhyvegc_image *gc_image;\n\tssize_t nwrite;\n\tunsigned int x, y;\n\tunsigned int celly, cellwidth;\n\tunsigned int xcells, ycells;\n\tunsigned int w, h;\n\tuint32_t *p;\n\tunsigned int rem_x, rem_y;   /* remainder for resolutions not x32 pixels ratio */\n\tlong retval;\n\tuint32_t *crc_p, *orig_crc;\n\tunsigned int changes;\n\n\tconsole_refresh();\n\tgc_image = console_get_image();\n\n\tpthread_mutex_lock(&rc->mtx);\n\tif (rc->sending) {\n\t\tpthread_mutex_unlock(&rc->mtx);\n\t\treturn (1);\n\t}\n\trc->sending = 1;\n\tpthread_mutex_unlock(&rc->mtx);\n\n\tretval = 0;\n\n\tif (all) {\n\t\tretval = rfb_send_all(rc, cfd, gc_image);\n\t\tgoto done;\n\t}\n\n\t/*\n\t * Calculate the checksum for each 32x32 cell. Send each that\n\t * has changed since the last scan.\n\t */\n\n\t/* Resolution changed */\n\n\trc->crc_width = gc_image->width;\n\trc->crc_height = gc_image->height;\n\n\tw = rc->crc_width;\n\th = rc->crc_height;\n\txcells = (unsigned int)howmany(rc->crc_width, PIX_PER_CELL);\n\tycells = (unsigned int)howmany(rc->crc_height, PIX_PER_CELL);\n\n\trem_x = w & PIXCELL_MASK;\n\n\trem_y = h & PIXCELL_MASK;\n\tif (!rem_y)\n\t\trem_y = PIX_PER_CELL;\n\n\tp = gc_image->data;\n\n\t/*\n\t * Go through all cells and calculate crc. If significant number\n\t * of changes, then send entire screen.\n\t * crc_tmp is dual purpose: to store the new crc and to flag as\n\t * a cell that has changed.\n\t */\n\tcrc_p = rc->crc_tmp - xcells;\n\torig_crc = rc->crc - xcells;\n\tchanges = 0;\n\tmemset(rc->crc_tmp, 0, sizeof(uint32_t) * xcells * ycells);\n\tfor (y = 0; y < h; y++) {\n\t\tif ((y & PIXCELL_MASK) == 0) {\n\t\t\tcrc_p += xcells;\n\t\t\torig_crc += xcells;\n\t\t}\n\n\t\tfor (x = 0; x < xcells; x++) {\n\t\t\tif (rc->hw_crc)\n\t\t\t\tcrc_p[x] = fast_crc32(p,\n\t\t\t\t             PIX_PER_CELL * sizeof(uint32_t),\n\t\t\t\t             crc_p[x]);\n\t\t\telse\n\t\t\t\tcrc_p[x] = (uint32_t)crc32(crc_p[x],\n\t\t\t\t             (Bytef *)p,\n\t\t\t\t             PIX_PER_CELL * sizeof(uint32_t));\n\n\t\t\tp += PIX_PER_CELL;\n\n\t\t\t/* check for crc delta if last row in cell */\n\t\t\tif ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {\n\t\t\t\tif (orig_crc[x] != crc_p[x]) {\n\t\t\t\t\torig_crc[x] = crc_p[x];\n\t\t\t\t\tcrc_p[x] = 1;\n\t\t\t\t\tchanges++;\n\t\t\t\t} else {\n\t\t\t\t\tcrc_p[x] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (rem_x) {\n\t\t\tif (rc->hw_crc)\n\t\t\t\tcrc_p[x] = fast_crc32(p,\n\t\t\t\t                    (size_t)rem_x * sizeof(uint32_t),\n\t\t\t\t                    crc_p[x]);\n\t\t\telse\n\t\t\t\tcrc_p[x] = (uint32_t)crc32(crc_p[x],\n\t\t\t\t                    (Bytef *)p,\n\t\t\t\t                    rem_x * sizeof(uint32_t));\n\t\t\tp += rem_x;\n\n\t\t\tif ((y & PIXCELL_MASK) == PIXCELL_MASK || y == (h-1)) {\n\t\t\t\tif (orig_crc[x] != crc_p[x]) {\n\t\t\t\t\torig_crc[x] = crc_p[x];\n\t\t\t\t\tcrc_p[x] = 1;\n\t\t\t\t\tchanges++;\n\t\t\t\t} else {\n\t\t\t\t\tcrc_p[x] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/* If number of changes is > THRESH percent, send the whole screen */\n\tif (((changes * 100) / (xcells * ycells)) >= RFB_SEND_ALL_THRESH) {\n\t\tretval = rfb_send_all(rc, cfd, gc_image);\n\t\tgoto done;\n\t}\n\n\t/* Go through all cells, and send only changed ones */\n\tcrc_p = rc->crc_tmp;\n\tfor (y = 0; y < h; y += PIX_PER_CELL) {\n\t\t/* previous cell's row */\n\t\tcelly = (y >> PIXCELL_SHIFT);\n\n\t\t/* Delta check crc to previous set */\n\t\tfor (x = 0; x < xcells; x++) {\n\t\t\tif (*crc_p++ == 0)\n\t\t\t\tcontinue;\n\n\t\t\tif (x == (xcells - 1) && rem_x > 0)\n\t\t\t\tcellwidth = rem_x;\n\t\t\telse\n\t\t\t\tcellwidth = PIX_PER_CELL;\n\t\t\tnwrite = rfb_send_rect(rc, cfd,\n\t\t\t\tgc_image,\n\t\t\t\tx * PIX_PER_CELL,\n\t\t\t\tcelly * PIX_PER_CELL,\n\t\t\t        cellwidth,\n\t\t\t\ty + PIX_PER_CELL >= h ? rem_y : PIX_PER_CELL);\n\t\t\tif (nwrite <= 0) {\n\t\t\t\tretval = nwrite;\n\t\t\t\tgoto done;\n\t\t\t}\n\t\t}\n\t}\n\tretval = 1;\n\ndone:\n\tpthread_mutex_lock(&rc->mtx);\n\trc->sending = 0;\n\tpthread_mutex_unlock(&rc->mtx);\n\n\treturn (retval);\n}\n\n\nstatic void\nrfb_recv_update_msg(struct rfb_softc *rc, int cfd, int discardonly)\n{\n\tstruct rfb_updt_msg updt_msg;\n\tstruct bhyvegc_image *gc_image;\n\n\t(void)stream_read(cfd, ((uint8_t *)&updt_msg) + 1 , sizeof(updt_msg) - 1);\n\n\tconsole_refresh();\n\tgc_image = console_get_image();\n\n\tupdt_msg.x = htons(updt_msg.x);\n\tupdt_msg.y = htons(updt_msg.y);\n\tupdt_msg.width = htons(updt_msg.width);\n\tupdt_msg.height = htons(updt_msg.height);\n\n\tif (updt_msg.width != gc_image->width ||\n\t    updt_msg.height != gc_image->height) {\n\t\trc->width = gc_image->width;\n\t\trc->height = gc_image->height;\n\t\tif (rc->enc_resize_ok)\n\t\t\trfb_send_resize_update_msg(rc, cfd);\n\t}\n\n\tif (discardonly)\n\t\treturn;\n\n\trfb_send_screen(rc, cfd, 1);\n}\n\nstatic void\nrfb_recv_key_msg(UNUSED struct rfb_softc *rc, int cfd)\n{\n\tstruct rfb_key_msg key_msg;\n\n\t(void)stream_read(cfd, ((uint8_t *)&key_msg) + 1, sizeof(key_msg) - 1);\n\n\tconsole_key_event(key_msg.down, htonl(key_msg.code));\n}\n\nstatic void\nrfb_recv_ptr_msg(UNUSED struct rfb_softc *rc, int cfd)\n{\n\tstruct rfb_ptr_msg ptr_msg;\n\n\t(void)stream_read(cfd, ((uint8_t *)&ptr_msg) + 1, sizeof(ptr_msg) - 1);\n\n\tconsole_ptr_event(ptr_msg.button, htons(ptr_msg.x), htons(ptr_msg.y));\n}\n\nstatic void\nrfb_recv_cuttext_msg(UNUSED struct rfb_softc *rc, int cfd)\n{\n\tstruct rfb_cuttext_msg ct_msg;\n\tunsigned char buf[32];\n\tlong len;\n\n\tlen = stream_read(cfd, ((uint8_t *)&ct_msg) + 1, sizeof(ct_msg) - 1);\n\tct_msg.length = htonl(ct_msg.length);\n\twhile (ct_msg.length > 0) {\n\t\tlen = stream_read(cfd, buf, ct_msg.length > sizeof(buf) ?\n\t\t\tsizeof(buf) : ct_msg.length);\n\t\tct_msg.length -= len;\n\t}\n}\n\nstatic int64_t\ntimeval_delta(struct timeval *prev, struct timeval *now)\n{\n\tint64_t n1, n2;\n\tn1 = now->tv_sec * 1000000 + now->tv_usec;\n\tn2 = prev->tv_sec * 1000000 + prev->tv_usec;\n\treturn (n1 - n2);\n}\n\nstatic void *\nrfb_wr_thr(void *arg)\n{\n\tstruct rfb_softc *rc;\n\tfd_set rfds;\n\tstruct timeval tv;\n\tstruct timeval prev_tv;\n\tint64_t tdiff;\n\tint cfd;\n\tint err;\n\n    pthread_setname_np(\"rfbout\");\n\n\trc = arg;\n\tcfd = rc->cfd;\n\n\tprev_tv.tv_sec = 0;\n\tprev_tv.tv_usec = 0;\n\twhile (rc->cfd >= 0) {\n\t\tFD_ZERO(&rfds);\n\t\tFD_SET(cfd, &rfds);\n\t\ttv.tv_sec = 0;\n\t\ttv.tv_usec = 10000;\n\n\t\terr = select(cfd+1, &rfds, NULL, NULL, &tv);\n                if (err < 0)\n\t\t\treturn (NULL);\n\n\t\t/* Determine if its time to push screen; ~24hz */\n\t\tgettimeofday(&tv, NULL);\n\t\ttdiff = timeval_delta(&prev_tv, &tv);\n\t\tif (tdiff > 40000) {\n\t\t\tprev_tv.tv_sec = tv.tv_sec;\n\t\t\tprev_tv.tv_usec = tv.tv_usec;\n\t\t\tif (rfb_send_screen(rc, cfd, 0) <= 0) {\n\t\t\t\treturn (NULL);\n\t\t\t}\n\t\t} else {\n\t\t\t/* sleep */\n\t\t\tusleep((useconds_t)(40000 - tdiff));\n\t\t}\n\t}\n\n\treturn (NULL);\n}\n\nstatic void\nbe32enc(void *pp, uint32_t x)\n{\n    uint8_t *p = (uint8_t *)pp;\n    p[3] = x & 0xff;\n    p[2] = (x >> 8) & 0xff;\n    p[1] = (x >> 16) & 0xff;\n    p[0] = (x >> 24) & 0xff;\n}\n\nstatic void\nrfb_handle(struct rfb_softc *rc, int cfd)\n{\n\tconst char *vbuf = \"RFB 003.008\\n\";\n\tunsigned char buf[80];\n\tchar *message = NULL;\n\n\tunsigned char challenge[AUTH_LENGTH];\n\tunsigned char keystr[PASSWD_LENGTH];\n\tunsigned char crypt_expected[AUTH_LENGTH];\n\n    size_t dataOutSize;\n    int i;\n    CCCryptorStatus cryptoResult;\n\n\tpthread_t tid = NULL;\n\tuint32_t sres = 0;\n\tlong len;\n\tint perror = 1;\n\n\trc->cfd = cfd;\n\n\t/* 1a. Send server version */\n\tstream_write(cfd, vbuf, (ssize_t)strlen(vbuf));\n\n\t/* 1b. Read client version */\n\tlen = read(cfd, buf, sizeof(buf));\n\n\t/* 2a. Send security type */\n\tbuf[0] = 1;\n\tif (rc->password)\n\t\tbuf[1] = SECURITY_TYPE_VNC_AUTH;\n\telse\n\t\tbuf[1] = SECURITY_TYPE_NONE;\n\n\tstream_write(cfd, buf, 2);\n\n\t/* 2b. Read agreed security type */\n\tlen = stream_read(cfd, buf, 1);\n\n\t/* 2c. Do VNC authentication */\n\tswitch (buf[0]) {\n\tcase SECURITY_TYPE_NONE:\n\t\tsres = 0;\n\t\tbreak;\n\tcase SECURITY_TYPE_VNC_AUTH:\n\t\t/*\n\t\t * The client encrypts the challenge with DES, using a password\n\t\t * supplied by the user as the key.\n\t\t * To form the key, the password is truncated to\n\t\t * eight characters, or padded with null bytes on the right.\n\t\t * The client then sends the resulting 16-bytes response.\n\t\t */\n\t\tstrncpy((char *)keystr, rc->password, PASSWD_LENGTH);\n\n\t\t/* VNC clients encrypts the challenge with all the bit fields\n\t\t * in each byte of the password mirrored.\n\t\t * Here we flip each byte of the keystr.\n\t\t */\n\t\tfor (i = 0; i < PASSWD_LENGTH; i++) {\n\t\t\tkeystr[i] = (keystr[i] & 0xF0) >> 4\n\t\t\t\t  | (unsigned char)((keystr[i] & 0x0F) << 4);\n\t\t\tkeystr[i] = (keystr[i] & 0xCC) >> 2\n\t\t\t\t  | (unsigned char)((keystr[i] & 0x33) << 2);\n\t\t\tkeystr[i] = (keystr[i] & 0xAA) >> 1\n\t\t\t\t  | (unsigned char)((keystr[i] & 0x55) << 1);\n\t\t}\n\n\t\t/* Initialize a 16-byte random challenge */\n\t\tarc4random_buf(challenge, sizeof(challenge));\n\t\tstream_write(cfd, challenge, AUTH_LENGTH);\n\n\t\t/* Receive the 16-byte challenge response */\n\t\tstream_read(cfd, buf, AUTH_LENGTH);\n\n\t\tmemcpy(crypt_expected, challenge, AUTH_LENGTH);\n\n        cryptoResult = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode,\n                               keystr, PASSWD_LENGTH,\n                               NULL,\n                               challenge, AUTH_LENGTH,\n                               crypt_expected, AUTH_LENGTH,\n                               &dataOutSize);\n\n        if (cryptoResult != kCCSuccess) {\n            message = \"Auth Failed: Internal Error.\";\n            sres = htonl(1);\n        } else if (memcmp(crypt_expected, buf, AUTH_LENGTH) != 0) {\n\t\t\tmessage = \"Auth Failed: Invalid Password.\";\n\t\t\tsres = htonl(1);\n        } else {\n\t\t\tsres = 0;\n        }\n        break;\n\t}\n\n\t/* 2d. Write back a status */\n\tstream_write(cfd, &sres, 4);\n\n\tif (sres) {\n\t\tbe32enc(buf, (uint32_t)strlen(message));\n\t\tstream_write(cfd, buf, 4);\n\t\tstream_write(cfd, message, (ssize_t)strlen(message));\n\t\tgoto done;\n\t}\n\n\t/* 3a. Read client shared-flag byte */\n\tlen = stream_read(cfd, buf, 1);\n\n\t/* 4a. Write server-init info */\n\trfb_send_server_init_msg(cfd);\n\n\tif (!rc->zbuf) {\n\t\trc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16);\n\t\tassert(rc->zbuf != NULL);\n\t}\n\n\trfb_send_screen(rc, cfd, 1);\n\n\tperror = pthread_create(&tid, NULL, rfb_wr_thr, rc);\n    if (perror != 0) {\n        goto done;\n    }\n\n        /* Now read in client requests. 1st byte identifies type */\n\tfor (;;) {\n\t\tlen = read(cfd, buf, 1);\n\t\tif (len <= 0) {\n\t\t\tDPRINTF((\"rfb client exiting\\r\\n\"));\n\t\t\tbreak;\n\t\t}\n\n\t\tswitch (buf[0]) {\n\t\tcase 0:\n\t\t\trfb_recv_set_pixfmt_msg(rc, cfd);\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\trfb_recv_set_encodings_msg(rc, cfd);\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\trfb_recv_update_msg(rc, cfd, 1);\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\trfb_recv_key_msg(rc, cfd);\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\trfb_recv_ptr_msg(rc, cfd);\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\trfb_recv_cuttext_msg(rc, cfd);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tWPRINTF((\"rfb unknown cli-code %d!\\n\", buf[0] & 0xff));\n\t\t\tgoto done;\n\t\t}\n\t}\ndone:\n\trc->cfd = -1;\n\tif (perror == 0)\n\t\tpthread_join(tid, NULL);\n\tif (rc->enc_zlib_ok)\n\t\tdeflateEnd(&rc->zstream);\n}\n\nstatic void *\nrfb_thr(void *arg)\n{\n\tstruct rfb_softc *rc;\n\tsigset_t set;\n\n\tint cfd;\n\n    pthread_setname_np(\"rfb\");\n\n\trc = arg;\n\n\tsigemptyset(&set);\n\tsigaddset(&set, SIGPIPE);\n\tif (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {\n\t\tperror(\"pthread_sigmask\");\n\t\treturn (NULL);\n\t}\n\n\tfor (;;) {\n\t\trc->enc_raw_ok = false;\n\t\trc->enc_zlib_ok = false;\n\t\trc->enc_resize_ok = false;\n\n\t\tcfd = accept(rc->sfd, NULL, NULL);\n\t\tif (rc->conn_wait) {\n\t\t\tpthread_mutex_lock(&rc->mtx);\n\t\t\tpthread_cond_signal(&rc->cond);\n\t\t\tpthread_mutex_unlock(&rc->mtx);\n\t\t\trc->conn_wait = 0;\n\t\t}\n\t\trfb_handle(rc, cfd);\n\t\tclose(cfd);\n\t}\n\n\t/* NOTREACHED */\n\treturn (NULL);\n}\n\nstatic int\nsse42_supported(void)\n{\n\tu_int cpu_registers[4], ecx;\n\n\tdo_cpuid(1, cpu_registers);\n\n\tecx = cpu_registers[2];\n\n\treturn ((ecx & CPUID2_SSE42) != 0);\n}\n\nint\nrfb_init(char *hostname, int port, int wait, char *password)\n{\n\tstruct rfb_softc *rc;\n\tstruct sockaddr_in sin;\n\tint on = 1;\n\n\trc = calloc(1, sizeof(struct rfb_softc));\n\n\trc->crc = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),\n\t                 sizeof(uint32_t));\n\trc->crc_tmp = calloc(howmany(RFB_MAX_WIDTH * RFB_MAX_HEIGHT, 32),\n\t                     sizeof(uint32_t));\n\trc->crc_width = RFB_MAX_WIDTH;\n\trc->crc_height = RFB_MAX_HEIGHT;\n\n\trc->password = password;\n\n\trc->sfd = socket(AF_INET, SOCK_STREAM, 0);\n\tif (rc->sfd < 0) {\n\t\tperror(\"socket\");\n\t\treturn (-1);\n\t}\n\n\tsetsockopt(rc->sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));\n\n\tsin.sin_len = sizeof(sin);\n\tsin.sin_family = AF_INET;\n\tsin.sin_port = port ? htons(port) : htons(5900);\n\tif (hostname && strlen(hostname) > 0)\n\t\tinet_pton(AF_INET, hostname, &(sin.sin_addr));\n\telse\n\t\tsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);\n\n\tif (bind(rc->sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {\n\t\tperror(\"bind\");\n\t\treturn (-1);\n\t}\n\n\tif (listen(rc->sfd, 1) < 0) {\n\t\tperror(\"listen\");\n\t\treturn (-1);\n\t}\n\n\trc->hw_crc = sse42_supported();\n\n\trc->conn_wait = wait;\n\tif (wait) {\n\t\tpthread_mutex_init(&rc->mtx, NULL);\n\t\tpthread_cond_init(&rc->cond, NULL);\n\t}\n\n\tpthread_create(&rc->tid, NULL, rfb_thr, rc);\n\n\tif (wait) {\n\t\tDPRINTF((\"Waiting for rfb client...\\n\"));\n\t\tpthread_mutex_lock(&rc->mtx);\n\t\tpthread_cond_wait(&rc->cond, &rc->mtx);\n\t\tpthread_mutex_unlock(&rc->mtx);\n\t}\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/rtc.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <time.h>\n#include <assert.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/acpi.h>\n#include <xhyve/pci_lpc.h>\n#include <xhyve/rtc.h>\n\n#define\tIO_RTC 0x70\n\n#define\tRTC_LMEM_LSB 0x34\n#define\tRTC_LMEM_MSB 0x35\n#define\tRTC_HMEM_LSB 0x5b\n#define\tRTC_HMEM_SB 0x5c\n#define\tRTC_HMEM_MSB 0x5d\n\n#define m_64KB (64*1024)\n#define\tm_16MB (16*1024*1024)\n\n/*\n * Returns the current RTC time as number of seconds since 00:00:00 Jan 1, 1970\n */\nstatic time_t\nrtc_time(int use_localtime)\n{\n\tstruct tm tm;\n\ttime_t t;\n\n\ttime(&t);\n\tif (use_localtime) {\n\t\tlocaltime_r(&t, &tm);\n\t\tt = timegm(&tm);\n\t}\n\treturn (t);\n}\n\nvoid\nrtc_init(int use_localtime)\n{\t\n\tsize_t himem;\n\tsize_t lomem;\n\tint err;\n\n\t/* XXX init diag/reset code/equipment/checksum ? */\n\n\t/*\n\t * Report guest memory size in nvram cells as required by UEFI.\n\t * Little-endian encoding.\n\t * 0x34/0x35 - 64KB chunks above 16MB, below 4GB\n\t * 0x5b/0x5c/0x5d - 64KB chunks above 4GB\n\t */\n\tlomem = (xh_vm_get_lowmem_size() - m_16MB) / m_64KB;\n\terr = xh_vm_rtc_write(RTC_LMEM_LSB, ((uint8_t) lomem));\n\tassert(err == 0);\n\terr = xh_vm_rtc_write(RTC_LMEM_MSB, ((uint8_t) (lomem >> 8)));\n\tassert(err == 0);\n\n\thimem = xh_vm_get_highmem_size() / m_64KB;\n\terr = xh_vm_rtc_write(RTC_HMEM_LSB, ((uint8_t) himem));\n\tassert(err == 0);\n\terr = xh_vm_rtc_write(RTC_HMEM_SB, ((uint8_t) (himem >> 8)));\n\tassert(err == 0);\n\terr = xh_vm_rtc_write(RTC_HMEM_MSB, ((uint8_t) (himem >> 16)));\n\tassert(err == 0);\n\n\terr = xh_vm_rtc_settime(rtc_time(use_localtime));\n\tassert(err == 0);\n}\n\nstatic void\nrtc_dsdt(void)\n{\n\tdsdt_line(\"\");\n\tdsdt_line(\"Device (RTC)\");\n\tdsdt_line(\"{\");\n\tdsdt_line(\"  Name (_HID, EisaId (\\\"PNP0B00\\\"))\");\n\tdsdt_line(\"  Name (_CRS, ResourceTemplate ()\");\n\tdsdt_line(\"  {\");\n\tdsdt_indent(2);\n\tdsdt_fixed_ioport(IO_RTC, 2);\n\tdsdt_fixed_irq(8);\n\tdsdt_unindent(2);\n\tdsdt_line(\"  })\");\n\tdsdt_line(\"}\");\n}\nLPC_DSDT(rtc_dsdt);\n\n/*\n * Reserve the extended RTC I/O ports although they are not emulated at this\n * time.\n */\nSYSRES_IO(0x72, 6);\n"
  },
  {
    "path": "src/smbiostbl.c",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <assert.h>\n#include <errno.h>\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n#include <sys/param.h>\n\n#include <CommonCrypto/CommonDigest.h>\n\n#include <xhyve/support/misc.h>\n#include <xhyve/support/uuid.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/smbiostbl.h>\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpacked\"\n\n#define\tGB (1024ULL*1024*1024)\n\n#define SMBIOS_BASE 0xF1000\n\n/* BHYVE_ACPI_BASE - SMBIOS_BASE) */\n#define\tSMBIOS_MAX_LENGTH (0xF2400 - 0xF1000)\n\n#define\tSMBIOS_TYPE_BIOS 0\n#define\tSMBIOS_TYPE_SYSTEM 1\n#define\tSMBIOS_TYPE_CHASSIS 3\n#define\tSMBIOS_TYPE_PROCESSOR 4\n#define\tSMBIOS_TYPE_MEMARRAY 16\n#define\tSMBIOS_TYPE_MEMDEVICE 17\n#define\tSMBIOS_TYPE_MEMARRAYMAP 19\n#define\tSMBIOS_TYPE_BOOT 32\n#define\tSMBIOS_TYPE_EOT 127\n\nstruct smbios_structure {\n\tuint8_t\t\ttype;\n\tuint8_t\t\tlength;\n\tuint16_t\thandle;\n} __packed;\n\ntypedef int (*initializer_func_t)(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstruct smbios_template_entry {\n\tstruct smbios_structure\t*entry;\n\tconst char\t\t**strings;\n\tinitializer_func_t\tinitializer;\n};\n\n/*\n * SMBIOS Structure Table Entry Point\n */\n#define\tSMBIOS_ENTRY_EANCHOR\t\"_SM_\"\n#define\tSMBIOS_ENTRY_EANCHORLEN\t4\n#define\tSMBIOS_ENTRY_IANCHOR\t\"_DMI_\"\n#define\tSMBIOS_ENTRY_IANCHORLEN\t5\n\nstruct smbios_entry_point {\n\tchar\t\teanchor[4];\t/* anchor tag */\n\tuint8_t\t\techecksum;\t/* checksum of entry point structure */\n\tuint8_t\t\teplen;\t\t/* length in bytes of entry point */\n\tuint8_t\t\tmajor;\t\t/* major version of the SMBIOS spec */\n\tuint8_t\t\tminor;\t\t/* minor version of the SMBIOS spec */\n\tuint16_t\tmaxssize;\t/* maximum size in bytes of a struct */\n\tuint8_t\t\trevision;\t/* entry point structure revision */\n\tuint8_t\t\tformat[5];\t/* entry point rev-specific data */\n\tchar\t\tianchor[5];\t/* intermediate anchor tag */\n\tuint8_t\t\tichecksum;\t/* intermediate checksum */\n\tuint16_t\tstlen;\t\t/* len in bytes of structure table */\n\tuint32_t\tstaddr;\t\t/* physical addr of structure table */\n\tuint16_t\tstnum;\t\t/* number of structure table entries */\n\tuint8_t\t\tbcdrev;\t\t/* BCD value representing DMI ver */\n} __packed;\n\n/*\n * BIOS Information\n */\n#define\tSMBIOS_FL_ISA\t\t0x00000010\t/* ISA is supported */\n#define\tSMBIOS_FL_PCI\t\t0x00000080\t/* PCI is supported */\n#define\tSMBIOS_FL_SHADOW\t0x00001000\t/* BIOS shadowing is allowed */\n#define\tSMBIOS_FL_CDBOOT\t0x00008000\t/* Boot from CD is supported */\n// #define\tSMBIOS_FL_SELBOOT\t0x00010000\t/* Selectable Boot supported */\n#define\tSMBIOS_FL_EDD\t\t0x00080000\t/* EDD Spec is supported */\n\n#define\tSMBIOS_XB1_FL_ACPI\t0x00000001\t/* ACPI is supported */\n\n#define\tSMBIOS_XB2_FL_BBS\t0x00000001\t/* BIOS Boot Specification */\n#define\tSMBIOS_XB2_FL_VM\t0x00000010\t/* Virtual Machine */\n\nstruct smbios_table_type0 {\n\tstruct smbios_structure\theader;\n\tuint8_t\t\t\tvendor;\t\t/* vendor string */\n\tuint8_t\t\t\tversion;\t/* version string */\n\tuint16_t\t\tsegment;\t/* address segment location */\n\tuint8_t\t\t\trel_date;\t/* release date */\n\tuint8_t\t\t\tsize;\t\t/* rom size */\n\tuint64_t\t\tcflags;\t\t/* characteristics */\n\tuint8_t\t\t\txc_bytes[2];\t/* characteristics ext bytes */\n\tuint8_t\t\t\tsb_major_rel;\t/* system bios version */\n\tuint8_t\t\t\tsb_minor_rele;\n\tuint8_t\t\t\tecfw_major_rel;\t/* embedded ctrl fw version */\n\tuint8_t\t\t\tecfw_minor_rel;\n} __packed;\n\n/*\n * System Information\n */\n#define\tSMBIOS_WAKEUP_SWITCH\t0x06\t/* power switch */\n\nstruct smbios_table_type1 {\n\tstruct smbios_structure\theader;\n\tuint8_t\t\t\tmanufacturer;\t/* manufacturer string */\n\tuint8_t\t\t\tproduct;\t/* product name string */\n\tuint8_t\t\t\tversion;\t/* version string */\n\tuint8_t\t\t\tserial;\t\t/* serial number string */\n\tuint8_t\t\t\tuuid[16];\t/* uuid byte array */\n\tuint8_t\t\t\twakeup;\t\t/* wake-up event */\n\tuint8_t\t\t\tsku;\t\t/* sku number string */\n\tuint8_t\t\t\tfamily;\t\t/* family name string */\n} __packed;\n\n/*\n * System Enclosure or Chassis\n */\n#define\tSMBIOS_CHT_UNKNOWN\t0x02\t/* unknown */\n\n#define\tSMBIOS_CHST_SAFE\t0x03\t/* safe */\n\n#define\tSMBIOS_CHSC_NONE\t0x03\t/* none */\n\nstruct smbios_table_type3 {\n\tstruct smbios_structure\theader;\n\tuint8_t\t\t\tmanufacturer;\t/* manufacturer string */\n\tuint8_t\t\t\ttype;\t\t/* type */\n\tuint8_t\t\t\tversion;\t/* version string */\n\tuint8_t\t\t\tserial;\t\t/* serial number string */\n\tuint8_t\t\t\tasset;\t\t/* asset tag string */\n\tuint8_t\t\t\tbustate;\t/* boot-up state */\n\tuint8_t\t\t\tpsstate;\t/* power supply state */\n\tuint8_t\t\t\ttstate;\t\t/* thermal state */\n\tuint8_t\t\t\tsecurity;\t/* security status */\n\tuint8_t\t\t\tuheight;\t/* height in 'u's */\n\tuint8_t\t\t\tcords;\t\t/* number of power cords */\n\tuint8_t\t\t\telems;\t\t/* number of element records */\n\tuint8_t\t\t\telemlen;\t/* length of records */\n\tuint8_t\t\t\tsku;\t\t/* sku number string */\n} __packed;\n\n/*\n * Processor Information\n */\n#define\tSMBIOS_PRT_CENTRAL\t0x03\t/* central processor */\n\n#define\tSMBIOS_PRF_OTHER\t0x01\t/* other */\n\n#define\tSMBIOS_PRS_PRESENT\t0x40\t/* socket is populated */\n#define\tSMBIOS_PRS_ENABLED\t0x1\t/* enabled */\n\n#define\tSMBIOS_PRU_NONE\t\t0x06\t/* none */\n\n#define\tSMBIOS_PFL_64B\t0x04\t/* 64-bit capable */\n\nstruct smbios_table_type4 {\n\tstruct smbios_structure\theader;\n\tuint8_t\t\t\tsocket;\t\t/* socket designation string */\n\tuint8_t\t\t\ttype;\t\t/* processor type */\n\tuint8_t\t\t\tfamily;\t\t/* processor family */\n\tuint8_t\t\t\tmanufacturer;\t/* manufacturer string */\n\tuint64_t\t\tcpuid;\t\t/* processor cpuid */\n\tuint8_t\t\t\tversion;\t/* version string */\n\tuint8_t\t\t\tvoltage;\t/* voltage */\n\tuint16_t\t\tclkspeed;\t/* ext clock speed in mhz */\n\tuint16_t\t\tmaxspeed;\t/* maximum speed in mhz */\n\tuint16_t\t\tcurspeed;\t/* current speed in mhz */\n\tuint8_t\t\t\tstatus;\t\t/* status */\n\tuint8_t\t\t\tupgrade;\t/* upgrade */\n\tuint16_t\t\tl1handle;\t/* l1 cache handle */\n\tuint16_t\t\tl2handle;\t/* l2 cache handle */\n\tuint16_t\t\tl3handle;\t/* l3 cache handle */\n\tuint8_t\t\t\tserial;\t\t/* serial number string */\n\tuint8_t\t\t\tasset;\t\t/* asset tag string */\n\tuint8_t\t\t\tpart;\t\t/* part number string */\n\tuint8_t\t\t\tcores;\t\t/* cores per socket */\n\tuint8_t\t\t\tecores;\t\t/* enabled cores */\n\tuint8_t\t\t\tthreads;\t/* threads per socket */\n\tuint16_t\t\tcflags;\t\t/* processor characteristics */\n\tuint16_t\t\tfamily2;\t/* processor family 2 */\n} __packed;\n\n/*\n * Physical Memory Array\n */\n#define\tSMBIOS_MAL_SYSMB\t0x03\t/* system board or motherboard */\n\n#define\tSMBIOS_MAU_SYSTEM\t0x03\t/* system memory */\n\n#define\tSMBIOS_MAE_NONE\t\t0x03\t/* none */\n\nstruct smbios_table_type16 {\n\tstruct smbios_structure\theader;\n\tuint8_t\t\t\tlocation;\t/* physical device location */\n\tuint8_t\t\t\tuse;\t\t/* device functional purpose */\n\tuint8_t\t\t\tecc;\t\t/* err detect/correct method */\n\tuint32_t\t\tsize;\t\t/* max mem capacity in kb */\n\tuint16_t\t\terrhand;\t/* handle of error (if any) */\n\tuint16_t\t\tndevs;\t\t/* num of slots or sockets */\n\tuint64_t\t\txsize;\t\t/* max mem capacity in bytes */\n} __packed;\n\n/*\n * Memory Device\n */\n#define\tSMBIOS_MDFF_UNKNOWN\t0x02\t/* unknown */\n\n#define\tSMBIOS_MDT_UNKNOWN\t0x02\t/* unknown */\n\n#define\tSMBIOS_MDF_UNKNOWN\t0x0004\t/* unknown */\n\nstruct smbios_table_type17 {\n\tstruct smbios_structure\theader;\n\tuint16_t\t\tarrayhand;\t/* handle of physl mem array */\n\tuint16_t\t\terrhand;\t/* handle of mem error data */\n\tuint16_t\t\ttwidth;\t\t/* total width in bits */\n\tuint16_t\t\tdwidth;\t\t/* data width in bits */\n\tuint16_t\t\tsize;\t\t/* size in kb or mb */\n\tuint8_t\t\t\tform;\t\t/* form factor */\n\tuint8_t\t\t\tset;\t\t/* set */\n\tuint8_t\t\t\tdloc;\t\t/* device locator string */\n\tuint8_t\t\t\tbloc;\t\t/* phys bank locator string */\n\tuint8_t\t\t\ttype;\t\t/* memory type */\n\tuint16_t\t\tflags;\t\t/* memory characteristics */\n\tuint16_t\t\tmaxspeed;\t/* maximum speed in mhz */\n\tuint8_t\t\t\tmanufacturer;\t/* manufacturer string */\n\tuint8_t\t\t\tserial;\t\t/* serial number string */\n\tuint8_t\t\t\tasset;\t\t/* asset tag string */\n\tuint8_t\t\t\tpart;\t\t/* part number string */\n\tuint8_t\t\t\tattributes;\t/* attributes */\n\tuint32_t\t\txsize;\t\t/* extended size in mb */\n\tuint16_t\t\tcurspeed;\t/* current speed in mhz */\n\tuint16_t\t\tminvoltage;\t/* minimum voltage */\n\tuint16_t\t\tmaxvoltage;\t/* maximum voltage */\n\tuint16_t\t\tcurvoltage;\t/* configured voltage */\n} __packed;\n\n/*\n * Memory Array Mapped Address\n */\nstruct smbios_table_type19 {\n\tstruct smbios_structure\theader;\n\tuint32_t\t\tsaddr;\t\t/* start phys addr in kb */\n\tuint32_t\t\teaddr;\t\t/* end phys addr in kb */\n\tuint16_t\t\tarrayhand;\t/* physical mem array handle */\n\tuint8_t\t\t\twidth;\t\t/* num of dev in row */\n\tuint64_t\t\txsaddr;\t\t/* start phys addr in bytes */\n\tuint64_t\t\txeaddr;\t\t/* end phys addr in bytes */\n} __packed;\n\n/*\n * System Boot Information\n */\n#define\tSMBIOS_BOOT_NORMAL\t0\t/* no errors detected */\n\nstruct smbios_table_type32 {\n\tstruct smbios_structure\theader;\n\tuint8_t\t\t\treserved[6];\n\tuint8_t\t\t\tstatus;\t\t/* boot status */\n} __packed;\n\n/*\n * End-of-Table\n */\nstruct smbios_table_type127 {\n\tstruct smbios_structure\theader;\n} __packed;\n\n#pragma clang diagnostic pop\n\nstatic struct smbios_table_type0 smbios_type0_template = {\n\t{ SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 },\n\t1,\t/* bios vendor string */\n\t2,\t/* bios version string */\n\t0xF000,\t/* bios address segment location */\n\t3,\t/* bios release date */\n\t0x0,\t/* bios size (64k * (n + 1) is the size in bytes) */\n\tSMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW |\n\t    SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD,\n\t{ SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM },\n\t0x0,\t/* bios major release */\n\t0x0,\t/* bios minor release */\n\t0xff,\t/* embedded controller firmware major release */\n\t0xff\t/* embedded controller firmware minor release */\n};\n\nstatic const char *smbios_type0_strings[] = {\n\t\"BHYVE\",\t/* vendor string */\n\t\"1.00\",\t\t/* bios version string */\n\t\"03/14/2014\",\t/* bios release date string */\n\tNULL\n};\n\nstatic struct smbios_table_type1 smbios_type1_template = {\n\t{ SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 },\n\t1,\t\t/* manufacturer string */\n\t2,\t\t/* product string */\n\t3,\t\t/* version string */\n\t4,\t\t/* serial number string */\n\t{ 0 },\n\tSMBIOS_WAKEUP_SWITCH,\n\t5,\t\t/* sku string */\n\t6\t\t/* family string */\n};\n\nstatic int smbios_type1_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstatic const char *smbios_type1_strings[] = {\n\t\" \",\t\t/* manufacturer string */\n\t\"BHYVE\",\t/* product name string */\n\t\"1.0\",\t\t/* version string */\n\t\"None\",\t\t/* serial number string */\n\t\"None\",\t\t/* sku string */\n\t\" \",\t\t/* family name string */\n\tNULL\n};\n\nstatic struct smbios_table_type3 smbios_type3_template = {\n\t{ SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 },\n\t1,\t\t/* manufacturer string */\n\tSMBIOS_CHT_UNKNOWN,\n\t2,\t\t/* version string */\n\t3,\t\t/* serial number string */\n\t4,\t\t/* asset tag string */\n\tSMBIOS_CHST_SAFE,\n\tSMBIOS_CHST_SAFE,\n\tSMBIOS_CHST_SAFE,\n\tSMBIOS_CHSC_NONE,\n\t0,\t\t/* height in 'u's (0=enclosure height unspecified) */\n\t0,\t\t/* number of power cords (0=number unspecified) */\n\t0,\t\t/* number of contained element records */\n\t0,\t\t/* length of records */\n\t5\t\t/* sku number string */\n};\n\nstatic const char *smbios_type3_strings[] = {\n\t\" \",\t\t/* manufacturer string */\n\t\"1.0\",\t\t/* version string */\n\t\"None\",\t\t/* serial number string */\n\t\"None\",\t\t/* asset tag string */\n\t\"None\",\t\t/* sku number string */\n\tNULL\n};\n\nstatic struct smbios_table_type4 smbios_type4_template = {\n\t{ SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 },\n\t1,\t\t/* socket designation string */\n\tSMBIOS_PRT_CENTRAL,\n\tSMBIOS_PRF_OTHER,\n\t2, /* manufacturer string */\n\t0, /* cpuid */\n\t3, /* version string */\n\t0, /* voltage */\n\t0, /* external clock frequency in mhz (0=unknown) */\n\t0, /* maximum frequency in mhz (0=unknown) */\n\t0, /* current frequency in mhz (0=unknown) */\n\tSMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED,\n\tSMBIOS_PRU_NONE,\n\t(uint16_t) (-1), /* l1 cache handle */\n\t(uint16_t) (-1), /* l2 cache handle */\n\t(uint16_t) (-1), /* l3 cache handle */\n\t4, /* serial number string */\n\t5, /* asset tag string */\n\t6, /* part number string */\n\t0, /* cores per socket (0=unknown) */\n\t0, /* enabled cores per socket (0=unknown) */\n\t0, /* threads per socket (0=unknown) */\n\tSMBIOS_PFL_64B,\n\tSMBIOS_PRF_OTHER\n};\n\nstatic const char *smbios_type4_strings[] = {\n\t\" \",\t\t/* socket designation string */\n\t\" \",\t\t/* manufacturer string */\n\t\" \",\t\t/* version string */\n\t\"None\",\t\t/* serial number string */\n\t\"None\",\t\t/* asset tag string */\n\t\"None\",\t\t/* part number string */\n\tNULL\n};\n\nstatic int smbios_type4_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstatic struct smbios_table_type16 smbios_type16_template = {\n\t{ SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16),  0 },\n\tSMBIOS_MAL_SYSMB,\n\tSMBIOS_MAU_SYSTEM,\n\tSMBIOS_MAE_NONE,\n\t0x80000000, /* max mem capacity in kb (0x80000000=use extended) */\n\t(uint16_t) (-1), /* handle of error (if any) */\n\t0, /* number of slots or sockets (TBD) */\n\t0 /* extended maximum memory capacity in bytes (TBD) */\n};\n\nstatic int smbios_type16_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstatic struct smbios_table_type17 smbios_type17_template = {\n\t{ SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17),  0 },\n\t(uint16_t) (-1), /* handle of physical memory array */\n\t(uint16_t) (-1), /* handle of memory error data */\n\t64, /* total width in bits including ecc */\n\t64, /* data width in bits */\n\t0, /* size in kb or mb (0x7fff=use extended)*/\n\tSMBIOS_MDFF_UNKNOWN,\n\t0, /* set (0x00=none, 0xff=unknown) */\n\t1, /* device locator string */\n\t2, /* physical bank locator string */\n\tSMBIOS_MDT_UNKNOWN,\n\tSMBIOS_MDF_UNKNOWN,\n\t0, /* maximum memory speed in mhz (0=unknown) */\n\t3, /* manufacturer string */\n\t4, /* serial number string */\n\t5, /* asset tag string */\n\t6, /* part number string */\n\t0, /* attributes (0=unknown rank information) */\n\t0, /* extended size in mb (TBD) */\n\t0, /* current speed in mhz (0=unknown) */\n\t0, /* minimum voltage in mv (0=unknown) */\n\t0, /* maximum voltage in mv (0=unknown) */\n\t0 /* configured voltage in mv (0=unknown) */\n};\n\nstatic const char *smbios_type17_strings[] = {\n\t\" \",\t\t/* device locator string */\n\t\" \",\t\t/* physical bank locator string */\n\t\" \",\t\t/* manufacturer string */\n\t\"None\",\t\t/* serial number string */\n\t\"None\",\t\t/* asset tag string */\n\t\"None\",\t\t/* part number string */\n\tNULL\n};\n\nstatic int smbios_type17_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstatic struct smbios_table_type19 smbios_type19_template = {\n\t{ SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19),  0 },\n\t0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */\n\t0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */\n\t(uint16_t) (-1), /* physical memory array handle */\n\t1, /* number of devices that form a row */\n\t0, /* extended starting phys addr in bytes (TDB) */\n\t0 /* extended ending phys addr in bytes (TDB) */\n};\n\nstatic int smbios_type19_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstatic struct smbios_table_type32 smbios_type32_template = {\n\t{ SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32),  0 },\n\t{ 0, 0, 0, 0, 0, 0 },\n\tSMBIOS_BOOT_NORMAL\n};\n\nstatic struct smbios_table_type127 smbios_type127_template = {\n\t{ SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127),  0 }\n};\n\nstatic int smbios_generic_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size);\n\nstatic struct smbios_template_entry smbios_template[] = {\n\t{ (struct smbios_structure *)&smbios_type0_template,\n\t  smbios_type0_strings,\n\t  smbios_generic_initializer },\n\t{ (struct smbios_structure *)&smbios_type1_template,\n\t  smbios_type1_strings,\n\t  smbios_type1_initializer },\n\t{ (struct smbios_structure *)&smbios_type3_template,\n\t  smbios_type3_strings,\n\t  smbios_generic_initializer },\n\t{ (struct smbios_structure *)&smbios_type4_template,\n\t  smbios_type4_strings,\n\t  smbios_type4_initializer },\n\t{ (struct smbios_structure *)&smbios_type16_template,\n\t  NULL,\n\t  smbios_type16_initializer },\n\t{ (struct smbios_structure *)&smbios_type17_template,\n\t  smbios_type17_strings,\n\t  smbios_type17_initializer },\n\t{ (struct smbios_structure *)&smbios_type19_template,\n\t  NULL,\n\t  smbios_type19_initializer },\n\t{ (struct smbios_structure *)&smbios_type32_template,\n\t  NULL,\n\t  smbios_generic_initializer },\n\t{ (struct smbios_structure *)&smbios_type127_template,\n\t  NULL,\n\t  smbios_generic_initializer },\n\t{ NULL,NULL, NULL }\n};\n\nstatic uint64_t guest_lomem, guest_himem;\nstatic uint16_t type16_handle;\n\nstatic int\nsmbios_generic_initializer(struct smbios_structure *template_entry,\n\tconst char **template_strings, char *curaddr, char **endaddr, uint16_t *n,\n\tUNUSED uint16_t *size)\n{\n\tstruct smbios_structure *entry;\n\n\tmemcpy(curaddr, template_entry, template_entry->length);\n\tentry = (struct smbios_structure *)curaddr;\n\tentry->handle = *n + 1;\n\tcuraddr += entry->length;\n\tif (template_strings != NULL) {\n\t\tint\ti;\n\n\t\tfor (i = 0; template_strings[i] != NULL; i++) {\n\t\t\tconst char *string;\n\t\t\tint len;\n\n\t\t\tstring = template_strings[i];\n\t\t\tlen = (int) (strlen(string) + 1);\n\t\t\tmemcpy(curaddr, string, len);\n\t\t\tcuraddr += len;\n\t\t}\n\t\t*curaddr = '\\0';\n\t\tcuraddr++;\n\t} else {\n\t\t/* Minimum string section is double nul */\n\t\t*curaddr = '\\0';\n\t\tcuraddr++;\n\t\t*curaddr = '\\0';\n\t\tcuraddr++;\n\t}\n\t(*n)++;\n\t*endaddr = curaddr;\n\n\treturn (0);\n}\n\nstatic int\nsmbios_type1_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size)\n{\n\tstruct smbios_table_type1 *type1;\n\n\tsmbios_generic_initializer(template_entry, template_strings,\n\t    curaddr, endaddr, n, size);\n\ttype1 = (struct smbios_table_type1 *)curaddr;\n\n\tif (guest_uuid_str != NULL) {\n\t\tuuid_t\t\tuuid;\n\t\tuint32_t\tstatus;\n\n\t\tuuid_from_string(guest_uuid_str, &uuid, &status);\n\t\tif (status != uuid_s_ok)\n\t\t\treturn (-1);\n\n\t\tuuid_enc_le(&type1->uuid, &uuid);\n\t} else {\n\t\tCC_SHA256_CTX\tmdctx;\n\t\tu_char\t\tdigest[CC_SHA256_DIGEST_LENGTH];\n\t\tchar\t\thostname[MAXHOSTNAMELEN];\n\n\t\t/*\n\t\t * Universally unique and yet reproducible are an\n\t\t * oxymoron, however reproducible is desirable in\n\t\t * this case.\n\t\t */\n\t\tif (gethostname(hostname, sizeof(hostname)))\n\t\t\treturn (-1);\n\n\t\tCC_SHA256_Init(&mdctx);\n\t\tCC_SHA256_Update(&mdctx, vmname, ((unsigned) strlen(vmname)));\n\t\tCC_SHA256_Update(&mdctx, hostname, ((unsigned) sizeof(hostname)));\n\t\tCC_SHA256_Final(digest, &mdctx);\n\n\t\t/*\n\t\t * Set the variant and version number.\n\t\t */\n\t\tdigest[6] &= 0x0F;\n\t\tdigest[6] |= 0x30;\t/* version 3 */\n\t\tdigest[8] &= 0x3F;\n\t\tdigest[8] |= 0x80;\n\n\t\tmemcpy(&type1->uuid, digest, sizeof (digest));\n\t}\n\n\treturn (0);\n}\n\nstatic int\nsmbios_type4_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size)\n{\n\tint i;\n\n\tfor (i = 0; i < guest_ncpus; i++) {\n\t\tstruct smbios_table_type4 *type4;\n\t\tchar *p;\n\t\tint nstrings, len;\n\n\t\tsmbios_generic_initializer(template_entry, template_strings,\n\t\t    curaddr, endaddr, n, size);\n\t\ttype4 = (struct smbios_table_type4 *)curaddr;\n\t\tp = curaddr + sizeof (struct smbios_table_type4);\n\t\tnstrings = 0;\n\t\twhile (p < *endaddr - 1) {\n\t\t\tif (*p++ == '\\0')\n\t\t\t\tnstrings++;\n\t\t}\n\t\tlen = sprintf(*endaddr - 1, \"CPU #%d\", i) + 1;\n\t\t*endaddr += len - 1;\n\t\t*(*endaddr) = '\\0';\n\t\t(*endaddr)++;\n\t\ttype4->socket = (uint8_t) (nstrings + 1);\n\t\tcuraddr = *endaddr;\n\t}\n\n\treturn (0);\n}\n\nstatic int\nsmbios_type16_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size)\n{\n\tstruct smbios_table_type16 *type16;\n\n\ttype16_handle = *n;\n\tsmbios_generic_initializer(template_entry, template_strings,\n\t    curaddr, endaddr, n, size);\n\ttype16 = (struct smbios_table_type16 *)curaddr;\n\ttype16->xsize = guest_lomem + guest_himem;\n\ttype16->ndevs = guest_himem > 0 ? 2 : 1;\n\n\treturn (0);\n}\n\nstatic int\nsmbios_type17_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size)\n{\n\tstruct smbios_table_type17 *type17;\n\tuint64_t memsize, size_KB, size_MB;\n\n\tsmbios_generic_initializer(template_entry, template_strings,\n\t    curaddr, endaddr, n, size);\n\ttype17 = (struct smbios_table_type17 *)curaddr;\n\ttype17->arrayhand = type16_handle;\n\n\tmemsize = guest_lomem + guest_himem;\n\tsize_KB = memsize / 1024UL;\n\tsize_MB = memsize / (1024UL * 1024);\n\n\t/* A single Type 17 entry can't represent more than ~2PB RAM */\n\tif (size_MB > 0x7FFFFFFF) {\n\t\tprintf(\"Warning: guest memory too big for SMBIOS Type 17 table: \"\n\t\t \t\"%lluMB greater than max supported 2147483647MB\\n\", size_MB);\n\n\t\tsize_MB = 0x7FFFFFFF;\n\t}\n\n\t/* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */\n\tif (size_KB <= 0x7FFF) {\n\t\t/* Can represent up to 32767KB with the top bit set */\n\t\ttype17->size = (uint16_t) (size_KB | (1 << 15));\n\t} else if (size_MB < 0x7FFF) {\n\t\t/* Can represent up to 32766MB with the top bit unset */\n\t\ttype17->size = (uint16_t) (size_MB & 0x7FFF);\n\t} else {\n\t\ttype17->size = 0x7FFF;\n\t\t/*\n\t\t * Can represent up to 2147483647MB (~2PB)\n\t\t * The top bit is reserved\n\t\t */\n\t\ttype17->xsize = (uint32_t) (size_MB & 0x7FFFFFFF);\n\t}\n\n\treturn (0);\n}\n\nstatic int\nsmbios_type19_initializer(struct smbios_structure *template_entry,\n    const char **template_strings, char *curaddr, char **endaddr,\n    uint16_t *n, uint16_t *size)\n{\n\tstruct smbios_table_type19 *type19;\n\n\tsmbios_generic_initializer(template_entry, template_strings,\n\t    curaddr, endaddr, n, size);\n\ttype19 = (struct smbios_table_type19 *)curaddr;\n\ttype19->arrayhand = type16_handle;\n\ttype19->xsaddr = 0;\n\ttype19->xeaddr = guest_lomem;\n\n\tif (guest_himem > 0) {\n\t\tcuraddr = *endaddr;\n\t\tsmbios_generic_initializer(template_entry, template_strings,\n\t\t    curaddr, endaddr, n, size);\n\t\ttype19 = (struct smbios_table_type19 *)curaddr;\n\t\ttype19->arrayhand = type16_handle;\n\t\ttype19->xsaddr = 4*GB;\n\t\ttype19->xeaddr = guest_himem;\n\t}\n\n\treturn (0);\n}\n\nstatic void\nsmbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)\n{\n\tmemset(smbios_ep, 0, sizeof(*smbios_ep));\n\tmemcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR,\n\t    SMBIOS_ENTRY_EANCHORLEN);\n\tsmbios_ep->eplen = 0x1F;\n\tassert(sizeof (struct smbios_entry_point) == smbios_ep->eplen);\n\tsmbios_ep->major = 2;\n\tsmbios_ep->minor = 6;\n\tsmbios_ep->revision = 0;\n\tmemcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR,\n\t    SMBIOS_ENTRY_IANCHORLEN);\n\tsmbios_ep->staddr = staddr;\n\tsmbios_ep->bcdrev = 0x24;\n}\n\nstatic void\nsmbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len,\n    uint16_t num, uint16_t maxssize)\n{\n\tuint8_t\tchecksum;\n\tint\ti;\n\n\tsmbios_ep->maxssize = maxssize;\n\tsmbios_ep->stlen = len;\n\tsmbios_ep->stnum = num;\n\n\tchecksum = 0;\n\tfor (i = 0x10; i < 0x1f; i++) {\n\t\tchecksum -= ((uint8_t *)smbios_ep)[i];\n\t}\n\tsmbios_ep->ichecksum = checksum;\n\n\tchecksum = 0;\n\tfor (i = 0; i < 0x1f; i++) {\n\t\tchecksum -= ((uint8_t *)smbios_ep)[i];\n\t}\n\tsmbios_ep->echecksum = checksum;\n}\n\nint\nsmbios_build(void)\n{\n\tstruct smbios_entry_point *smbios_ep;\n\tuint16_t n;\n\tuint16_t maxssize;\n\tchar *curaddr, *startaddr, *ststartaddr;\n\tint i;\n\tint err;\n\n\tguest_lomem = xh_vm_get_lowmem_size();\n\tguest_himem = xh_vm_get_highmem_size();\n\n\tstartaddr = paddr_guest2host(SMBIOS_BASE, SMBIOS_MAX_LENGTH);\n\tif (startaddr == NULL) {\n\t\tfprintf(stderr, \"smbios table requires mapped mem\\n\");\n\t\treturn (ENOMEM);\n\t}\n\n\tcuraddr = startaddr;\n\n\tsmbios_ep = (struct smbios_entry_point *)curaddr;\n\tsmbios_ep_initializer(smbios_ep, SMBIOS_BASE +\n\t    sizeof(struct smbios_entry_point));\n\tcuraddr += sizeof(struct smbios_entry_point);\n\tststartaddr = curaddr;\n\n\tn = 0;\n\tmaxssize = 0;\n\tfor (i = 0; smbios_template[i].entry != NULL; i++) {\n\t\tstruct smbios_structure\t*entry;\n\t\tconst char **strings;\n\t\tinitializer_func_t initializer;\n\t\tchar *endaddr;\n\t\tuint16_t size;\n\n\t\tentry = smbios_template[i].entry;\n\t\tstrings = smbios_template[i].strings;\n\t\tinitializer = smbios_template[i].initializer;\n\n\t\terr = (*initializer)(entry, strings, curaddr, &endaddr,\n\t\t    &n, &size);\n\t\tif (err != 0)\n\t\t\treturn (err);\n\n\t\tif (size > maxssize)\n\t\t\tmaxssize = size;\n\n\t\tcuraddr = endaddr;\n\t}\n\n\tassert(curaddr - startaddr < SMBIOS_MAX_LENGTH);\n\tsmbios_ep_finalizer(smbios_ep, ((uint16_t) (curaddr - ststartaddr)), n,\n\t\tmaxssize);\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/sockstream.c",
    "content": "/*-\n * Copyright (c) 2015 Nahanni Systems, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n\n#include <sys/cdefs.h>\n\n#include <sys/types.h>\n#include <unistd.h>\n\n#include <errno.h>\n\n#include <xhyve/sockstream.h>\n\nssize_t\nstream_read(int fd, void *buf, ssize_t nbytes)\n{\n\tuint8_t *p;\n\tssize_t len = 0;\n\tssize_t n;\n\n\tp = buf;\n\n\twhile (len < nbytes) {\n\t\tn = read(fd, p + len, (size_t)(nbytes - len));\n\t\tif (n == 0)\n\t\t\tbreak;\n\n\t\tif (n < 0) {\n\t\t\tif (errno == EINTR || errno == EAGAIN)\n\t\t\t\tcontinue;\n\t\t\treturn (n);\n\t\t}\n\t\tlen += n;\n\t}\n\treturn (len);\n}\n\nssize_t\nstream_write(int fd, const void *buf, ssize_t nbytes)\n{\n\tconst uint8_t *p;\n\tssize_t len = 0;\n\tssize_t n;\n\n\tp = buf;\n\n\twhile (len < nbytes) {\n\t\tn = write(fd, p + len, (size_t)(nbytes - len));\n\t\tif (n == 0)\n\t\t\tbreak;\n\t\tif (n < 0) {\n\t\t\tif (errno == EINTR || errno == EAGAIN)\n\t\t\t\tcontinue;\n\t\t\treturn (n);\n\t\t}\n\t\tlen += n;\n\t}\n\treturn (len);\n}\n\n\n"
  },
  {
    "path": "src/task_switch.c",
    "content": "/*-\n * Copyright (c) 2014 Neel Natu <neel@freebsd.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <errno.h>\n#include <sys/param.h>\n#include <sys/uio.h>\n\n#include <xhyve/support/psl.h>\n#include <xhyve/support/segments.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/xhyve.h>\n\n/*\n * Using 'struct i386tss' is tempting but causes myriad sign extension\n * issues because all of its fields are defined as signed integers.\n */\nstruct tss32 {\n\tuint16_t\ttss_link;\n\tuint16_t\trsvd1;\n\tuint32_t\ttss_esp0;\n\tuint16_t\ttss_ss0;\n\tuint16_t\trsvd2;\n\tuint32_t\ttss_esp1;\n\tuint16_t\ttss_ss1;\n\tuint16_t\trsvd3;\n\tuint32_t\ttss_esp2;\n\tuint16_t\ttss_ss2;\n\tuint16_t\trsvd4;\n\tuint32_t\ttss_cr3;\n\tuint32_t\ttss_eip;\n\tuint32_t\ttss_eflags;\n\tuint32_t\ttss_eax;\n\tuint32_t\ttss_ecx;\n\tuint32_t\ttss_edx;\n\tuint32_t\ttss_ebx;\n\tuint32_t\ttss_esp;\n\tuint32_t\ttss_ebp;\n\tuint32_t\ttss_esi;\n\tuint32_t\ttss_edi;\n\tuint16_t\ttss_es;\n\tuint16_t\trsvd5;\n\tuint16_t\ttss_cs;\n\tuint16_t\trsvd6;\n\tuint16_t\ttss_ss;\n\tuint16_t\trsvd7;\n\tuint16_t\ttss_ds;\n\tuint16_t\trsvd8;\n\tuint16_t\ttss_fs;\n\tuint16_t\trsvd9;\n\tuint16_t\ttss_gs;\n\tuint16_t\trsvd10;\n\tuint16_t\ttss_ldt;\n\tuint16_t\trsvd11;\n\tuint16_t\ttss_trap;\n\tuint16_t\ttss_iomap;\n};\nCTASSERT(sizeof(struct tss32) == 104);\n\n#define\tSEL_START(sel)\t(((sel) & ~0x7))\n#define\tSEL_LIMIT(sel)\t(((sel) | 0x7))\n#define\tTSS_BUSY(type)\t(((type) & 0x2) != 0)\n\nstatic uint64_t\nGETREG(int vcpu, int reg)\n{\n\tuint64_t val;\n\tint error;\n\n\terror = xh_vm_get_register(vcpu, reg, &val);\n\tassert(error == 0);\n\treturn (val);\n}\n\nstatic void\nSETREG(int vcpu, int reg, uint64_t val)\n{\n\tint error;\n\n\terror = xh_vm_set_register(vcpu, reg, val);\n\tassert(error == 0);\n}\n\nstatic struct seg_desc\nusd_to_seg_desc(struct user_segment_descriptor *usd)\n{\n\tstruct seg_desc seg_desc;\n\n\tseg_desc.base = (u_int)USD_GETBASE(usd);\n\tif (usd->sd_gran)\n\t\tseg_desc.limit = (u_int)(USD_GETLIMIT(usd) << 12) | 0xfff;\n\telse\n\t\tseg_desc.limit = (u_int)USD_GETLIMIT(usd);\n\tseg_desc.access = (uint32_t) (usd->sd_type | (usd->sd_dpl << 5) | (usd->sd_p << 7));\n\tseg_desc.access |= (uint32_t) (usd->sd_xx << 12);\n\tseg_desc.access |= (uint32_t) (usd->sd_def32 << 14);\n\tseg_desc.access |= (uint32_t) (usd->sd_gran << 15);\n\n\treturn (seg_desc);\n}\n\n/*\n * Inject an exception with an error code that is a segment selector.\n * The format of the error code is described in section 6.13, \"Error Code\",\n * Intel SDM volume 3.\n *\n * Bit 0 (EXT) denotes whether the exception occurred during delivery\n * of an external event like an interrupt.\n *\n * Bit 1 (IDT) indicates whether the selector points to a gate descriptor\n * in the IDT.\n *\n * Bit 2(GDT/LDT) has the usual interpretation of Table Indicator (TI).\n */\nstatic void\nsel_exception(int vcpu, int vector, uint16_t sel, int ext)\n{\n\t/*\n\t * Bit 2 from the selector is retained as-is in the error code.\n\t *\n\t * Bit 1 can be safely cleared because none of the selectors\n\t * encountered during task switch emulation refer to a task\n\t * gate in the IDT.\n\t *\n\t * Bit 0 is set depending on the value of 'ext'.\n\t */\n\tsel &= ~0x3;\n\tif (ext)\n\t\tsel |= 0x1;\n\txh_vm_inject_fault(vcpu, vector, 1, sel);\n}\n\n/*\n * Return 0 if the selector 'sel' in within the limits of the GDT/LDT\n * and non-zero otherwise.\n */\nstatic int\ndesc_table_limit_check(int vcpu, uint16_t sel)\n{\n\tuint64_t base;\n\tuint32_t limit, access;\n\tint error, reg;\n\n\treg = ISLDT(sel) ? VM_REG_GUEST_LDTR : VM_REG_GUEST_GDTR;\n\terror = xh_vm_get_desc(vcpu, reg, &base, &limit, &access);\n\tassert(error == 0);\n\n\tif (reg == VM_REG_GUEST_LDTR) {\n\t\tif (SEG_DESC_UNUSABLE(access) || !SEG_DESC_PRESENT(access))\n\t\t\treturn (-1);\n\t}\n\n\tif (limit < SEL_LIMIT(sel))\n\t\treturn (-1);\n\telse\n\t\treturn (0);\n}\n\n/*\n * Read/write the segment descriptor 'desc' into the GDT/LDT slot referenced\n * by the selector 'sel'.\n *\n * Returns 0 on success.\n * Returns 1 if an exception was injected into the guest.\n * Returns -1 otherwise.\n */\nstatic int\ndesc_table_rw(int vcpu, struct vm_guest_paging *paging,\n    uint16_t sel, struct user_segment_descriptor *desc, bool doread,\n    int *faultptr)\n{\n\tstruct iovec iov[2];\n\tuint64_t base;\n\tuint32_t limit, access;\n\tint error, reg;\n\n\treg = ISLDT(sel) ? VM_REG_GUEST_LDTR : VM_REG_GUEST_GDTR;\n\terror = xh_vm_get_desc(vcpu, reg, &base, &limit, &access);\n\tassert(error == 0);\n\tassert(limit >= SEL_LIMIT(sel));\n\n\terror = xh_vm_copy_setup(vcpu, paging, base + SEL_START(sel),\n\t    sizeof(*desc), doread ? XHYVE_PROT_READ : XHYVE_PROT_WRITE, iov, nitems(iov),\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\n\tif (doread)\n\t\txh_vm_copyin(iov, desc, sizeof(*desc));\n\telse\n\t\txh_vm_copyout(desc, iov, sizeof(*desc));\n\treturn (0);\n}\n\nstatic int\ndesc_table_read(int vcpu, struct vm_guest_paging *paging, uint16_t sel,\n\tstruct user_segment_descriptor *desc, int *faultptr)\n{\n\treturn (desc_table_rw(vcpu, paging, sel, desc, true, faultptr));\n}\n\nstatic int\ndesc_table_write(int vcpu, struct vm_guest_paging *paging, uint16_t sel,\n\tstruct user_segment_descriptor *desc, int *faultptr)\n{\n\treturn (desc_table_rw(vcpu, paging, sel, desc, false, faultptr));\n}\n\n/*\n * Read the TSS descriptor referenced by 'sel' into 'desc'.\n *\n * Returns 0 on success.\n * Returns 1 if an exception was injected into the guest.\n * Returns -1 otherwise.\n */\nstatic int\nread_tss_descriptor(int vcpu, struct vm_task_switch *ts, uint16_t sel,\n\tstruct user_segment_descriptor *desc, int *faultptr)\n{\n\tstruct vm_guest_paging sup_paging;\n\tint error;\n\n\tassert(!ISLDT(sel));\n\tassert(IDXSEL(sel) != 0);\n\n\t/* Fetch the new TSS descriptor */\n\tif (desc_table_limit_check(vcpu, sel)) {\n\t\tif (ts->reason == TSR_IRET)\n\t\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\telse\n\t\t\tsel_exception(vcpu, IDT_GP, sel, ts->ext);\n\t\treturn (1);\n\t}\n\n\tsup_paging = ts->paging;\n\tsup_paging.cpl = 0;\t\t/* implicit supervisor mode */\n\terror = desc_table_read(vcpu, &sup_paging, sel, desc, faultptr);\n\treturn (error);\n}\n\nstatic bool\ncode_desc(int sd_type)\n{\n\t/* code descriptor */\n\treturn ((sd_type & 0x18) == 0x18);\n}\n\nstatic bool\nstack_desc(int sd_type)\n{\n\t/* writable data descriptor */\n\treturn ((sd_type & 0x1A) == 0x12);\n}\n\nstatic bool\ndata_desc(int sd_type)\n{\n\t/* data descriptor or a readable code descriptor */\n\treturn ((sd_type & 0x18) == 0x10 || (sd_type & 0x1A) == 0x1A);\n}\n\nstatic bool\nldt_desc(int sd_type)\n{\n\n\treturn (sd_type == SDT_SYSLDT);\n}\n\nCTASSERT(sizeof(struct user_segment_descriptor) == 8);\n/*\n * Validate the descriptor 'seg_desc' associated with 'segment'.\n */\nstatic int\nvalidate_seg_desc(int vcpu, struct vm_task_switch *ts, int segment,\n\tstruct seg_desc *seg_desc, int *faultptr)\n{\n\tstruct vm_guest_paging sup_paging;\n\tstruct user_segment_descriptor usd;\n\tint error, idtvec;\n\tint cpl, dpl, rpl;\n\tuint16_t sel, cs;\n\tbool ldtseg, codeseg, stackseg, dataseg, conforming;\n\n\tldtseg = codeseg = stackseg = dataseg = false;\n\tswitch (segment) {\n\tcase VM_REG_GUEST_LDTR:\n\t\tldtseg = true;\n\t\tbreak;\n\tcase VM_REG_GUEST_CS:\n\t\tcodeseg = true;\n\t\tbreak;\n\tcase VM_REG_GUEST_SS:\n\t\tstackseg = true;\n\t\tbreak;\n\tcase VM_REG_GUEST_DS:\n\tcase VM_REG_GUEST_ES:\n\tcase VM_REG_GUEST_FS:\n\tcase VM_REG_GUEST_GS:\n\t\tdataseg = true;\n\t\tbreak;\n\tdefault:\n\t\tassert(0);\n\t}\n\n\t/* Get the segment selector */\n\tsel = (uint16_t) GETREG(vcpu, segment);\n\n\t/* LDT selector must point into the GDT */\n\tif (ldtseg && ISLDT(sel)) {\n\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\treturn (1);\n\t}\n\n\t/* Descriptor table limit check */\n\tif (desc_table_limit_check(vcpu, sel)) {\n\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\treturn (1);\n\t}\n\n\t/* NULL selector */\n\tif (IDXSEL(sel) == 0) {\n\t\t/* Code and stack segment selectors cannot be NULL */\n\t\tif (codeseg || stackseg) {\n\t\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\t\treturn (1);\n\t\t}\n\t\tseg_desc->base = 0;\n\t\tseg_desc->limit = 0;\n\t\tseg_desc->access = 0x10000;\t/* unusable */\n\t\treturn (0);\n\t}\n\n\t/* Read the descriptor from the GDT/LDT */\n\tsup_paging = ts->paging;\n\tsup_paging.cpl = 0;\t/* implicit supervisor mode */\n\terror = desc_table_read(vcpu, &sup_paging, sel, &usd, faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\n\t/* Verify that the descriptor type is compatible with the segment */\n\tif ((ldtseg && !ldt_desc(usd.sd_type)) ||\n\t    (codeseg && !code_desc(usd.sd_type)) ||\n\t    (dataseg && !data_desc(usd.sd_type)) ||\n\t    (stackseg && !stack_desc(usd.sd_type))) {\n\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\treturn (1);\n\t}\n\n\t/* Segment must be marked present */\n\tif (!usd.sd_p) {\n\t\tif (ldtseg)\n\t\t\tidtvec = IDT_TS;\n\t\telse if (stackseg)\n\t\t\tidtvec = IDT_SS;\n\t\telse\n\t\t\tidtvec = IDT_NP;\n\t\tsel_exception(vcpu, idtvec, sel, ts->ext);\n\t\treturn (1);\n\t}\n\n\tcs = (uint16_t) GETREG(vcpu, VM_REG_GUEST_CS);\n\tcpl = cs & SEL_RPL_MASK;\n\trpl = sel & SEL_RPL_MASK;\n\tdpl = usd.sd_dpl;\n\n\tif (stackseg && (rpl != cpl || dpl != cpl)) {\n\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\treturn (1);\n\t}\n\n\tif (codeseg) {\n\t\tconforming = (usd.sd_type & 0x4) ? true : false;\n\t\tif ((conforming && (cpl < dpl)) ||\n\t\t    (!conforming && (cpl != dpl))) {\n\t\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\t\treturn (1);\n\t\t}\n\t}\n\n\tif (dataseg) {\n\t\t/*\n\t\t * A data segment is always non-conforming except when it's\n\t\t * descriptor is a readable, conforming code segment.\n\t\t */\n\t\tif (code_desc(usd.sd_type) && (usd.sd_type & 0x4) != 0)\n\t\t\tconforming = true;\n\t\telse\n\t\t\tconforming = false;\n\n\t\tif (!conforming && (rpl > dpl || cpl > dpl)) {\n\t\t\tsel_exception(vcpu, IDT_TS, sel, ts->ext);\n\t\t\treturn (1);\n\t\t}\n\t}\n\t*seg_desc = usd_to_seg_desc(&usd);\n\treturn (0);\n}\n\nstatic void\ntss32_save(int vcpu, struct vm_task_switch *task_switch,\n    uint32_t eip, struct tss32 *tss, struct iovec *iov)\n{\n\n\t/* General purpose registers */\n\ttss->tss_eax = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RAX);\n\ttss->tss_ecx = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RCX);\n\ttss->tss_edx = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RDX);\n\ttss->tss_ebx = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RBX);\n\ttss->tss_esp = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RSP);\n\ttss->tss_ebp = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RBP);\n\ttss->tss_esi = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RSI);\n\ttss->tss_edi = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RDI);\n\n\t/* Segment selectors */\n\ttss->tss_es = (uint16_t) GETREG(vcpu, VM_REG_GUEST_ES);\n\ttss->tss_cs = (uint16_t) GETREG(vcpu, VM_REG_GUEST_CS);\n\ttss->tss_ss = (uint16_t) GETREG(vcpu, VM_REG_GUEST_SS);\n\ttss->tss_ds = (uint16_t) GETREG(vcpu, VM_REG_GUEST_DS);\n\ttss->tss_fs = (uint16_t) GETREG(vcpu, VM_REG_GUEST_FS);\n\ttss->tss_gs = (uint16_t) GETREG(vcpu, VM_REG_GUEST_GS);\n\n\t/* eflags and eip */\n\ttss->tss_eflags = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RFLAGS);\n\tif (task_switch->reason == TSR_IRET)\n\t\ttss->tss_eflags &= ~((unsigned) PSL_NT);\n\ttss->tss_eip = eip;\n\n\t/* Copy updated old TSS into guest memory */\n\txh_vm_copyout(tss, iov, sizeof(struct tss32));\n}\n\nstatic void\nupdate_seg_desc(int vcpu, int reg, struct seg_desc *sd)\n{\n\tint error;\n\n\terror = xh_vm_set_desc(vcpu, reg, sd->base, sd->limit, sd->access);\n\tassert(error == 0);\n}\n\n/*\n * Update the vcpu registers to reflect the state of the new task.\n */\nstatic int\ntss32_restore(int vcpu, struct vm_task_switch *ts, uint16_t ot_sel,\n\tstruct tss32 *tss, struct iovec *iov, int *faultptr)\n{\n\tstruct seg_desc seg_desc, seg_desc2;\n\tuint64_t *pdpte, maxphyaddr, reserved;\n\tuint32_t eflags;\n\tint error, i;\n\tbool nested;\n\n\tnested = false;\n\tif (ts->reason != TSR_IRET && ts->reason != TSR_JMP) {\n\t\ttss->tss_link = ot_sel;\n\t\tnested = true;\n\t}\n\n\teflags = tss->tss_eflags;\n\tif (nested)\n\t\teflags |= PSL_NT;\n\n\t/* LDTR */\n\tSETREG(vcpu, VM_REG_GUEST_LDTR, tss->tss_ldt);\n\n\t/* PBDR */\n\tif (ts->paging.paging_mode != PAGING_MODE_FLAT) {\n\t\tif (ts->paging.paging_mode == PAGING_MODE_PAE) {\n\t\t\t/*\n\t\t\t * XXX Assuming 36-bit MAXPHYADDR.\n\t\t\t */\n\t\t\tmaxphyaddr = (1UL << 36) - 1;\n\t\t\tpdpte = paddr_guest2host(tss->tss_cr3 & ~((unsigned) 0x1f), 32);\n\t\t\tfor (i = 0; i < 4; i++) {\n\t\t\t\t/* Check reserved bits if the PDPTE is valid */\n\t\t\t\tif (!(pdpte[i] & 0x1))\n\t\t\t\t\tcontinue;\n\t\t\t\t/*\n\t\t\t\t * Bits 2:1, 8:5 and bits above the processor's\n\t\t\t\t * maximum physical address are reserved.\n\t\t\t\t */\n\t\t\t\treserved = ~maxphyaddr | 0x1E6;\n\t\t\t\tif (pdpte[i] & reserved) {\n\t\t\t\t\tvm_inject_gp(vcpu);\n\t\t\t\t\treturn (1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tSETREG(vcpu, VM_REG_GUEST_PDPTE0, pdpte[0]);\n\t\t\tSETREG(vcpu, VM_REG_GUEST_PDPTE1, pdpte[1]);\n\t\t\tSETREG(vcpu, VM_REG_GUEST_PDPTE2, pdpte[2]);\n\t\t\tSETREG(vcpu, VM_REG_GUEST_PDPTE3, pdpte[3]);\n\t\t}\n\t\tSETREG(vcpu, VM_REG_GUEST_CR3, tss->tss_cr3);\n\t\tts->paging.cr3 = tss->tss_cr3;\n\t}\n\n\t/* eflags and eip */\n\tSETREG(vcpu, VM_REG_GUEST_RFLAGS, eflags);\n\tSETREG(vcpu, VM_REG_GUEST_RIP, tss->tss_eip);\n\n\t/* General purpose registers */\n\tSETREG(vcpu, VM_REG_GUEST_RAX, tss->tss_eax);\n\tSETREG(vcpu, VM_REG_GUEST_RCX, tss->tss_ecx);\n\tSETREG(vcpu, VM_REG_GUEST_RDX, tss->tss_edx);\n\tSETREG(vcpu, VM_REG_GUEST_RBX, tss->tss_ebx);\n\tSETREG(vcpu, VM_REG_GUEST_RSP, tss->tss_esp);\n\tSETREG(vcpu, VM_REG_GUEST_RBP, tss->tss_ebp);\n\tSETREG(vcpu, VM_REG_GUEST_RSI, tss->tss_esi);\n\tSETREG(vcpu, VM_REG_GUEST_RDI, tss->tss_edi);\n\n\t/* Segment selectors */\n\tSETREG(vcpu, VM_REG_GUEST_ES, tss->tss_es);\n\tSETREG(vcpu, VM_REG_GUEST_CS, tss->tss_cs);\n\tSETREG(vcpu, VM_REG_GUEST_SS, tss->tss_ss);\n\tSETREG(vcpu, VM_REG_GUEST_DS, tss->tss_ds);\n\tSETREG(vcpu, VM_REG_GUEST_FS, tss->tss_fs);\n\tSETREG(vcpu, VM_REG_GUEST_GS, tss->tss_gs);\n\n\t/*\n\t * If this is a nested task then write out the new TSS to update\n\t * the previous link field.\n\t */\n\tif (nested)\n\t\txh_vm_copyout(tss, iov, sizeof(*tss));\n\n\t/* Validate segment descriptors */\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_LDTR, &seg_desc,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_LDTR, &seg_desc);\n\n\t/*\n\t * Section \"Checks on Guest Segment Registers\", Intel SDM, Vol 3.\n\t *\n\t * The SS and CS attribute checks on VM-entry are inter-dependent so\n\t * we need to make sure that both segments are valid before updating\n\t * either of them. This ensures that the VMCS state can pass the\n\t * VM-entry checks so the guest can handle any exception injected\n\t * during task switch emulation.\n\t */\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_CS, &seg_desc,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_SS, &seg_desc2,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_CS, &seg_desc);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_SS, &seg_desc2);\n\tts->paging.cpl = tss->tss_cs & SEL_RPL_MASK;\n\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_DS, &seg_desc,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_DS, &seg_desc);\n\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_ES, &seg_desc,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_ES, &seg_desc);\n\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_FS, &seg_desc,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_FS, &seg_desc);\n\n\terror = validate_seg_desc(vcpu, ts, VM_REG_GUEST_GS, &seg_desc,\n\t    faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_GS, &seg_desc);\n\n\treturn (0);\n}\n\n/*\n * Push an error code on the stack of the new task. This is needed if the\n * task switch was triggered by a hardware exception that causes an error\n * code to be saved (e.g. #PF).\n */\nstatic int\npush_errcode(int vcpu, struct vm_guest_paging *paging, int task_type,\n\tuint32_t errcode, int *faultptr)\n{\n\tstruct iovec iov[2];\n\tstruct seg_desc seg_desc;\n\tint stacksize, bytes, error;\n\tuint64_t gla, cr0, rflags;\n\tuint32_t esp;\n\tuint16_t stacksel;\n\n\t*faultptr = 0;\n\n\tcr0 = GETREG(vcpu, VM_REG_GUEST_CR0);\n\trflags = GETREG(vcpu, VM_REG_GUEST_RFLAGS);\n\tstacksel = (uint16_t) GETREG(vcpu, VM_REG_GUEST_SS);\n\n\terror = xh_vm_get_desc(vcpu, VM_REG_GUEST_SS, &seg_desc.base,\n\t    &seg_desc.limit, &seg_desc.access);\n\tassert(error == 0);\n\n\t/*\n\t * Section \"Error Code\" in the Intel SDM vol 3: the error code is\n\t * pushed on the stack as a doubleword or word (depending on the\n\t * default interrupt, trap or task gate size).\n\t */\n\tif (task_type == SDT_SYS386BSY || task_type == SDT_SYS386TSS)\n\t\tbytes = 4;\n\telse\n\t\tbytes = 2;\n\n\t/*\n\t * PUSH instruction from Intel SDM vol 2: the 'B' flag in the\n\t * stack-segment descriptor determines the size of the stack\n\t * pointer outside of 64-bit mode.\n\t */\n\tif (SEG_DESC_DEF32(seg_desc.access))\n\t\tstacksize = 4;\n\telse\n\t\tstacksize = 2;\n\n\tesp = (uint32_t) GETREG(vcpu, VM_REG_GUEST_RSP);\n\tesp -= (uint32_t) bytes;\n\n\tif (vie_calculate_gla(paging->cpu_mode, VM_REG_GUEST_SS, &seg_desc, esp,\n\t\tbytes, stacksize, XHYVE_PROT_WRITE, &gla))\n\t{\n\t\tsel_exception(vcpu, IDT_SS, stacksel, 1);\n\t\t*faultptr = 1;\n\t\treturn (0);\n\t}\n\n\tif (vie_alignment_check(paging->cpl, bytes, cr0, rflags, gla)) {\n\t\tvm_inject_ac(vcpu, 1);\n\t\t*faultptr = 1;\n\t\treturn (0);\n\t}\n\n\terror = xh_vm_copy_setup(vcpu, paging, gla, ((size_t) bytes),\n\t\tXHYVE_PROT_WRITE, iov, nitems(iov), faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\n\txh_vm_copyout(&errcode, iov, ((size_t) bytes));\n\tSETREG(vcpu, VM_REG_GUEST_RSP, esp);\n\treturn (0);\n}\n\n/*\n * Evaluate return value from helper functions and potentially return to\n * the VM run loop.\n */\n#define\tCHKERR(error,fault)\t\t\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\\\n\t\tassert((error == 0) || (error == EFAULT));\t\t\\\n\t\tif (error)\t\t\t\t\t\t\\\n\t\t\treturn (VMEXIT_ABORT);\t\t\t\t\\\n\t\telse if (fault)\t\t\t\t\t\t\\\n\t\t\treturn (VMEXIT_CONTINUE);\t\t\t\\\n\t} while (0)\n\nint vmexit_task_switch(struct vm_exit *vmexit, int *pvcpu);\n\nint\nvmexit_task_switch(struct vm_exit *vmexit, int *pvcpu)\n{\n\tstruct seg_desc nt;\n\tstruct tss32 oldtss, newtss;\n\tstruct vm_task_switch *task_switch;\n\tstruct vm_guest_paging *paging, sup_paging;\n\tstruct user_segment_descriptor nt_desc, ot_desc;\n\tstruct iovec nt_iov[2], ot_iov[2];\n\tuint64_t cr0, ot_base;\n\tuint32_t eip, ot_lim, access;\n\tint error, ext, fault, minlimit, nt_type, ot_type, vcpu;\n\tenum task_switch_reason reason;\n\tuint16_t nt_sel, ot_sel;\n\n\ttask_switch = &vmexit->u.task_switch;\n\tnt_sel = task_switch->tsssel;\n\text = vmexit->u.task_switch.ext;\n\treason = vmexit->u.task_switch.reason;\n\tpaging = &vmexit->u.task_switch.paging;\n\tvcpu = *pvcpu;\n\n\tassert(paging->cpu_mode == CPU_MODE_PROTECTED);\n\n\t/*\n\t * Calculate the instruction pointer to store in the old TSS.\n\t */\n\teip = (uint32_t) (vmexit->rip + ((uint64_t) vmexit->inst_length));\n\n\t/*\n\t * Section 4.6, \"Access Rights\" in Intel SDM Vol 3.\n\t * The following page table accesses are implicitly supervisor mode:\n\t * - accesses to GDT or LDT to load segment descriptors\n\t * - accesses to the task state segment during task switch\n\t */\n\tsup_paging = *paging;\n\tsup_paging.cpl = 0;\t/* implicit supervisor mode */\n\n\t/* Fetch the new TSS descriptor */\n\terror = read_tss_descriptor(vcpu, task_switch, nt_sel, &nt_desc,\n\t    &fault);\n\tCHKERR(error, fault);\n\n\tnt = usd_to_seg_desc(&nt_desc);\n\n\t/* Verify the type of the new TSS */\n\tnt_type = SEG_DESC_TYPE(nt.access);\n\tif (nt_type != SDT_SYS386BSY && nt_type != SDT_SYS386TSS &&\n\t    nt_type != SDT_SYS286BSY && nt_type != SDT_SYS286TSS) {\n\t\tsel_exception(vcpu, IDT_TS, nt_sel, ext);\n\t\tgoto done;\n\t}\n\n\t/* TSS descriptor must have present bit set */\n\tif (!SEG_DESC_PRESENT(nt.access)) {\n\t\tsel_exception(vcpu, IDT_NP, nt_sel, ext);\n\t\tgoto done;\n\t}\n\n\t/*\n\t * TSS must have a minimum length of 104 bytes for a 32-bit TSS and\n\t * 44 bytes for a 16-bit TSS.\n\t */\n\tif (nt_type == SDT_SYS386BSY || nt_type == SDT_SYS386TSS)\n\t\tminlimit = 104 - 1;\n\telse if (nt_type == SDT_SYS286BSY || nt_type == SDT_SYS286TSS)\n\t\tminlimit = 44 - 1;\n\telse\n\t\tminlimit = 0;\n\n\tassert(minlimit > 0);\n\tif (nt.limit < ((uint32_t) minlimit)) {\n\t\tsel_exception(vcpu, IDT_TS, nt_sel, ext);\n\t\tgoto done;\n\t}\n\n\t/* TSS must be busy if task switch is due to IRET */\n\tif (reason == TSR_IRET && !TSS_BUSY(nt_type)) {\n\t\tsel_exception(vcpu, IDT_TS, nt_sel, ext);\n\t\tgoto done;\n\t}\n\n\t/*\n\t * TSS must be available (not busy) if task switch reason is\n\t * CALL, JMP, exception or interrupt.\n\t */\n\tif (reason != TSR_IRET && TSS_BUSY(nt_type)) {\n\t\tsel_exception(vcpu, IDT_GP, nt_sel, ext);\n\t\tgoto done;\n\t}\n\n\t/* Fetch the new TSS */\n\terror = xh_vm_copy_setup(vcpu, &sup_paging, nt.base,\n\t\t((size_t) (minlimit + 1)), (XHYVE_PROT_READ | XHYVE_PROT_WRITE), nt_iov,\n\t\tnitems(nt_iov), &fault);\n\tCHKERR(error, fault);\n\txh_vm_copyin(nt_iov, &newtss, ((size_t) (minlimit + 1)));\n\n\t/* Get the old TSS selector from the guest's task register */\n\tot_sel = (uint16_t) GETREG(vcpu, VM_REG_GUEST_TR);\n\tif (ISLDT(ot_sel) || IDXSEL(ot_sel) == 0) {\n\t\t/*\n\t\t * This might happen if a task switch was attempted without\n\t\t * ever loading the task register with LTR. In this case the\n\t\t * TR would contain the values from power-on:\n\t\t * (sel = 0, base = 0, limit = 0xffff).\n\t\t */\n\t\tsel_exception(vcpu, IDT_TS, ot_sel, task_switch->ext);\n\t\tgoto done;\n\t}\n\n\t/* Get the old TSS base and limit from the guest's task register */\n\terror = xh_vm_get_desc(vcpu, VM_REG_GUEST_TR, &ot_base, &ot_lim,\n\t    &access);\n\tassert(error == 0);\n\tassert(!SEG_DESC_UNUSABLE(access) && SEG_DESC_PRESENT(access));\n\tot_type = SEG_DESC_TYPE(access);\n\tassert(ot_type == SDT_SYS386BSY || ot_type == SDT_SYS286BSY);\n\n\t/* Fetch the old TSS descriptor */\n\terror = read_tss_descriptor(vcpu, task_switch, ot_sel, &ot_desc,\n\t    &fault);\n\tCHKERR(error, fault);\n\n\t/* Get the old TSS */\n\terror = xh_vm_copy_setup(vcpu, &sup_paging, ot_base,\n\t\t((size_t) (minlimit + 1)), (XHYVE_PROT_READ | XHYVE_PROT_WRITE),\n\t\tot_iov, nitems(ot_iov), &fault);\n\tCHKERR(error, fault);\n\txh_vm_copyin(ot_iov, &oldtss, ((size_t) (minlimit + 1)));\n\n\t/*\n\t * Clear the busy bit in the old TSS descriptor if the task switch\n\t * due to an IRET or JMP instruction.\n\t */\n\tif (reason == TSR_IRET || reason == TSR_JMP) {\n\t\tot_desc.sd_type &= ~0x2;\n\t\terror = desc_table_write(vcpu, &sup_paging, ot_sel,\n\t\t    &ot_desc, &fault);\n\t\tCHKERR(error, fault);\n\t}\n\n\tif (nt_type == SDT_SYS286BSY || nt_type == SDT_SYS286TSS) {\n\t\tfprintf(stderr, \"Task switch to 16-bit TSS not supported\\n\");\n\t\treturn (VMEXIT_ABORT);\n\t}\n\n\t/* Save processor state in old TSS */\n\ttss32_save(vcpu, task_switch, eip, &oldtss, ot_iov);\n\n\t/*\n\t * If the task switch was triggered for any reason other than IRET\n\t * then set the busy bit in the new TSS descriptor.\n\t */\n\tif (reason != TSR_IRET) {\n\t\tnt_desc.sd_type |= 0x2;\n\t\terror = desc_table_write(vcpu, &sup_paging, nt_sel,\n\t\t    &nt_desc, &fault);\n\t\tCHKERR(error, fault);\n\t}\n\n\t/* Update task register to point at the new TSS */\n\tSETREG(vcpu, VM_REG_GUEST_TR, nt_sel);\n\n\t/* Update the hidden descriptor state of the task register */\n\tnt = usd_to_seg_desc(&nt_desc);\n\tupdate_seg_desc(vcpu, VM_REG_GUEST_TR, &nt);\n\n\t/* Set CR0.TS */\n\tcr0 = GETREG(vcpu, VM_REG_GUEST_CR0);\n\tSETREG(vcpu, VM_REG_GUEST_CR0, cr0 | CR0_TS);\n\n\t/*\n\t * We are now committed to the task switch. Any exceptions encountered\n\t * after this point will be handled in the context of the new task and\n\t * the saved instruction pointer will belong to the new task.\n\t */\n\terror = xh_vm_set_register(vcpu, VM_REG_GUEST_RIP, newtss.tss_eip);\n\tassert(error == 0);\n\n\t/* Load processor state from new TSS */\n\terror = tss32_restore(vcpu, task_switch, ot_sel, &newtss, nt_iov,\n\t    &fault);\n\tCHKERR(error, fault);\n\n\t/*\n\t * Section \"Interrupt Tasks\" in Intel SDM, Vol 3: if an exception\n\t * caused an error code to be generated, this error code is copied\n\t * to the stack of the new task.\n\t */\n\tif (task_switch->errcode_valid) {\n\t\tassert(task_switch->ext);\n\t\tassert(task_switch->reason == TSR_IDT_GATE);\n\t\terror = push_errcode(vcpu, &task_switch->paging, nt_type,\n\t\t    task_switch->errcode, &fault);\n\t\tCHKERR(error, fault);\n\t}\n\n\t/*\n\t * Treatment of virtual-NMI blocking if NMI is delivered through\n\t * a task gate.\n\t *\n\t * Section \"Architectural State Before A VM Exit\", Intel SDM, Vol3:\n\t * If the virtual NMIs VM-execution control is 1, VM entry injects\n\t * an NMI, and delivery of the NMI causes a task switch that causes\n\t * a VM exit, virtual-NMI blocking is in effect before the VM exit\n\t * commences.\n\t *\n\t * Thus, virtual-NMI blocking is in effect at the time of the task\n\t * switch VM exit.\n\t */\n\n\t/*\n\t * Treatment of virtual-NMI unblocking on IRET from NMI handler task.\n\t *\n\t * Section \"Changes to Instruction Behavior in VMX Non-Root Operation\"\n\t * If \"virtual NMIs\" control is 1 IRET removes any virtual-NMI blocking.\n\t * This unblocking of virtual-NMI occurs even if IRET causes a fault.\n\t *\n\t * Thus, virtual-NMI blocking is cleared at the time of the task switch\n\t * VM exit.\n\t */\n\n\t/*\n\t * If the task switch was triggered by an event delivered through\n\t * the IDT then extinguish the pending event from the vcpu's\n\t * exitintinfo.\n\t */\n\tif (task_switch->reason == TSR_IDT_GATE) {\n\t\terror = xh_vm_set_intinfo(vcpu, 0);\n\t\tassert(error == 0);\n\t}\n\n\t/*\n\t * XXX should inject debug exception if 'T' bit is 1\n\t */\ndone:\n\treturn (VMEXIT_CONTINUE);\n}\n"
  },
  {
    "path": "src/uart_emul.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <strings.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <pthread.h>\n#include <termios.h>\n#include <assert.h>\n#include <xhyve/support/ns16550.h>\n#include <xhyve/mevent.h>\n#include <xhyve/uart_emul.h>\n\n#define\tCOM1_BASE      \t0x3F8\n#define COM1_IRQ\t4\n#define\tCOM2_BASE      \t0x2F8\n#define COM2_IRQ\t3\n\n#define\tDEFAULT_RCLK\t1843200\n#define\tDEFAULT_BAUD\t9600\n\n#define\tFCR_RX_MASK\t0xC0\n\n#define\tMCR_OUT1\t0x04\n#define\tMCR_OUT2\t0x08\n\n#define\tMSR_DELTA_MASK\t0x0f\n\n#ifndef REG_SCR\n#define REG_SCR\t\tcom_scr\n#endif\n\n#define\tFIFOSZ\t16\n\nstatic bool uart_stdio;\t\t/* stdio in use for i/o */\nstatic struct termios tio_stdio_orig;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstatic struct {\n\tint\tbaseaddr;\n\tint\tirq;\n\tbool\tinuse;\n} uart_lres[] = {\n\t{ COM1_BASE, COM1_IRQ, false},\n\t{ COM2_BASE, COM2_IRQ, false},\n};\n\n#define\tUART_NLDEVS\t(sizeof(uart_lres) / sizeof(uart_lres[0]))\n\nstruct fifo {\n\tuint8_t\tbuf[FIFOSZ];\n\tint\trindex;\t\t/* index to read from */\n\tint\twindex;\t\t/* index to write to */\n\tint\tnum;\t\t/* number of characters in the fifo */\n\tint\tsize;\t\t/* size of the fifo */\n};\n\nstruct ttyfd {\n\tbool\topened;\n\tint\tfd;\t\t/* tty device file descriptor */\n\tchar *name; /* slave pty name when using autopty*/\n\tstruct termios tio_orig, tio_new;    /* I/O Terminals */\n};\n\nstruct uart_softc {\n\tpthread_mutex_t mtx;\t/* protects all softc elements */\n\tuint8_t\tdata;\t\t/* Data register (R/W) */\n\tuint8_t ier;\t\t/* Interrupt enable register (R/W) */\n\tuint8_t lcr;\t\t/* Line control register (R/W) */\n\tuint8_t mcr;\t\t/* Modem control register (R/W) */\n\tuint8_t lsr;\t\t/* Line status register (R/W) */\n\tuint8_t msr;\t\t/* Modem status register (R/W) */\n\tuint8_t fcr;\t\t/* FIFO control register (W) */\n\tuint8_t scr;\t\t/* Scratch register (R/W) */\n\n\tuint8_t dll;\t\t/* Baudrate divisor latch LSB */\n\tuint8_t dlh;\t\t/* Baudrate divisor latch MSB */\n\n\tstruct fifo rxfifo;\n\tstruct mevent *mev;\n\n\tstruct ttyfd tty;\n\tbool\tthre_int_pending;\t/* THRE interrupt pending */\n\n\tvoid\t*arg;\n\tuart_intr_func_t intr_assert;\n\tuart_intr_func_t intr_deassert;\n};\n#pragma clang diagnostic pop\n\nstatic void uart_drain(int fd, enum ev_type ev, void *arg);\n\nstatic void\nttyclose(void)\n{\n\n\ttcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig);\n}\n\nstatic void\nttyopen(struct ttyfd *tf)\n{\n\n\ttcgetattr(tf->fd, &tf->tio_orig);\n\n\ttf->tio_new = tf->tio_orig;\n\tcfmakeraw(&tf->tio_new);\n\ttf->tio_new.c_cflag |= CLOCAL;\n\ttcsetattr(tf->fd, TCSANOW, &tf->tio_new);\n\n\tif (tf->fd == STDIN_FILENO) {\n\t\ttio_stdio_orig = tf->tio_orig;\n\t\tatexit(ttyclose);\n\t}\n}\n\nstatic int\nttyread(struct ttyfd *tf)\n{\n\tunsigned char rb;\n\n\tif (read(tf->fd, &rb, 1) == 1)\n\t\treturn (rb);\n\telse\n\t\treturn (-1);\n}\n\nstatic void\nttywrite(struct ttyfd *tf, unsigned char wb)\n{\n\n\t(void)write(tf->fd, &wb, 1);\n}\n\nstatic void\nrxfifo_reset(struct uart_softc *sc, int size)\n{\n\tchar flushbuf[32];\n\tstruct fifo *fifo;\n\tssize_t nread;\n\tint error;\n\n\tfifo = &sc->rxfifo;\n\tbzero(fifo, sizeof(struct fifo));\n\tfifo->size = size;\n\n\tif (sc->tty.opened) {\n\t\t/*\n\t\t * Flush any unread input from the tty buffer.\n\t\t */\n\t\twhile (1) {\n\t\t\tnread = read(sc->tty.fd, flushbuf, sizeof(flushbuf));\n\t\t\tif (nread != sizeof(flushbuf))\n\t\t\t\tbreak;\n\t\t}\n\n\t\t/*\n\t\t * Enable mevent to trigger when new characters are available\n\t\t * on the tty fd.\n\t\t */\n\t\terror = mevent_enable(sc->mev);\n\t\tassert(error == 0);\n\t}\n}\n\nstatic int\nrxfifo_available(struct uart_softc *sc)\n{\n\tstruct fifo *fifo;\n\n\tfifo = &sc->rxfifo;\n\treturn (fifo->num < fifo->size);\n}\n\nstatic int\nrxfifo_putchar(struct uart_softc *sc, uint8_t ch)\n{\n\tstruct fifo *fifo;\n\tint error;\n\n\tfifo = &sc->rxfifo;\n\n\tif (fifo->num < fifo->size) {\n\t\tfifo->buf[fifo->windex] = ch;\n\t\tfifo->windex = (fifo->windex + 1) % fifo->size;\n\t\tfifo->num++;\n\t\tif (!rxfifo_available(sc)) {\n\t\t\tif (sc->tty.opened) {\n\t\t\t\t/*\n\t\t\t\t * Disable mevent callback if the FIFO is full.\n\t\t\t\t */\n\t\t\t\terror = mevent_disable(sc->mev);\n\t\t\t\tassert(error == 0);\n\t\t\t}\n\t\t}\n\t\treturn (0);\n\t} else\n\t\treturn (-1);\n}\n\nstatic int\nrxfifo_getchar(struct uart_softc *sc)\n{\n\tstruct fifo *fifo;\n\tint c, error, wasfull;\n\n\twasfull = 0;\n\tfifo = &sc->rxfifo;\n\tif (fifo->num > 0) {\n\t\tif (!rxfifo_available(sc))\n\t\t\twasfull = 1;\n\t\tc = fifo->buf[fifo->rindex];\n\t\tfifo->rindex = (fifo->rindex + 1) % fifo->size;\n\t\tfifo->num--;\n\t\tif (wasfull) {\n\t\t\tif (sc->tty.opened) {\n\t\t\t\terror = mevent_enable(sc->mev);\n\t\t\t\tassert(error == 0);\n\t\t\t}\n\t\t}\n\t\treturn (c);\n\t} else\n\t\treturn (-1);\n}\n\nstatic int\nrxfifo_numchars(struct uart_softc *sc)\n{\n\tstruct fifo *fifo = &sc->rxfifo;\n\n\treturn (fifo->num);\n}\n\nstatic void\nuart_opentty(struct uart_softc *sc)\n{\n\n\tttyopen(&sc->tty);\n\tsc->mev = mevent_add(sc->tty.fd, EVF_READ, uart_drain, sc);\n\tassert(sc->mev != NULL);\n}\n\n/*\n * The IIR returns a prioritized interrupt reason:\n * - receive data available\n * - transmit holding register empty\n * - modem status change\n *\n * Return an interrupt reason if one is available.\n */\nstatic int\nuart_intr_reason(struct uart_softc *sc)\n{\n\n\tif ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)\n\t\treturn (IIR_RLS);\n\telse if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0)\n\t\treturn (IIR_RXTOUT);\n\telse if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)\n\t\treturn (IIR_TXRDY);\n\telse if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)\n\t\treturn (IIR_MLSC);\n\telse\n\t\treturn (IIR_NOPEND);\n}\n\nstatic void\nuart_reset(struct uart_softc *sc)\n{\n\tuint16_t divisor;\n\n\tdivisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;\n\tsc->dll = (uint8_t) divisor;\n\tsc->dlh = (uint8_t) (divisor >> 16);\n\n\trxfifo_reset(sc, 1);\t/* no fifo until enabled by software */\n}\n\n/*\n * Toggle the COM port's intr pin depending on whether or not we have an\n * interrupt condition to report to the processor.\n */\nstatic void\nuart_toggle_intr(struct uart_softc *sc)\n{\n\tuint8_t intr_reason;\n\n\tintr_reason = (uint8_t) uart_intr_reason(sc);\n\n\tif (intr_reason == IIR_NOPEND)\n\t\t(*sc->intr_deassert)(sc->arg);\n\telse\n\t\t(*sc->intr_assert)(sc->arg);\n}\n\nstatic void\nuart_drain(int fd, enum ev_type ev, void *arg)\n{\n\tstruct uart_softc *sc;\n\tint ch;\n\n\tsc = arg;\n\n\tassert(fd == sc->tty.fd);\n\tassert(ev == EVF_READ);\n\n\t/*\n\t * This routine is called in the context of the mevent thread\n\t * to take out the softc lock to protect against concurrent\n\t * access from a vCPU i/o exit\n\t */\n\tpthread_mutex_lock(&sc->mtx);\n\n\tif ((sc->mcr & MCR_LOOPBACK) != 0) {\n\t\t(void) ttyread(&sc->tty);\n\t} else {\n\t\twhile (rxfifo_available(sc) &&\n\t\t       ((ch = ttyread(&sc->tty)) != -1)) {\n\t\t\trxfifo_putchar(sc, ((uint8_t) ch));\n\t\t}\n\t\tuart_toggle_intr(sc);\n\t}\n\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\nvoid\nuart_write(struct uart_softc *sc, int offset, uint8_t value)\n{\n\tint fifosz;\n\tuint8_t msr;\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\t/*\n\t * Take care of the special case DLAB accesses first\n\t */\n\tif ((sc->lcr & LCR_DLAB) != 0) {\n\t\tif (offset == REG_DLL) {\n\t\t\tsc->dll = value;\n\t\t\tgoto done;\n\t\t}\n\n\t\tif (offset == REG_DLH) {\n\t\t\tsc->dlh = value;\n\t\t\tgoto done;\n\t\t}\n\t}\n\n        switch (offset) {\n\tcase REG_DATA:\n\t\tif (sc->mcr & MCR_LOOPBACK) {\n\t\t\tif (rxfifo_putchar(sc, value) != 0)\n\t\t\t\tsc->lsr |= LSR_OE;\n\t\t} else if (sc->tty.opened) {\n\t\t\tttywrite(&sc->tty, value);\n\t\t} /* else drop on floor */\n\t\tsc->thre_int_pending = true;\n\t\tbreak;\n\tcase REG_IER:\n\t\t/*\n\t\t * Apply mask so that bits 4-7 are 0\n\t\t * Also enables bits 0-3 only if they're 1\n\t\t */\n\t\tsc->ier = value & 0x0F;\n\t\tbreak;\n\t\tcase REG_FCR:\n\t\t\t/*\n\t\t\t * When moving from FIFO and 16450 mode and vice versa,\n\t\t\t * the FIFO contents are reset.\n\t\t\t */\n\t\t\tif ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {\n\t\t\t\tfifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;\n\t\t\t\trxfifo_reset(sc, fifosz);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * The FCR_ENABLE bit must be '1' for the programming\n\t\t\t * of other FCR bits to be effective.\n\t\t\t */\n\t\t\tif ((value & FCR_ENABLE) == 0) {\n\t\t\t\tsc->fcr = 0;\n\t\t\t} else {\n\t\t\t\tif ((value & FCR_RCV_RST) != 0)\n\t\t\t\t\trxfifo_reset(sc, FIFOSZ);\n\n\t\t\t\tsc->fcr = value &\n\t\t\t\t\t (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase REG_LCR:\n\t\t\tsc->lcr = value;\n\t\t\tbreak;\n\t\tcase REG_MCR:\n\t\t\t/* Apply mask so that bits 5-7 are 0 */\n\t\t\tsc->mcr = value & 0x1F;\n\n\t\t\tmsr = 0;\n\t\t\tif (sc->mcr & MCR_LOOPBACK) {\n\t\t\t\t/*\n\t\t\t\t * In the loopback mode certain bits from the\n\t\t\t\t * MCR are reflected back into MSR\n\t\t\t\t */\n\t\t\t\tif (sc->mcr & MCR_RTS)\n\t\t\t\t\tmsr |= MSR_CTS;\n\t\t\t\tif (sc->mcr & MCR_DTR)\n\t\t\t\t\tmsr |= MSR_DSR;\n\t\t\t\tif (sc->mcr & MCR_OUT1)\n\t\t\t\t\tmsr |= MSR_RI;\n\t\t\t\tif (sc->mcr & MCR_OUT2)\n\t\t\t\t\tmsr |= MSR_DCD;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Detect if there has been any change between the\n\t\t\t * previous and the new value of MSR. If there is\n\t\t\t * then assert the appropriate MSR delta bit.\n\t\t\t */\n\t\t\tif ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))\n\t\t\t\tsc->msr |= MSR_DCTS;\n\t\t\tif ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))\n\t\t\t\tsc->msr |= MSR_DDSR;\n\t\t\tif ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))\n\t\t\t\tsc->msr |= MSR_DDCD;\n\t\t\tif ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)\n\t\t\t\tsc->msr |= MSR_TERI;\n\n\t\t\t/*\n\t\t\t * Update the value of MSR while retaining the delta\n\t\t\t * bits.\n\t\t\t */\n\t\t\tsc->msr &= MSR_DELTA_MASK;\n\t\t\tsc->msr |= msr;\n\t\t\tbreak;\n\t\tcase REG_LSR:\n\t\t\t/*\n\t\t\t * Line status register is not meant to be written to\n\t\t\t * during normal operation.\n\t\t\t */\n\t\t\tbreak;\n\t\tcase REG_MSR:\n\t\t\t/*\n\t\t\t * As far as I can tell MSR is a read-only register.\n\t\t\t */\n\t\t\tbreak;\n\t\tcase REG_SCR:\n\t\t\tsc->scr = value;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\ndone:\n\tuart_toggle_intr(sc);\n\tpthread_mutex_unlock(&sc->mtx);\n}\n\nuint8_t\nuart_read(struct uart_softc *sc, int offset)\n{\n\tuint8_t iir, intr_reason, reg;\n\n\tpthread_mutex_lock(&sc->mtx);\n\n\t/*\n\t * Take care of the special case DLAB accesses first\n\t */\n\tif ((sc->lcr & LCR_DLAB) != 0) {\n\t\tif (offset == REG_DLL) {\n\t\t\treg = sc->dll;\n\t\t\tgoto done;\n\t\t}\n\n\t\tif (offset == REG_DLH) {\n\t\t\treg = sc->dlh;\n\t\t\tgoto done;\n\t\t}\n\t}\n\n\tswitch (offset) {\n\tcase REG_DATA:\n\t\treg = (uint8_t) rxfifo_getchar(sc);\n\t\tbreak;\n\tcase REG_IER:\n\t\treg = sc->ier;\n\t\tbreak;\n\tcase REG_IIR:\n\t\tiir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;\n\n\t\tintr_reason = (uint8_t) uart_intr_reason(sc);\n\n\t\t/*\n\t\t * Deal with side effects of reading the IIR register\n\t\t */\n\t\tif (intr_reason == IIR_TXRDY)\n\t\t\tsc->thre_int_pending = false;\n\n\t\tiir |= intr_reason;\n\n\t\treg = iir;\n\t\tbreak;\n\tcase REG_LCR:\n\t\treg = sc->lcr;\n\t\tbreak;\n\tcase REG_MCR:\n\t\treg = sc->mcr;\n\t\tbreak;\n\tcase REG_LSR:\n\t\t/* Transmitter is always ready for more data */\n\t\tsc->lsr |= LSR_TEMT | LSR_THRE;\n\n\t\t/* Check for new receive data */\n\t\tif (rxfifo_numchars(sc) > 0)\n\t\t\tsc->lsr |= LSR_RXRDY;\n\t\telse\n\t\t\tsc->lsr &= ~LSR_RXRDY;\n\n\t\treg = sc->lsr;\n\n\t\t/* The LSR_OE bit is cleared on LSR read */\n\t\tsc->lsr &= ~LSR_OE;\n\t\tbreak;\n\tcase REG_MSR:\n\t\t/*\n\t\t * MSR delta bits are cleared on read\n\t\t */\n\t\treg = sc->msr;\n\t\tsc->msr &= ~MSR_DELTA_MASK;\n\t\tbreak;\n\tcase REG_SCR:\n\t\treg = sc->scr;\n\t\tbreak;\n\tdefault:\n\t\treg = 0xFF;\n\t\tbreak;\n\t}\n\ndone:\n\tuart_toggle_intr(sc);\n\tpthread_mutex_unlock(&sc->mtx);\n\n\treturn (reg);\n}\n\nint\nuart_legacy_alloc(int which, int *baseaddr, int *irq)\n{\n\n\tif ((which < 0) || (((unsigned) which) >= UART_NLDEVS) ||\n\t\tuart_lres[which].inuse)\n\t{\n\t\treturn (-1);\n\t}\n\n\tuart_lres[which].inuse = true;\n\t*baseaddr = uart_lres[which].baseaddr;\n\t*irq = uart_lres[which].irq;\n\n\treturn (0);\n}\n\nstruct uart_softc *\nuart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,\n    void *arg)\n{\n\tstruct uart_softc *sc;\n\n\tsc = calloc(1, sizeof(struct uart_softc));\n\n\tsc->arg = arg;\n\tsc->intr_assert = intr_assert;\n\tsc->intr_deassert = intr_deassert;\n\n\tpthread_mutex_init(&sc->mtx, NULL);\n\n\tuart_reset(sc);\n\n\treturn (sc);\n}\n\nstatic int\nuart_tty_backend(struct uart_softc *sc, const char *backend)\n{\n\tint fd;\n\tint retval;\n\n\tretval = -1;\n\n\tfd = open(backend, O_RDWR | O_NONBLOCK);\n\tif (fd > 0 && isatty(fd)) {\n\t\tsc->tty.fd = fd;\n\t\tsc->tty.opened = true;\n\t\tretval = 0;\n\t}\n\n\treturn (retval);\n}\n\nint\nuart_set_backend(struct uart_softc *sc, const char *backend, const char *devname)\n{\n\tint retval;\n\tint ptyfd;\n\tchar *ptyname;\n\n\tretval = -1;\n\n\tif (backend == NULL)\n\t\treturn (0);\n\n\tif (strcmp(\"stdio\", backend) == 0 && !uart_stdio) {\n\t\tsc->tty.fd = STDIN_FILENO;\n\t\tsc->tty.opened = true;\n\t\tuart_stdio = true;\n\t\tretval = fcntl(sc->tty.fd, F_SETFL, O_NONBLOCK);\n\t} else if (strcmp(\"autopty\", backend) == 0) {\n\t\tif ((ptyfd = open(\"/dev/ptmx\", O_RDWR | O_NONBLOCK)) == -1) {\n\t\t\tfprintf(stderr, \"error opening /dev/ptmx char device\");\n\t\t\treturn retval;\n\t\t}\n\n\t\tif ((ptyname = ptsname(ptyfd)) == NULL) {\n\t\t\tperror(\"ptsname: error getting name for slave pseudo terminal\");\n\t\t\treturn retval;\n\t\t}\n\n\t\tif ((retval = grantpt(ptyfd)) == -1) {\n\t\t\tperror(\"error setting up ownership and permissions on slave pseudo terminal\");\n\t\t\treturn retval;\n\t\t}\n\n\t\tif ((retval = unlockpt(ptyfd)) == -1) {\n\t\t\tperror(\"error unlocking slave pseudo terminal, to allow its usage\");\n\t\t\treturn retval;\n\t\t}\n\n\t\tfprintf(stdout, \"%s connected to %s\\n\", devname, ptyname);\n\t\tsc->tty.fd = ptyfd;\n\t\tsc->tty.name = ptyname;\n\t\tsc->tty.opened = true;\n\t\tretval = 0;\n\t} else if (uart_tty_backend(sc, backend) == 0) {\n\t\tretval = 0;\n\t}\n\n\tif (retval == 0)\n\t\tuart_opentty(sc);\n\n\treturn (retval);\n}\n"
  },
  {
    "path": "src/vga.c",
    "content": "/*-\n * Copyright (c) 2015 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <sys/cdefs.h>\n\n#include <sys/param.h>\n\n#include <assert.h>\n#include <pthread.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <xhyve/vmm/vmm.h>\n\n#include <xhyve/bhyvegc.h>\n#include <xhyve/console.h>\n#include <xhyve/inout.h>\n#include <xhyve/mem.h>\n#include <xhyve/vga.h>\n\n#define\tKB\t(1024UL)\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n\nstruct vga_softc {\n\tstruct mem_range\tmr;\n\n\tstruct bhyvegc\t\t*gc;\n\tuint16_t\t\t\tgc_width;\n\tuint16_t\t\t\tgc_height;\n\tstruct bhyvegc_image\t*gc_image;\n\n\tuint8_t\t\t\t*vga_ram;\n\n\t/*\n\t * General registers\n\t */\n\tuint8_t\t\t\tvga_misc;\n\tuint8_t\t\t\tvga_sts1;\n\n\t/*\n\t * Sequencer\n\t */\n\tstruct {\n\t\tint\t\tseq_index;\n\t\tuint8_t\t\tseq_reset;\n\t\tuint8_t\t\tseq_clock_mode;\n\t\tint\t\tseq_cm_dots;\n\t\tuint8_t\t\tseq_map_mask;\n\t\tuint8_t\t\tseq_cmap_sel;\n\t\tint\t\tseq_cmap_pri_off;\n\t\tint\t\tseq_cmap_sec_off;\n\t\tuint8_t\t\tseq_mm;\n\t} vga_seq;\n\n\t/*\n\t * CRT Controller\n\t */\n\tstruct {\n\t\tint\t\tcrtc_index;\n\t\tuint8_t\t\tcrtc_mode_ctrl;\n\t\tuint8_t\t\tcrtc_horiz_total;\n\t\tuint8_t\t\tcrtc_horiz_disp_end;\n\t\tuint8_t\t\tcrtc_start_horiz_blank;\n\t\tuint8_t\t\tcrtc_end_horiz_blank;\n\t\tuint8_t\t\tcrtc_start_horiz_retrace;\n\t\tuint8_t\t\tcrtc_end_horiz_retrace;\n\t\tuint8_t\t\tcrtc_vert_total;\n\t\tuint8_t\t\tcrtc_overflow;\n\t\tuint8_t\t\tcrtc_present_row_scan;\n\t\tuint8_t\t\tcrtc_max_scan_line;\n\t\tuint8_t\t\tcrtc_cursor_start;\n\t\tuint8_t\t\tcrtc_cursor_on;\n\t\tuint8_t\t\tcrtc_cursor_end;\n\t\tuint8_t\t\tcrtc_start_addr_high;\n\t\tuint8_t\t\tcrtc_start_addr_low;\n\t\tuint16_t\tcrtc_start_addr;\n\t\tuint8_t\t\tcrtc_cursor_loc_low;\n\t\tuint8_t\t\tcrtc_cursor_loc_high;\n\t\tuint16_t\tcrtc_cursor_loc;\n\t\tuint8_t\t\tcrtc_vert_retrace_start;\n\t\tuint8_t\t\tcrtc_vert_retrace_end;\n\t\tuint8_t\t\tcrtc_vert_disp_end;\n\t\tuint8_t\t\tcrtc_offset;\n\t\tuint8_t\t\tcrtc_underline_loc;\n\t\tuint8_t\t\tcrtc_start_vert_blank;\n\t\tuint8_t\t\tcrtc_end_vert_blank;\n\t\tuint8_t\t\tcrtc_line_compare;\n\t} vga_crtc;\n\n\t/*\n\t * Graphics Controller\n\t */\n\tstruct {\n\t\tint\t\tgc_index;\n\t\tuint8_t\t\tgc_set_reset;\n\t\tuint8_t\t\tgc_enb_set_reset;\n\t\tuint8_t\t\tgc_color_compare;\n\t\tuint8_t\t\tgc_rotate;\n\t\tuint8_t\t\tgc_op;\n\t\tuint8_t\t\tgc_read_map_sel;\n\t\tuint8_t\t\tgc_mode;\n\t\tbool\t\tgc_mode_c4;\t\t/* chain 4 */\n\t\tbool\t\tgc_mode_oe;\t\t/* odd/even */\n\t\tuint8_t\t\tgc_mode_rm;\t\t/* read mode */\n\t\tuint8_t\t\tgc_mode_wm;\t\t/* write mode */\n\t\tuint8_t\t\tgc_misc;\n\t\tuint8_t\t\tgc_misc_gm;\t\t/* graphics mode */\n\t\tuint8_t\t\tgc_misc_mm;\t\t/* memory map */\n\t\tuint8_t\t\tgc_color_dont_care;\n\t\tuint8_t\t\tgc_bit_mask;\n\t\tuint8_t\t\tgc_latch0;\n\t\tuint8_t\t\tgc_latch1;\n\t\tuint8_t\t\tgc_latch2;\n\t\tuint8_t\t\tgc_latch3;\n\t} vga_gc;\n\n\t/*\n\t * Attribute Controller\n\t */\n\tstruct {\n\t\tint\t\tatc_flipflop;\n\t\tint\t\tatc_index;\n\t\tuint8_t\t\tatc_palette[16];\n\t\tuint8_t\t\tatc_mode;\n\t\tuint8_t\t\tatc_overscan_color;\n\t\tuint8_t\t\tatc_color_plane_enb;\n\t\tuint8_t\t\tatc_horiz_pixel_panning;\n\t\tuint8_t\t\tatc_color_select;\n\t\tuint8_t\t\tatc_color_select_45;\n\t\tuint8_t\t\tatc_color_select_67;\n\t} vga_atc;\n\n\t/*\n\t * DAC\n\t */\n\tstruct {\n\t\tuint8_t\t\tdac_state;\n\t\tuint8_t\t\tdac_rd_index;\n\t\tuint8_t\t\tdac_rd_subindex;\n\t\tuint8_t\t\tdac_wr_index;\n\t\tuint8_t\t\tdac_wr_subindex;\n\t\tuint8_t\t\tdac_palette[3 * 256];\n\t\tuint32_t\tdac_palette_rgb[256];\n\t} vga_dac;\n};\n\n#pragma clang diagnostic pop\n\nstatic bool\nvga_in_reset(struct vga_softc *sc)\n{\n\treturn (((sc->vga_seq.seq_clock_mode & SEQ_CM_SO) != 0) ||\n\t    ((sc->vga_seq.seq_reset & SEQ_RESET_ASYNC) == 0) ||\n\t    ((sc->vga_seq.seq_reset & SEQ_RESET_SYNC) == 0) ||\n\t    ((sc->vga_crtc.crtc_mode_ctrl & CRTC_MC_TE) == 0));\n}\n\nstatic void\nvga_check_size(struct bhyvegc *gc, struct vga_softc *sc)\n{\n\tint old_width, old_height;\n\n\tif (vga_in_reset(sc))\n\t\treturn;\n\n\t//old_width = sc->gc_width;\n\t//old_height = sc->gc_height;\n\told_width = sc->gc_image->width;\n\told_height = sc->gc_image->height;\n\n\t/*\n\t * Horizontal Display End: For text modes this is the number\n\t * of characters.  For graphics modes this is the number of\n\t * pixels per scanlines divided by the number of pixels per\n\t * character clock.\n\t */\n\tsc->gc_width = (uint16_t)((sc->vga_crtc.crtc_horiz_disp_end + 1) *\n\t    sc->vga_seq.seq_cm_dots);\n\n\tsc->gc_height = (uint16_t)((sc->vga_crtc.crtc_vert_disp_end |\n\t    (((sc->vga_crtc.crtc_overflow & CRTC_OF_VDE8) >> CRTC_OF_VDE8_SHIFT) << 8) |\n\t    (((sc->vga_crtc.crtc_overflow & CRTC_OF_VDE9) >> CRTC_OF_VDE9_SHIFT) << 9)) + 1);\n\n\tif (old_width != sc->gc_width || old_height != sc->gc_height)\n\t\tbhyvegc_resize(gc, sc->gc_width, sc->gc_height);\n}\n\nstatic uint32_t\nvga_get_pixel(struct vga_softc *sc, uint16_t x, uint16_t y)\n{\n\tunsigned int offset;\n\tint bit;\n\tuint8_t data;\n\tuint8_t idx;\n\n\toffset = (y * sc->gc_width / 8) + (x / 8);\n\tbit = 7 - (x % 8);\n\n\tdata = (uint8_t)(((sc->vga_ram[offset + 0 * 64*KB] >> bit) & 0x1) << 0) |\n\t\t(uint8_t)(((sc->vga_ram[offset + 1 * 64*KB] >> bit) & 0x1) << 1) |\n\t\t(uint8_t)(((sc->vga_ram[offset + 2 * 64*KB] >> bit) & 0x1) << 2) |\n\t\t(uint8_t)(((sc->vga_ram[offset + 3 * 64*KB] >> bit) & 0x1) << 3);\n\n\tdata &= sc->vga_atc.atc_color_plane_enb;\n\n\tif (sc->vga_atc.atc_mode & ATC_MC_IPS) {\n\t\tidx = sc->vga_atc.atc_palette[data] & 0x0f;\n\t\tidx |= sc->vga_atc.atc_color_select_45;\n\t} else {\n\t\tidx = sc->vga_atc.atc_palette[data];\n\t}\n\tidx |= sc->vga_atc.atc_color_select_67;\n\n\treturn (sc->vga_dac.dac_palette_rgb[idx]);\n}\n\nstatic void\nvga_render_graphics(struct vga_softc *sc)\n{\n\tuint16_t x, y;\n\n\tfor (y = 0; y < sc->gc_height; y++) {\n\t\tfor (x = 0; x < sc->gc_width; x++) {\n\t\t\tint offset;\n\n\t\t\toffset = y * sc->gc_width + x;\n\t\t\tsc->gc_image->data[offset] = vga_get_pixel(sc, x, y);\n\t\t}\n\t}\n}\n\nstatic uint32_t\nvga_get_text_pixel(struct vga_softc *sc, uint16_t x, uint16_t y)\n{\n\tint bit;\n    unsigned int dots, offset, font_offset;\n\tuint8_t ch, attr, font;\n\tuint8_t idx;\n\n    assert(sc->vga_seq.seq_cm_dots >= 0);\n\tdots = (unsigned int)sc->vga_seq.seq_cm_dots;\n\n\toffset = 2 * sc->vga_crtc.crtc_start_addr;\n\toffset += (y / 16 * sc->gc_width / dots) * 2 + (x / dots) * 2;\n\n\tbit = 7 - (x % dots > 7 ? 7 : x % dots);\n\n\tch = sc->vga_ram[offset + 0 * 64*KB];\n\tattr = sc->vga_ram[offset + 1 * 64*KB];\n\n\tif (sc->vga_crtc.crtc_cursor_on &&\n\t    (offset == (sc->vga_crtc.crtc_cursor_loc * 2)) &&\n\t    ((y % 16) >= (sc->vga_crtc.crtc_cursor_start & CRTC_CS_CS)) &&\n\t    ((y % 16) <= (sc->vga_crtc.crtc_cursor_end & CRTC_CE_CE))) {\n\t\tidx = sc->vga_atc.atc_palette[attr & 0xf];\n\t\treturn (sc->vga_dac.dac_palette_rgb[idx]);\n\t}\n\n\tif ((sc->vga_seq.seq_mm & SEQ_MM_EM) &&\n\t    sc->vga_seq.seq_cmap_pri_off != sc->vga_seq.seq_cmap_sec_off) {\n\t\tif (attr & 0x8)\n\t\t\tfont_offset = (unsigned int)sc->vga_seq.seq_cmap_pri_off +\n\t\t\t\t(unsigned int)(ch << 5) + y % 16;\n\t\telse\n\t\t\tfont_offset = (unsigned int)sc->vga_seq.seq_cmap_sec_off +\n\t\t\t\t(unsigned int)(ch << 5) + y % 16;\n\t\tattr &= ~0x8;\n\t} else {\n\t\tfont_offset = (unsigned int)(ch << 5) + y % 16;\n\t}\n\n\tfont = sc->vga_ram[font_offset + 2 * 64*KB];\n\n\tif (font & (1 << bit))\n\t\tidx = sc->vga_atc.atc_palette[attr & 0xf];\n\telse\n\t\tidx = sc->vga_atc.atc_palette[attr >> 4];\n\n\treturn (sc->vga_dac.dac_palette_rgb[idx]);\n}\n\nstatic void\nvga_render_text(struct vga_softc *sc)\n{\n\tuint16_t x, y;\n\n\tfor (y = 0; y < sc->gc_height; y++) {\n\t\tfor (x = 0; x < sc->gc_width; x++) {\n\t\t\tint offset;\n\n\t\t\toffset = y * sc->gc_width + x;\n\t\t\tsc->gc_image->data[offset] = vga_get_text_pixel(sc, x, y);\n\t\t}\n\t}\n}\n\nvoid\nvga_render(struct bhyvegc *gc, void *arg)\n{\n\tstruct vga_softc *sc = arg;\n\n\tvga_check_size(gc, sc);\n\n\tif (vga_in_reset(sc)) {\n\t\tmemset(sc->gc_image->data, 0,\n\t\t    sc->gc_image->width * sc->gc_image->height *\n\t\t     sizeof (uint32_t));\n\t\treturn;\n\t}\n\n\tif (sc->vga_gc.gc_misc_gm && (sc->vga_atc.atc_mode & ATC_MC_GA))\n\t\tvga_render_graphics(sc);\n\telse\n\t\tvga_render_text(sc);\n}\n\nstatic uint64_t\nvga_mem_rd_handler(uint64_t addr, void *arg1)\n{\n\tstruct vga_softc *sc = arg1;\n\tuint8_t map_sel;\n\tuint64_t offset;\n\n\toffset = addr;\n\tswitch (sc->vga_gc.gc_misc_mm) {\n\tcase 0x0:\n\t\t/*\n\t\t * extended mode: base 0xa0000 size 128k\n\t\t */\n\t\toffset -=0xa0000;\n\t\toffset &= (128 * KB - 1);\n\t\tbreak;\n\tcase 0x1:\n\t\t/*\n\t\t * EGA/VGA mode: base 0xa0000 size 64k\n\t\t */\n\t\toffset -=0xa0000;\n\t\toffset &= (64 * KB - 1);\n\t\tbreak;\n\tcase 0x2:\n\t\t/*\n\t\t * monochrome text mode: base 0xb0000 size 32kb\n\t\t */\n\t\tassert(0);\n\tcase 0x3:\n\t\t/*\n\t\t * color text mode and CGA: base 0xb8000 size 32kb\n\t\t */\n\t\toffset -=0xb8000;\n\t\toffset &= (32 * KB - 1);\n\t\tbreak;\n\t}\n\n\t/* Fill latches. */\n\tsc->vga_gc.gc_latch0 = sc->vga_ram[offset + 0*64*KB];\n\tsc->vga_gc.gc_latch1 = sc->vga_ram[offset + 1*64*KB];\n\tsc->vga_gc.gc_latch2 = sc->vga_ram[offset + 2*64*KB];\n\tsc->vga_gc.gc_latch3 = sc->vga_ram[offset + 3*64*KB];\n\n\tif (sc->vga_gc.gc_mode_rm) {\n\t\t/* read mode 1 */\n\t\tassert(0);\n\t}\n\n\tmap_sel = sc->vga_gc.gc_read_map_sel;\n\tif (sc->vga_gc.gc_mode_oe) {\n\t\tmap_sel |= (offset & 1);\n\t\toffset &= (uint64_t)~1;\n\t}\n\n\t/* read mode 0: return the byte from the selected plane. */\n\toffset += map_sel * 64*KB;\n\n\treturn (sc->vga_ram[offset]);\n}\n\nstatic void\nvga_mem_wr_handler(uint64_t addr, uint8_t val, void *arg1)\n{\n\tstruct vga_softc *sc = arg1;\n\tuint8_t c0, c1, c2, c3;\n\tuint8_t m0, m1, m2, m3;\n\tuint8_t set_reset;\n\tuint8_t enb_set_reset;\n\tuint8_t\tmask;\n\tuint64_t offset;\n\n\toffset = addr;\n\tswitch (sc->vga_gc.gc_misc_mm) {\n\tcase 0x0:\n\t\t/*\n\t\t * extended mode: base 0xa0000 size 128kb\n\t\t */\n\t\toffset -=0xa0000;\n\t\toffset &= (128 * KB - 1);\n\t\tbreak;\n\tcase 0x1:\n\t\t/*\n\t\t * EGA/VGA mode: base 0xa0000 size 64kb\n\t\t */\n\t\toffset -=0xa0000;\n\t\toffset &= (64 * KB - 1);\n\t\tbreak;\n\tcase 0x2:\n\t\t/*\n\t\t * monochrome text mode: base 0xb0000 size 32kb\n\t\t */\n\t\tassert(0);\n\tcase 0x3:\n\t\t/*\n\t\t * color text mode and CGA: base 0xb8000 size 32kb\n\t\t */\n\t\toffset -=0xb8000;\n\t\toffset &= (32 * KB - 1);\n\t\tbreak;\n\t}\n\n\tset_reset = sc->vga_gc.gc_set_reset;\n\tenb_set_reset = sc->vga_gc.gc_enb_set_reset;\n\n\tc0 = sc->vga_gc.gc_latch0;\n\tc1 = sc->vga_gc.gc_latch1;\n\tc2 = sc->vga_gc.gc_latch2;\n\tc3 = sc->vga_gc.gc_latch3;\n\n\tswitch (sc->vga_gc.gc_mode_wm) {\n\tcase 0:\n\t\t/* write mode 0 */\n\t\tmask = sc->vga_gc.gc_bit_mask;\n\n\t\tval = (uint8_t)(val >> sc->vga_gc.gc_rotate) |\n\t\t    (uint8_t)(val << (8 - sc->vga_gc.gc_rotate));\n\n\t\tswitch (sc->vga_gc.gc_op) {\n\t\tcase 0x00:\t\t/* replace */\n\t\t\tm0 = (set_reset & 1) ? mask : 0x00;\n\t\t\tm1 = (set_reset & 2) ? mask : 0x00;\n\t\t\tm2 = (set_reset & 4) ? mask : 0x00;\n\t\t\tm3 = (set_reset & 8) ? mask : 0x00;\n\n\t\t\tc0 = (enb_set_reset & 1) ? (c0 & ~mask) : (val & mask);\n\t\t\tc1 = (enb_set_reset & 2) ? (c1 & ~mask) : (val & mask);\n\t\t\tc2 = (enb_set_reset & 4) ? (c2 & ~mask) : (val & mask);\n\t\t\tc3 = (enb_set_reset & 8) ? (c3 & ~mask) : (val & mask);\n\n\t\t\tc0 |= m0;\n\t\t\tc1 |= m1;\n\t\t\tc2 |= m2;\n\t\t\tc3 |= m3;\n\t\t\tbreak;\n\t\tcase 0x08:\t\t/* AND */\n\t\t\tm0 = set_reset & 1 ? 0xff : ~mask;\n\t\t\tm1 = set_reset & 2 ? 0xff : ~mask;\n\t\t\tm2 = set_reset & 4 ? 0xff : ~mask;\n\t\t\tm3 = set_reset & 8 ? 0xff : ~mask;\n\n\t\t\tc0 = enb_set_reset & 1 ? c0 & m0 : val & m0;\n\t\t\tc1 = enb_set_reset & 2 ? c1 & m1 : val & m1;\n\t\t\tc2 = enb_set_reset & 4 ? c2 & m2 : val & m2;\n\t\t\tc3 = enb_set_reset & 8 ? c3 & m3 : val & m3;\n\t\t\tbreak;\n\t\tcase 0x10:\t\t/* OR */\n\t\t\tm0 = set_reset & 1 ? mask : 0x00;\n\t\t\tm1 = set_reset & 2 ? mask : 0x00;\n\t\t\tm2 = set_reset & 4 ? mask : 0x00;\n\t\t\tm3 = set_reset & 8 ? mask : 0x00;\n\n\t\t\tc0 = enb_set_reset & 1 ? c0 | m0 : val | m0;\n\t\t\tc1 = enb_set_reset & 2 ? c1 | m1 : val | m1;\n\t\t\tc2 = enb_set_reset & 4 ? c2 | m2 : val | m2;\n\t\t\tc3 = enb_set_reset & 8 ? c3 | m3 : val | m3;\n\t\t\tbreak;\n\t\tcase 0x18:\t\t/* XOR */\n\t\t\tm0 = set_reset & 1 ? mask : 0x00;\n\t\t\tm1 = set_reset & 2 ? mask : 0x00;\n\t\t\tm2 = set_reset & 4 ? mask : 0x00;\n\t\t\tm3 = set_reset & 8 ? mask : 0x00;\n\n\t\t\tc0 = enb_set_reset & 1 ? c0 ^ m0 : val ^ m0;\n\t\t\tc1 = enb_set_reset & 2 ? c1 ^ m1 : val ^ m1;\n\t\t\tc2 = enb_set_reset & 4 ? c2 ^ m2 : val ^ m2;\n\t\t\tc3 = enb_set_reset & 8 ? c3 ^ m3 : val ^ m3;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 1:\n\t\t/* write mode 1 */\n\t\tbreak;\n\tcase 2:\n\t\t/* write mode 2 */\n\t\tmask = sc->vga_gc.gc_bit_mask;\n\n\t\tswitch (sc->vga_gc.gc_op) {\n\t\tcase 0x00:\t\t/* replace */\n\t\t\tm0 = (val & 1 ? 0xff : 0x00) & mask;\n\t\t\tm1 = (val & 2 ? 0xff : 0x00) & mask;\n\t\t\tm2 = (val & 4 ? 0xff : 0x00) & mask;\n\t\t\tm3 = (val & 8 ? 0xff : 0x00) & mask;\n\n\t\t\tc0 &= ~mask;\n\t\t\tc1 &= ~mask;\n\t\t\tc2 &= ~mask;\n\t\t\tc3 &= ~mask;\n\n\t\t\tc0 |= m0;\n\t\t\tc1 |= m1;\n\t\t\tc2 |= m2;\n\t\t\tc3 |= m3;\n\t\t\tbreak;\n\t\tcase 0x08:\t\t/* AND */\n\t\t\tm0 = (val & 1 ? 0xff : 0x00) | ~mask;\n\t\t\tm1 = (val & 2 ? 0xff : 0x00) | ~mask;\n\t\t\tm2 = (val & 4 ? 0xff : 0x00) | ~mask;\n\t\t\tm3 = (val & 8 ? 0xff : 0x00) | ~mask;\n\n\t\t\tc0 &= m0;\n\t\t\tc1 &= m1;\n\t\t\tc2 &= m2;\n\t\t\tc3 &= m3;\n\t\t\tbreak;\n\t\tcase 0x10:\t\t/* OR */\n\t\t\tm0 = (val & 1 ? 0xff : 0x00) & mask;\n\t\t\tm1 = (val & 2 ? 0xff : 0x00) & mask;\n\t\t\tm2 = (val & 4 ? 0xff : 0x00) & mask;\n\t\t\tm3 = (val & 8 ? 0xff : 0x00) & mask;\n\n\t\t\tc0 |= m0;\n\t\t\tc1 |= m1;\n\t\t\tc2 |= m2;\n\t\t\tc3 |= m3;\n\t\t\tbreak;\n\t\tcase 0x18:\t\t/* XOR */\n\t\t\tm0 = (val & 1 ? 0xff : 0x00) & mask;\n\t\t\tm1 = (val & 2 ? 0xff : 0x00) & mask;\n\t\t\tm2 = (val & 4 ? 0xff : 0x00) & mask;\n\t\t\tm3 = (val & 8 ? 0xff : 0x00) & mask;\n\n\t\t\tc0 ^= m0;\n\t\t\tc1 ^= m1;\n\t\t\tc2 ^= m2;\n\t\t\tc3 ^= m3;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 3:\n\t\t/* write mode 3 */\n\t\tmask = sc->vga_gc.gc_bit_mask & val;\n\n\t\tval = (uint8_t)(val >> sc->vga_gc.gc_rotate) |\n\t\t    (uint8_t)(val << (8 - sc->vga_gc.gc_rotate));\n\n\t\tswitch (sc->vga_gc.gc_op) {\n\t\tcase 0x00:\t\t/* replace */\n\t\t\tm0 = (set_reset & 1 ? 0xff : 0x00) & mask;\n\t\t\tm1 = (set_reset & 2 ? 0xff : 0x00) & mask;\n\t\t\tm2 = (set_reset & 4 ? 0xff : 0x00) & mask;\n\t\t\tm3 = (set_reset & 8 ? 0xff : 0x00) & mask;\n\n\t\t\tc0 &= ~mask;\n\t\t\tc1 &= ~mask;\n\t\t\tc2 &= ~mask;\n\t\t\tc3 &= ~mask;\n\n\t\t\tc0 |= m0;\n\t\t\tc1 |= m1;\n\t\t\tc2 |= m2;\n\t\t\tc3 |= m3;\n\t\t\tbreak;\n\t\tcase 0x08:\t\t/* AND */\n\t\t\tm0 = (set_reset & 1 ? 0xff : 0x00) | ~mask;\n\t\t\tm1 = (set_reset & 2 ? 0xff : 0x00) | ~mask;\n\t\t\tm2 = (set_reset & 4 ? 0xff : 0x00) | ~mask;\n\t\t\tm3 = (set_reset & 8 ? 0xff : 0x00) | ~mask;\n\n\t\t\tc0 &= m0;\n\t\t\tc1 &= m1;\n\t\t\tc2 &= m2;\n\t\t\tc3 &= m3;\n\t\t\tbreak;\n\t\tcase 0x10:\t\t/* OR */\n\t\t\tm0 = (set_reset & 1 ? 0xff : 0x00) & mask;\n\t\t\tm1 = (set_reset & 2 ? 0xff : 0x00) & mask;\n\t\t\tm2 = (set_reset & 4 ? 0xff : 0x00) & mask;\n\t\t\tm3 = (set_reset & 8 ? 0xff : 0x00) & mask;\n\n\t\t\tc0 |= m0;\n\t\t\tc1 |= m1;\n\t\t\tc2 |= m2;\n\t\t\tc3 |= m3;\n\t\t\tbreak;\n\t\tcase 0x18:\t\t/* XOR */\n\t\t\tm0 = (set_reset & 1 ? 0xff : 0x00) & mask;\n\t\t\tm1 = (set_reset & 2 ? 0xff : 0x00) & mask;\n\t\t\tm2 = (set_reset & 4 ? 0xff : 0x00) & mask;\n\t\t\tm3 = (set_reset & 8 ? 0xff : 0x00) & mask;\n\n\t\t\tc0 ^= m0;\n\t\t\tc1 ^= m1;\n\t\t\tc2 ^= m2;\n\t\t\tc3 ^= m3;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\t}\n\n\tif (sc->vga_gc.gc_mode_oe) {\n\t\tif (offset & 1) {\n\t\t\toffset &= (uint64_t)~1;\n\t\t\tif (sc->vga_seq.seq_map_mask & 2)\n\t\t\t\tsc->vga_ram[offset + 1*64*KB] = c1;\n\t\t\tif (sc->vga_seq.seq_map_mask & 8)\n\t\t\t\tsc->vga_ram[offset + 3*64*KB] = c3;\n\t\t} else {\n\t\t\tif (sc->vga_seq.seq_map_mask & 1)\n\t\t\t\tsc->vga_ram[offset + 0*64*KB] = c0;\n\t\t\tif (sc->vga_seq.seq_map_mask & 4)\n\t\t\t\tsc->vga_ram[offset + 2*64*KB] = c2;\n\t\t}\n\t} else {\n\t\tif (sc->vga_seq.seq_map_mask & 1)\n\t\t\tsc->vga_ram[offset + 0*64*KB] = c0;\n\t\tif (sc->vga_seq.seq_map_mask & 2)\n\t\t\tsc->vga_ram[offset + 1*64*KB] = c1;\n\t\tif (sc->vga_seq.seq_map_mask & 4)\n\t\t\tsc->vga_ram[offset + 2*64*KB] = c2;\n\t\tif (sc->vga_seq.seq_map_mask & 8)\n\t\t\tsc->vga_ram[offset + 3*64*KB] = c3;\n\t}\n}\n\nstatic int\nvga_mem_handler(UNUSED int vcpu, int dir, uint64_t addr,\n\t\tint size, uint64_t *val, void *arg1, UNUSED long arg2)\n{\n\tif (dir == MEM_F_WRITE) {\n\t\tswitch (size) {\n\t\tcase 1:\n\t\t\tvga_mem_wr_handler(addr, (uint8_t)*val, arg1);\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tvga_mem_wr_handler(addr, (uint8_t)*val, arg1);\n\t\t\tvga_mem_wr_handler(addr + 1, (uint8_t)(*val >> 8), arg1);\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tvga_mem_wr_handler(addr, (uint8_t)*val, arg1);\n\t\t\tvga_mem_wr_handler(addr + 1, (uint8_t)(*val >> 8), arg1);\n\t\t\tvga_mem_wr_handler(addr + 2, (uint8_t)(*val >> 16), arg1);\n\t\t\tvga_mem_wr_handler(addr + 3, (uint8_t)(*val >> 24), arg1);\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tvga_mem_wr_handler(addr, (uint8_t)*val, arg1);\n\t\t\tvga_mem_wr_handler(addr + 1, (uint8_t)(*val >> 8), arg1);\n\t\t\tvga_mem_wr_handler(addr + 2, (uint8_t)(*val >> 16), arg1);\n\t\t\tvga_mem_wr_handler(addr + 3, (uint8_t)(*val >> 24), arg1);\n\t\t\tvga_mem_wr_handler(addr + 4, (uint8_t)(*val >> 32), arg1);\n\t\t\tvga_mem_wr_handler(addr + 5, (uint8_t)(*val >> 40), arg1);\n\t\t\tvga_mem_wr_handler(addr + 6, (uint8_t)(*val >> 48), arg1);\n\t\t\tvga_mem_wr_handler(addr + 7, (uint8_t)(*val >> 56), arg1);\n\t\t\tbreak;\n\t\t}\n\t} else {\n\t\tswitch (size) {\n\t\tcase 1:\n\t\t\t*val = vga_mem_rd_handler(addr, arg1);\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\t*val = vga_mem_rd_handler(addr, arg1);\n\t\t\t*val |= vga_mem_rd_handler(addr + 1, arg1) << 8;\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\t*val = vga_mem_rd_handler(addr, arg1);\n\t\t\t*val |= vga_mem_rd_handler(addr + 1, arg1) << 8;\n\t\t\t*val |= vga_mem_rd_handler(addr + 2, arg1) << 16;\n\t\t\t*val |= vga_mem_rd_handler(addr + 3, arg1) << 24;\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\t*val = vga_mem_rd_handler(addr, arg1);\n\t\t\t*val |= vga_mem_rd_handler(addr + 1, arg1) << 8;\n\t\t\t*val |= vga_mem_rd_handler(addr + 2, arg1) << 16;\n\t\t\t*val |= vga_mem_rd_handler(addr + 3, arg1) << 24;\n\t\t\t*val |= vga_mem_rd_handler(addr + 4, arg1) << 32;\n\t\t\t*val |= vga_mem_rd_handler(addr + 5, arg1) << 40;\n\t\t\t*val |= vga_mem_rd_handler(addr + 6, arg1) << 48;\n\t\t\t*val |= vga_mem_rd_handler(addr + 7, arg1) << 56;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn (0);\n}\n\nstatic int\nvga_port_in_handler(UNUSED int in, int port, UNUSED int bytes,\n\t\t    uint8_t *val, void *arg)\n{\n\tstruct vga_softc *sc = arg;\n\n\tswitch (port) {\n\tcase CRTC_IDX_MONO_PORT:\n\tcase CRTC_IDX_COLOR_PORT:\n\t\t*val = (uint8_t)sc->vga_crtc.crtc_index;\n\t\tbreak;\n\tcase CRTC_DATA_MONO_PORT:\n\tcase CRTC_DATA_COLOR_PORT:\n\t\tswitch (sc->vga_crtc.crtc_index) {\n\t\tcase CRTC_HORIZ_TOTAL:\n\t\t\t*val = sc->vga_crtc.crtc_horiz_total;\n\t\t\tbreak;\n\t\tcase CRTC_HORIZ_DISP_END:\n\t\t\t*val = sc->vga_crtc.crtc_horiz_disp_end;\n\t\t\tbreak;\n\t\tcase CRTC_START_HORIZ_BLANK:\n\t\t\t*val = sc->vga_crtc.crtc_start_horiz_blank;\n\t\t\tbreak;\n\t\tcase CRTC_END_HORIZ_BLANK:\n\t\t\t*val = sc->vga_crtc.crtc_end_horiz_blank;\n\t\t\tbreak;\n\t\tcase CRTC_START_HORIZ_RETRACE:\n\t\t\t*val = sc->vga_crtc.crtc_start_horiz_retrace;\n\t\t\tbreak;\n\t\tcase CRTC_END_HORIZ_RETRACE:\n\t\t\t*val = sc->vga_crtc.crtc_end_horiz_retrace;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_TOTAL:\n\t\t\t*val = sc->vga_crtc.crtc_vert_total;\n\t\t\tbreak;\n\t\tcase CRTC_OVERFLOW:\n\t\t\t*val = sc->vga_crtc.crtc_overflow;\n\t\t\tbreak;\n\t\tcase CRTC_PRESET_ROW_SCAN:\n\t\t\t*val = sc->vga_crtc.crtc_present_row_scan;\n\t\t\tbreak;\n\t\tcase CRTC_MAX_SCAN_LINE:\n\t\t\t*val = sc->vga_crtc.crtc_max_scan_line;\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_START:\n\t\t\t*val = sc->vga_crtc.crtc_cursor_start;\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_END:\n\t\t\t*val = sc->vga_crtc.crtc_cursor_end;\n\t\t\tbreak;\n\t\tcase CRTC_START_ADDR_HIGH:\n\t\t\t*val = sc->vga_crtc.crtc_start_addr_high;\n\t\t\tbreak;\n\t\tcase CRTC_START_ADDR_LOW:\n\t\t\t*val = sc->vga_crtc.crtc_start_addr_low;\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_LOC_HIGH:\n\t\t\t*val = sc->vga_crtc.crtc_cursor_loc_high;\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_LOC_LOW:\n\t\t\t*val = sc->vga_crtc.crtc_cursor_loc_low;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_RETRACE_START:\n\t\t\t*val = sc->vga_crtc.crtc_vert_retrace_start;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_RETRACE_END:\n\t\t\t*val = sc->vga_crtc.crtc_vert_retrace_end;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_DISP_END:\n\t\t\t*val = sc->vga_crtc.crtc_vert_disp_end;\n\t\t\tbreak;\n\t\tcase CRTC_OFFSET:\n\t\t\t*val = sc->vga_crtc.crtc_offset;\n\t\t\tbreak;\n\t\tcase CRTC_UNDERLINE_LOC:\n\t\t\t*val = sc->vga_crtc.crtc_underline_loc;\n\t\t\tbreak;\n\t\tcase CRTC_START_VERT_BLANK:\n\t\t\t*val = sc->vga_crtc.crtc_start_vert_blank;\n\t\t\tbreak;\n\t\tcase CRTC_END_VERT_BLANK:\n\t\t\t*val = sc->vga_crtc.crtc_end_vert_blank;\n\t\t\tbreak;\n\t\tcase CRTC_MODE_CONTROL:\n\t\t\t*val = sc->vga_crtc.crtc_mode_ctrl;\n\t\t\tbreak;\n\t\tcase CRTC_LINE_COMPARE:\n\t\t\t*val = sc->vga_crtc.crtc_line_compare;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t//printf(\"XXX VGA CRTC: inb 0x%04x at index %d\\n\", port, sc->vga_crtc.crtc_index);\n\t\t\tassert(0);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase ATC_IDX_PORT:\n\t\t*val = (uint8_t)sc->vga_atc.atc_index;\n\t\tbreak;\n\tcase ATC_DATA_PORT:\n\t\tswitch (sc->vga_atc.atc_index) {\n\t\tcase ATC_MODE_CONTROL:\n\t\t\t*val = sc->vga_atc.atc_mode;\n\t\t\tbreak;\n\t\tcase ATC_OVERSCAN_COLOR:\n\t\t\t*val = sc->vga_atc.atc_overscan_color;\n\t\t\tbreak;\n\t\tcase ATC_COLOR_PLANE_ENABLE:\n\t\t\t*val = sc->vga_atc.atc_color_plane_enb;\n\t\t\tbreak;\n\t\tcase ATC_HORIZ_PIXEL_PANNING:\n\t\t\t*val = sc->vga_atc.atc_horiz_pixel_panning;\n\t\t\tbreak;\n\t\tcase ATC_COLOR_SELECT:\n\t\t\t*val = sc->vga_atc.atc_color_select;\n\t\t\tbreak;\n\t\tdefault:\n            if (sc->vga_atc.atc_index >= ATC_PALETTE0 && sc->vga_atc.atc_index <= ATC_PALETTE15) {\n                *val = sc->vga_atc.atc_palette[sc->vga_atc.atc_index];\n            } else {\n                //printf(\"XXX VGA ATC inb 0x%04x at index %d\\n\", port , sc->vga_atc.atc_index);\n                assert(0);\n            }\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase SEQ_IDX_PORT:\n\t\t*val = (uint8_t)sc->vga_seq.seq_index;\n\t\tbreak;\n\tcase SEQ_DATA_PORT:\n\t\tswitch (sc->vga_seq.seq_index) {\n\t\tcase SEQ_RESET:\n\t\t\t*val = sc->vga_seq.seq_reset;\n\t\t\tbreak;\n\t\tcase SEQ_CLOCKING_MODE:\n\t\t\t*val = sc->vga_seq.seq_clock_mode;\n\t\t\tbreak;\n\t\tcase SEQ_MAP_MASK:\n\t\t\t*val = sc->vga_seq.seq_map_mask;\n\t\t\tbreak;\n\t\tcase SEQ_CHAR_MAP_SELECT:\n\t\t\t*val = sc->vga_seq.seq_cmap_sel;\n\t\t\tbreak;\n\t\tcase SEQ_MEMORY_MODE:\n\t\t\t*val = sc->vga_seq.seq_mm;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t//printf(\"XXX VGA SEQ: inb 0x%04x at index %d\\n\", port, sc->vga_seq.seq_index);\n\t\t\tassert(0);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase DAC_DATA_PORT:\n\t\t*val = sc->vga_dac.dac_palette[3 * sc->vga_dac.dac_rd_index +\n\t\t\t\t\t       sc->vga_dac.dac_rd_subindex];\n\t\tsc->vga_dac.dac_rd_subindex++;\n\t\tif (sc->vga_dac.dac_rd_subindex == 3) {\n\t\t\tsc->vga_dac.dac_rd_index++;\n\t\t\tsc->vga_dac.dac_rd_subindex = 0;\n\t\t}\n\t\tbreak;\n\tcase GC_IDX_PORT:\n\t\t*val = (uint8_t)sc->vga_gc.gc_index;\n\t\tbreak;\n\tcase GC_DATA_PORT:\n\t\tswitch (sc->vga_gc.gc_index) {\n\t\tcase GC_SET_RESET:\n\t\t\t*val = sc->vga_gc.gc_set_reset;\n\t\t\tbreak;\n\t\tcase GC_ENABLE_SET_RESET:\n\t\t\t*val = sc->vga_gc.gc_enb_set_reset;\n\t\t\tbreak;\n\t\tcase GC_COLOR_COMPARE:\n\t\t\t*val = sc->vga_gc.gc_color_compare;\n\t\t\tbreak;\n\t\tcase GC_DATA_ROTATE:\n\t\t\t*val = sc->vga_gc.gc_rotate;\n\t\t\tbreak;\n\t\tcase GC_READ_MAP_SELECT:\n\t\t\t*val = sc->vga_gc.gc_read_map_sel;\n\t\t\tbreak;\n\t\tcase GC_MODE:\n\t\t\t*val = sc->vga_gc.gc_mode;\n\t\t\tbreak;\n\t\tcase GC_MISCELLANEOUS:\n\t\t\t*val = sc->vga_gc.gc_misc;\n\t\t\tbreak;\n\t\tcase GC_COLOR_DONT_CARE:\n\t\t\t*val = sc->vga_gc.gc_color_dont_care;\n\t\t\tbreak;\n\t\tcase GC_BIT_MASK:\n\t\t\t*val = sc->vga_gc.gc_bit_mask;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t//printf(\"XXX VGA GC: inb 0x%04x at index %d\\n\", port, sc->vga_crtc.crtc_index);\n\t\t\tassert(0);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase GEN_MISC_OUTPUT_PORT:\n\t\t*val = sc->vga_misc;\n\t\tbreak;\n\tcase GEN_INPUT_STS0_PORT:\n\t\tassert(0);\n\t\tbreak;\n\tcase GEN_INPUT_STS1_MONO_PORT:\n\tcase GEN_INPUT_STS1_COLOR_PORT:\n\t\tsc->vga_atc.atc_flipflop = 0;\n\t\tsc->vga_sts1 = GEN_IS1_VR | GEN_IS1_DE;\n\t\t//sc->vga_sts1 ^= (GEN_IS1_VR | GEN_IS1_DE);\n\t\t*val = sc->vga_sts1;\n\t\tbreak;\n\tcase GEN_FEATURE_CTRL_PORT:\n\t\t// OpenBSD calls this with bytes = 1\n\t\t//assert(0);\n\t\t*val = 0;\n\t\tbreak;\n\tcase 0x3c3:\n\t\t*val = 0;\n\t\tbreak;\n\tdefault:\n\t\tprintf(\"XXX vga_port_in_handler() unhandled port 0x%x\\n\", port);\n\t\t//assert(0);\n\t\treturn (-1);\n\t}\n\n\treturn (0);\n}\n\nstatic int\nvga_port_out_handler(UNUSED int in, int port, UNUSED int bytes,\n\t\t     uint8_t val, void *arg)\n{\n\tstruct vga_softc *sc = arg;\n\n\tswitch (port) {\n\tcase CRTC_IDX_MONO_PORT:\n\tcase CRTC_IDX_COLOR_PORT:\n\t\tsc->vga_crtc.crtc_index = val;\n\t\tbreak;\n\tcase CRTC_DATA_MONO_PORT:\n\tcase CRTC_DATA_COLOR_PORT:\n\t\tswitch (sc->vga_crtc.crtc_index) {\n\t\tcase CRTC_HORIZ_TOTAL:\n\t\t\tsc->vga_crtc.crtc_horiz_total = val;\n\t\t\tbreak;\n\t\tcase CRTC_HORIZ_DISP_END:\n\t\t\tsc->vga_crtc.crtc_horiz_disp_end = val;\n\t\t\tbreak;\n\t\tcase CRTC_START_HORIZ_BLANK:\n\t\t\tsc->vga_crtc.crtc_start_horiz_blank = val;\n\t\t\tbreak;\n\t\tcase CRTC_END_HORIZ_BLANK:\n\t\t\tsc->vga_crtc.crtc_end_horiz_blank = val;\n\t\t\tbreak;\n\t\tcase CRTC_START_HORIZ_RETRACE:\n\t\t\tsc->vga_crtc.crtc_start_horiz_retrace = val;\n\t\t\tbreak;\n\t\tcase CRTC_END_HORIZ_RETRACE:\n\t\t\tsc->vga_crtc.crtc_end_horiz_retrace = val;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_TOTAL:\n\t\t\tsc->vga_crtc.crtc_vert_total = val;\n\t\t\tbreak;\n\t\tcase CRTC_OVERFLOW:\n\t\t\tsc->vga_crtc.crtc_overflow = val;\n\t\t\tbreak;\n\t\tcase CRTC_PRESET_ROW_SCAN:\n\t\t\tsc->vga_crtc.crtc_present_row_scan = val;\n\t\t\tbreak;\n\t\tcase CRTC_MAX_SCAN_LINE:\n\t\t\tsc->vga_crtc.crtc_max_scan_line = val;\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_START:\n\t\t\tsc->vga_crtc.crtc_cursor_start = val;\n\t\t\tsc->vga_crtc.crtc_cursor_on = (val & CRTC_CS_CO) == 0;\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_END:\n\t\t\tsc->vga_crtc.crtc_cursor_end = val;\n\t\t\tbreak;\n\t\tcase CRTC_START_ADDR_HIGH:\n\t\t\tsc->vga_crtc.crtc_start_addr_high = val;\n\t\t\tsc->vga_crtc.crtc_start_addr &= 0x00ff;\n\t\t\tsc->vga_crtc.crtc_start_addr |= (val << 8);\n\t\t\tbreak;\n\t\tcase CRTC_START_ADDR_LOW:\n\t\t\tsc->vga_crtc.crtc_start_addr_low = val;\n\t\t\tsc->vga_crtc.crtc_start_addr &= 0xff00;\n\t\t\tsc->vga_crtc.crtc_start_addr |= (val & 0xff);\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_LOC_HIGH:\n\t\t\tsc->vga_crtc.crtc_cursor_loc_high = val;\n\t\t\tsc->vga_crtc.crtc_cursor_loc &= 0x00ff;\n\t\t\tsc->vga_crtc.crtc_cursor_loc |= (val << 8);\n\t\t\tbreak;\n\t\tcase CRTC_CURSOR_LOC_LOW:\n\t\t\tsc->vga_crtc.crtc_cursor_loc_low = val;\n\t\t\tsc->vga_crtc.crtc_cursor_loc &= 0xff00;\n\t\t\tsc->vga_crtc.crtc_cursor_loc |= (val & 0xff);\n\t\t\tbreak;\n\t\tcase CRTC_VERT_RETRACE_START:\n\t\t\tsc->vga_crtc.crtc_vert_retrace_start = val;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_RETRACE_END:\n\t\t\tsc->vga_crtc.crtc_vert_retrace_end = val;\n\t\t\tbreak;\n\t\tcase CRTC_VERT_DISP_END:\n\t\t\tsc->vga_crtc.crtc_vert_disp_end = val;\n\t\t\tbreak;\n\t\tcase CRTC_OFFSET:\n\t\t\tsc->vga_crtc.crtc_offset = val;\n\t\t\tbreak;\n\t\tcase CRTC_UNDERLINE_LOC:\n\t\t\tsc->vga_crtc.crtc_underline_loc = val;\n\t\t\tbreak;\n\t\tcase CRTC_START_VERT_BLANK:\n\t\t\tsc->vga_crtc.crtc_start_vert_blank = val;\n\t\t\tbreak;\n\t\tcase CRTC_END_VERT_BLANK:\n\t\t\tsc->vga_crtc.crtc_end_vert_blank = val;\n\t\t\tbreak;\n\t\tcase CRTC_MODE_CONTROL:\n\t\t\tsc->vga_crtc.crtc_mode_ctrl = val;\n\t\t\tbreak;\n\t\tcase CRTC_LINE_COMPARE:\n\t\t\tsc->vga_crtc.crtc_line_compare = val;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t//printf(\"XXX VGA CRTC: outb 0x%04x, 0x%02x at index %d\\n\", port, val, sc->vga_crtc.crtc_index);\n\t\t\tassert(0);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase ATC_IDX_PORT:\n\t\tif (sc->vga_atc.atc_flipflop == 0) {\n\t\t\tif (sc->vga_atc.atc_index & 0x20)\n\t\t\t\tassert(0);\n\t\t\tsc->vga_atc.atc_index = val & ATC_IDX_MASK;\n\t\t} else {\n\t\t\tswitch (sc->vga_atc.atc_index) {\n\t\t\tcase ATC_MODE_CONTROL:\n\t\t\t\tsc->vga_atc.atc_mode = val;\n\t\t\t\tbreak;\n\t\t\tcase ATC_OVERSCAN_COLOR:\n\t\t\t\tsc->vga_atc.atc_overscan_color = val;\n\t\t\t\tbreak;\n\t\t\tcase ATC_COLOR_PLANE_ENABLE:\n\t\t\t\tsc->vga_atc.atc_color_plane_enb = val;\n\t\t\t\tbreak;\n\t\t\tcase ATC_HORIZ_PIXEL_PANNING:\n\t\t\t\tsc->vga_atc.atc_horiz_pixel_panning = val;\n\t\t\t\tbreak;\n\t\t\tcase ATC_COLOR_SELECT:\n\t\t\t\tsc->vga_atc.atc_color_select = val;\n\t\t\t\tsc->vga_atc.atc_color_select_45 =\n\t\t\t\t\t(uint8_t)((val & ATC_CS_C45) << 4);\n\t\t\t\tsc->vga_atc.atc_color_select_67 =\n\t\t\t\t\t(uint8_t)(((val & ATC_CS_C67) >> 2) << 6);\n\t\t\t\tbreak;\n\t\t\tdefault:\n                if (sc->vga_atc.atc_index >= ATC_PALETTE0 && sc->vga_atc.atc_index <= ATC_PALETTE15) {\n                    sc->vga_atc.atc_palette[sc->vga_atc.atc_index] = val & 0x3f;\n                } else {\n                    //printf(\"XXX VGA ATC: outb 0x%04x, 0x%02x at index %d\\n\", port, val, sc->vga_atc.atc_index);\n                    assert(0);\n                }\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tsc->vga_atc.atc_flipflop ^= 1;\n\t\tbreak;\n\tcase ATC_DATA_PORT:\n\t\tbreak;\n\tcase SEQ_IDX_PORT:\n\t\tsc->vga_seq.seq_index = val & 0x1f;\n\t\tbreak;\n\tcase SEQ_DATA_PORT:\n\t\tswitch (sc->vga_seq.seq_index) {\n\t\tcase SEQ_RESET:\n\t\t\tsc->vga_seq.seq_reset = val;\n\t\t\tbreak;\n\t\tcase SEQ_CLOCKING_MODE:\n\t\t\tsc->vga_seq.seq_clock_mode = val;\n\t\t\tsc->vga_seq.seq_cm_dots = (val & SEQ_CM_89) ? 8 : 9;\n\t\t\tbreak;\n\t\tcase SEQ_MAP_MASK:\n\t\t\tsc->vga_seq.seq_map_mask = val;\n\t\t\tbreak;\n\t\tcase SEQ_CHAR_MAP_SELECT:\n\t\t\tsc->vga_seq.seq_cmap_sel = val;\n\n\t\t\tsc->vga_seq.seq_cmap_pri_off = ((((val & SEQ_CMS_SA) >> SEQ_CMS_SA_SHIFT) * 2) + ((val & SEQ_CMS_SAH) >> SEQ_CMS_SAH_SHIFT)) * 8 * KB;\n\t\t\tsc->vga_seq.seq_cmap_sec_off = ((((val & SEQ_CMS_SB) >> SEQ_CMS_SB_SHIFT) * 2) + ((val & SEQ_CMS_SBH) >> SEQ_CMS_SBH_SHIFT)) * 8 * KB;\n\t\t\tbreak;\n\t\tcase SEQ_MEMORY_MODE:\n\t\t\tsc->vga_seq.seq_mm = val;\n\t\t\t/* Windows queries Chain4 */\n\t\t\t//assert((sc->vga_seq.seq_mm & SEQ_MM_C4) == 0);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t//printf(\"XXX VGA SEQ: outb 0x%04x, 0x%02x at index %d\\n\", port, val, sc->vga_seq.seq_index);\n\t\t\tassert(0);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase DAC_MASK:\n\t\tbreak;\n\tcase DAC_IDX_RD_PORT:\n\t\tsc->vga_dac.dac_rd_index = val;\n\t\tsc->vga_dac.dac_rd_subindex = 0;\n\t\tbreak;\n\tcase DAC_IDX_WR_PORT:\n\t\tsc->vga_dac.dac_wr_index = val;\n\t\tsc->vga_dac.dac_wr_subindex = 0;\n\t\tbreak;\n\tcase DAC_DATA_PORT:\n\t\tsc->vga_dac.dac_palette[3 * sc->vga_dac.dac_wr_index +\n\t\t\t\t\tsc->vga_dac.dac_wr_subindex] = val;\n\t\tsc->vga_dac.dac_wr_subindex++;\n\t\tif (sc->vga_dac.dac_wr_subindex == 3) {\n\t\t\tsc->vga_dac.dac_palette_rgb[sc->vga_dac.dac_wr_index] =\n\t\t\t\t((uint32_t)(((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] << 2) |\n\t\t\t\t   ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] & 0x1) << 1) |\n\t\t\t\t   (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 0] & 0x1)) << 16) |\n\t\t\t\t (uint32_t)(((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] << 2) |\n\t\t\t\t   ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] & 0x1) << 1) |\n\t\t\t\t   (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 1] & 0x1)) << 8) |\n\t\t\t\t (uint32_t)(((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] << 2) |\n\t\t\t\t   ((sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] & 0x1) << 1) |\n\t\t\t\t   (sc->vga_dac.dac_palette[3*sc->vga_dac.dac_wr_index + 2] & 0x1)) << 0));\n\n\t\t\tsc->vga_dac.dac_wr_index++;\n\t\t\tsc->vga_dac.dac_wr_subindex = 0;\n\t\t}\n\t\tbreak;\n\tcase GC_IDX_PORT:\n\t\tsc->vga_gc.gc_index = val;\n\t\tbreak;\n\tcase GC_DATA_PORT:\n\t\tswitch (sc->vga_gc.gc_index) {\n\t\tcase GC_SET_RESET:\n\t\t\tsc->vga_gc.gc_set_reset = val;\n\t\t\tbreak;\n\t\tcase GC_ENABLE_SET_RESET:\n\t\t\tsc->vga_gc.gc_enb_set_reset = val;\n\t\t\tbreak;\n\t\tcase GC_COLOR_COMPARE:\n\t\t\tsc->vga_gc.gc_color_compare = val;\n\t\t\tbreak;\n\t\tcase GC_DATA_ROTATE:\n\t\t\tsc->vga_gc.gc_rotate = val;\n\t\t\tsc->vga_gc.gc_op = (val >> 3) & 0x3;\n\t\t\tbreak;\n\t\tcase GC_READ_MAP_SELECT:\n\t\t\tsc->vga_gc.gc_read_map_sel = val;\n\t\t\tbreak;\n\t\tcase GC_MODE:\n\t\t\tsc->vga_gc.gc_mode = val;\n\t\t\tsc->vga_gc.gc_mode_c4 = (val & GC_MODE_C4) != 0;\n\t\t\tassert(!sc->vga_gc.gc_mode_c4);\n\t\t\tsc->vga_gc.gc_mode_oe = (val & GC_MODE_OE) != 0;\n\t\t\tsc->vga_gc.gc_mode_rm = (val >> 3) & 0x1;\n\t\t\tsc->vga_gc.gc_mode_wm = val & 0x3;\n\n\t\t\tif (sc->gc_image)\n\t\t\t\tsc->gc_image->vgamode = 1;\n\t\t\tbreak;\n\t\tcase GC_MISCELLANEOUS:\n\t\t\tsc->vga_gc.gc_misc = val;\n\t\t\tsc->vga_gc.gc_misc_gm = val & GC_MISC_GM;\n\t\t\tsc->vga_gc.gc_misc_mm = (val & GC_MISC_MM) >>\n\t\t\t    GC_MISC_MM_SHIFT;\n\t\t\tbreak;\n\t\tcase GC_COLOR_DONT_CARE:\n\t\t\tsc->vga_gc.gc_color_dont_care = val;\n\t\t\tbreak;\n\t\tcase GC_BIT_MASK:\n\t\t\tsc->vga_gc.gc_bit_mask = val;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t//printf(\"XXX VGA GC: outb 0x%04x, 0x%02x at index %d\\n\", port, val, sc->vga_gc.gc_index);\n\t\t\tassert(0);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase GEN_INPUT_STS0_PORT:\n\t\t/* write to Miscellaneous Output Register */\n\t\tsc->vga_misc = val;\n\t\tbreak;\n\tcase GEN_INPUT_STS1_MONO_PORT:\n\tcase GEN_INPUT_STS1_COLOR_PORT:\n\t\t/* write to Feature Control Register */\n\t\tbreak;\n//\tcase 0x3c3:\n//\t\tbreak;\n\tdefault:\n\t\tprintf(\"XXX vga_port_out_handler() unhandled port 0x%x, val 0x%x\\n\", port, val);\n\t\t//assert(0);\n\t\treturn (-1);\n\t}\n\treturn (0);\n}\n\nstatic int\nvga_port_handler(UNUSED int vcpu, int in, int port, int bytes,\n\t\t uint32_t *eax, void *arg)\n{\n\tuint8_t val;\n\tint error;\n\n\tswitch (bytes) {\n\tcase 1:\n\t\tif (in) {\n\t\t\t*eax &= (uint32_t)~0xff;\n\t\t\terror = vga_port_in_handler(in, port, 1,\n\t\t\t\t\t\t    &val, arg);\n\t\t\tif (!error) {\n\t\t\t\t*eax |= val & 0xff;\n\t\t\t}\n\t\t} else {\n\t\t\tval = *eax & 0xff;\n\t\t\terror = vga_port_out_handler(in, port, 1,\n\t\t\t\t\t\t     val, arg);\n\t\t}\n\t\tbreak;\n\tcase 2:\n\t\tif (in) {\n\t\t\t*eax &= (uint32_t)~0xffff;\n\t\t\terror = vga_port_in_handler(in, port, 1,\n\t\t\t\t\t\t    &val, arg);\n\t\t\tif (!error) {\n\t\t\t\t*eax |= val & 0xff;\n\t\t\t}\n\t\t\terror = vga_port_in_handler(in, port + 1, 1,\n\t\t\t\t\t\t    &val, arg);\n\t\t\tif (!error) {\n\t\t\t\t*eax |= (uint32_t)((val & 0xff) << 8);\n\t\t\t}\n\t\t} else {\n\t\t\tval = *eax & 0xff;\n\t\t\terror = vga_port_out_handler(in, port, 1,\n\t\t\t\t\t\t     val, arg);\n\t\t\tval = (*eax >> 8) & 0xff;\n\t\t\terror =vga_port_out_handler(in, port + 1, 1,\n\t\t\t\t\t\t    val, arg);\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tassert(0);\n\t\treturn (-1);\n\t}\n\n\treturn (error);\n}\n\nvoid *\nvga_init(int io_only)\n{\n\tstruct inout_port iop;\n\tstruct vga_softc *sc;\n\tint port, error;\n\n\tsc = calloc(1, sizeof(struct vga_softc));\n\n\tbzero(&iop, sizeof(struct inout_port));\n\tiop.name = \"VGA\";\n\tfor (port = VGA_IOPORT_START; port <= VGA_IOPORT_END; port++) {\n\t\tiop.port = port;\n\t\tiop.size = 1;\n\t\tiop.flags = IOPORT_F_INOUT;\n\t\tiop.handler = vga_port_handler;\n\t\tiop.arg = sc;\n\n\t\terror = register_inout(&iop);\n\t\tassert(error == 0);\n\t}\n\n\tsc->gc_image = console_get_image();\n\n\t/* only handle io ports; vga graphics is disabled */\n\tif (io_only)\n\t\treturn(sc);\n\n\tsc->mr.name = \"VGA memory\";\n\tsc->mr.flags = MEM_F_RW;\n\tsc->mr.base = 640 * KB;\n\tsc->mr.size = 128 * KB;\n\tsc->mr.handler = vga_mem_handler;\n\tsc->mr.arg1 = sc;\n\terror = register_mem_fallback(&sc->mr);\n\tassert(error == 0);\n\n\tsc->vga_ram = malloc(256 * KB);\n\tmemset(sc->vga_ram, 0, 256 * KB);\n\n\t{\n\t\tstatic uint8_t palette[] = {\n\t\t\t0x00,0x00,0x00, 0x00,0x00,0x2a, 0x00,0x2a,0x00, 0x00,0x2a,0x2a,\n\t\t\t0x2a,0x00,0x00, 0x2a,0x00,0x2a, 0x2a,0x2a,0x00, 0x2a,0x2a,0x2a,\n\t\t\t0x00,0x00,0x15, 0x00,0x00,0x3f, 0x00,0x2a,0x15, 0x00,0x2a,0x3f,\n\t\t\t0x2a,0x00,0x15, 0x2a,0x00,0x3f, 0x2a,0x2a,0x15, 0x2a,0x2a,0x3f,\n\t\t};\n\t\tint i;\n\n\t\tmemcpy(sc->vga_dac.dac_palette, palette, 16 * 3 * sizeof (uint8_t));\n\t\tfor (i = 0; i < 16; i++) {\n\t\t\tsc->vga_dac.dac_palette_rgb[i] =\n\t\t\t\t((uint32_t)(((sc->vga_dac.dac_palette[3*i + 0] << 2) |\n\t\t\t\t   ((sc->vga_dac.dac_palette[3*i + 0] & 0x1) << 1) |\n\t\t\t\t   (sc->vga_dac.dac_palette[3*i + 0] & 0x1)) << 16) |\n\t\t\t\t (uint32_t)(((sc->vga_dac.dac_palette[3*i + 1] << 2) |\n\t\t\t\t   ((sc->vga_dac.dac_palette[3*i + 1] & 0x1) << 1) |\n\t\t\t\t   (sc->vga_dac.dac_palette[3*i + 1] & 0x1)) << 8) |\n\t\t\t\t (uint32_t)(((sc->vga_dac.dac_palette[3*i + 2] << 2) |\n\t\t\t\t   ((sc->vga_dac.dac_palette[3*i + 2] & 0x1) << 1) |\n\t\t\t\t   (sc->vga_dac.dac_palette[3*i + 2] & 0x1)) << 0));\n\t\t}\n\t}\n\n\treturn (sc);\n}\n"
  },
  {
    "path": "src/virtio.c",
    "content": "/*-\n * Copyright (c) 2013  Chris Torek <torek @ torek net>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <pthread.h>\n#include <sys/param.h>\n#include <sys/uio.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/virtio.h>\n\n/*\n * Functions for dealing with generalized \"virtual devices\" as\n * defined by <https://www.google.com/#output=search&q=virtio+spec>\n */\n\n/*\n * In case we decide to relax the \"virtio softc comes at the\n * front of virtio-based device softc\" constraint, let's use\n * this to convert.\n */\n#define DEV_SOFTC(vs) ((void *)(vs))\n\n/*\n * Link a virtio_softc to its constants, the device softc, and\n * the PCI emulation.\n */\nvoid\nvi_softc_linkup(struct virtio_softc *vs, struct virtio_consts *vc,\n\t\tvoid *dev_softc, struct pci_devinst *pi,\n\t\tstruct vqueue_info *queues)\n{\n\tint i;\n\n\t/* vs and dev_softc addresses must match */\n\tassert((void *)vs == dev_softc);\n\tvs->vs_vc = vc;\n\tvs->vs_pi = pi;\n\tpi->pi_arg = vs;\n\n\tvs->vs_queues = queues;\n\tfor (i = 0; i < vc->vc_nvq; i++) {\n\t\tqueues[i].vq_vs = vs;\n\t\tqueues[i].vq_num = (uint16_t) i;\n\t}\n}\n\n/*\n * Reset device (device-wide).  This erases all queues, i.e.,\n * all the queues become invalid (though we don't wipe out the\n * internal pointers, we just clear the VQ_ALLOC flag).\n *\n * It resets negotiated features to \"none\".\n *\n * If MSI-X is enabled, this also resets all the vectors to NO_VECTOR.\n */\nvoid\nvi_reset_dev(struct virtio_softc *vs)\n{\n\tstruct vqueue_info *vq;\n\tint i, nvq;\n\n\tnvq = vs->vs_vc->vc_nvq;\n\tfor (vq = vs->vs_queues, i = 0; i < nvq; vq++, i++) {\n\t\tvq->vq_flags = 0;\n\t\tvq->vq_last_avail = 0;\n\t\tvq->vq_save_used = 0;\n\t\tvq->vq_pfn = 0;\n\t\tvq->vq_msix_idx = VIRTIO_MSI_NO_VECTOR;\n\t}\n\tvs->vs_negotiated_caps = 0;\n\tvs->vs_curq = 0;\n\t/* vs->vs_status = 0; -- redundant */\n\tif (vs->vs_isr)\n\t\tpci_lintr_deassert(vs->vs_pi);\n\tvs->vs_isr = 0;\n\tvs->vs_msix_cfg_idx = VIRTIO_MSI_NO_VECTOR;\n}\n\n/*\n * Set I/O BAR (usually 0) to map PCI config registers.\n */\nvoid\nvi_set_io_bar(struct virtio_softc *vs, int barnum)\n{\n\tsize_t size;\n\n\t/*\n\t * ??? should we use CFG0 if MSI-X is disabled?\n\t * Existing code did not...\n\t */\n\tsize = VTCFG_R_CFG1 + vs->vs_vc->vc_cfgsize;\n\tpci_emul_alloc_bar(vs->vs_pi, barnum, PCIBAR_IO, size);\n}\n\n/*\n * Initialize MSI-X vector capabilities if we're to use MSI-X,\n * or MSI capabilities if not.\n *\n * We assume we want one MSI-X vector per queue, here, plus one\n * for the config vec.\n */\nint\nvi_intr_init(struct virtio_softc *vs, int barnum, int use_msix)\n{\n\tint nvec;\n\n\tif (use_msix) {\n\t\tvs->vs_flags |= VIRTIO_USE_MSIX;\n\t\tVS_LOCK(vs);\n\t\tvi_reset_dev(vs); /* set all vectors to NO_VECTOR */\n\t\tVS_UNLOCK(vs);\n\t\tnvec = vs->vs_vc->vc_nvq + 1;\n\t\tif (pci_emul_add_msixcap(vs->vs_pi, nvec, barnum))\n\t\t\treturn (1);\n\t} else\n\t\tvs->vs_flags &= ~VIRTIO_USE_MSIX;\n\n\t/* Only 1 MSI vector for bhyve */\n\tpci_emul_add_msicap(vs->vs_pi, 1);\n\n\t/* Legacy interrupts are mandatory for virtio devices */\n\tpci_lintr_request(vs->vs_pi);\n\n\treturn (0);\n}\n\n/*\n * Initialize the currently-selected virtio queue (vs->vs_curq).\n * The guest just gave us a page frame number, from which we can\n * calculate the addresses of the queue.\n */\nstatic void\nvi_vq_init(struct virtio_softc *vs, uint32_t pfn)\n{\n\tstruct vqueue_info *vq;\n\tuint64_t phys;\n\tsize_t size;\n\tchar *base;\n\n\tvq = &vs->vs_queues[vs->vs_curq];\n\tvq->vq_pfn = pfn;\n\tphys = (uint64_t)pfn << VRING_PFN;\n\tsize = vring_size(vq->vq_qsize);\n\tbase = paddr_guest2host(phys, size);\n\n\t/* First page(s) are descriptors... */\n\tvq->vq_desc = (struct virtio_desc *)base;\n\tbase += vq->vq_qsize * sizeof(struct virtio_desc);\n\n\t/* ... immediately followed by \"avail\" ring (entirely uint16_t's) */\n\tvq->vq_avail = (struct vring_avail *)base;\n\tbase += (2 + vq->vq_qsize + 1) * sizeof(uint16_t);\n\n\t/* Then it's rounded up to the next page... */\n\tbase = (char *) roundup2(((uintptr_t) base), ((uintptr_t) VRING_ALIGN));\n\n\t/* ... and the last page(s) are the used ring. */\n\tvq->vq_used = (struct vring_used *)base;\n\n\t/* Mark queue as allocated, and start at 0 when we use it. */\n\tvq->vq_flags = VQ_ALLOC;\n\tvq->vq_last_avail = 0;\n\tvq->vq_save_used = 0;\n}\n\n/*\n * Helper inline for vq_getchain(): record the i'th \"real\"\n * descriptor.\n */\nstatic inline void\n_vq_record(int i, volatile struct virtio_desc *vd, struct iovec *iov, int n_iov,\n\tuint16_t *flags)\n{\n\tif (i >= n_iov)\n\t\treturn;\n\tiov[i].iov_base = paddr_guest2host(vd->vd_addr, vd->vd_len);\n\tiov[i].iov_len = vd->vd_len;\n\tif (flags != NULL)\n\t\tflags[i] = vd->vd_flags;\n}\n#define\tVQ_MAX_DESCRIPTORS\t512\t/* see below */\n\n/*\n * Examine the chain of descriptors starting at the \"next one\" to\n * make sure that they describe a sensible request.  If so, return\n * the number of \"real\" descriptors that would be needed/used in\n * acting on this request.  This may be smaller than the number of\n * available descriptors, e.g., if there are two available but\n * they are two separate requests, this just returns 1.  Or, it\n * may be larger: if there are indirect descriptors involved,\n * there may only be one descriptor available but it may be an\n * indirect pointing to eight more.  We return 8 in this case,\n * i.e., we do not count the indirect descriptors, only the \"real\"\n * ones.\n *\n * Basically, this vets the vd_flags and vd_next field of each\n * descriptor and tells you how many are involved.  Since some may\n * be indirect, this also needs the vmctx (in the pci_devinst\n * at vs->vs_pi) so that it can find indirect descriptors.\n *\n * As we process each descriptor, we copy and adjust it (guest to\n * host address wise, also using the vmtctx) into the given iov[]\n * array (of the given size).  If the array overflows, we stop\n * placing values into the array but keep processing descriptors,\n * up to VQ_MAX_DESCRIPTORS, before giving up and returning -1.\n * So you, the caller, must not assume that iov[] is as big as the\n * return value (you can process the same thing twice to allocate\n * a larger iov array if needed, or supply a zero length to find\n * out how much space is needed).\n *\n * If you want to verify the WRITE flag on each descriptor, pass a\n * non-NULL \"flags\" pointer to an array of \"uint16_t\" of the same size\n * as n_iov and we'll copy each vd_flags field after unwinding any\n * indirects.\n *\n * If some descriptor(s) are invalid, this prints a diagnostic message\n * and returns -1.  If no descriptors are ready now it simply returns 0.\n *\n * You are assumed to have done a vq_ring_ready() if needed (note\n * that vq_has_descs() does one).\n */\nint\nvq_getchain(struct vqueue_info *vq, uint16_t *pidx, struct iovec *iov,\n\tint n_iov, uint16_t *flags)\n{\n\tint i;\n\tu_int ndesc, n_indir;\n\tu_int idx, next;\n\tvolatile struct virtio_desc *vdir, *vindir, *vp;\n\tstruct virtio_softc *vs;\n\tconst char *name;\n\n\tvs = vq->vq_vs;\n\tname = vs->vs_vc->vc_name;\n\n\t/*\n\t * Note: it's the responsibility of the guest not to\n\t * update vq->vq_avail->va_idx until all of the descriptors\n         * the guest has written are valid (including all their\n         * vd_next fields and vd_flags).\n\t *\n\t * Compute (last_avail - va_idx) in integers mod 2**16.  This is\n\t * the number of descriptors the device has made available\n\t * since the last time we updated vq->vq_last_avail.\n\t *\n\t * We just need to do the subtraction as an unsigned int,\n\t * then trim off excess bits.\n\t */\n\tidx = vq->vq_last_avail;\n\tndesc = (uint16_t)((u_int)vq->vq_avail->va_idx - idx);\n\tif (ndesc == 0)\n\t\treturn (0);\n\tif (ndesc > vq->vq_qsize) {\n\t\t/* XXX need better way to diagnose issues */\n\t\tfprintf(stderr,\n\t\t    \"%s: ndesc (%u) out of range, driver confused?\\r\\n\",\n\t\t    name, (u_int)ndesc);\n\t\treturn (-1);\n\t}\n\n\t/*\n\t * Now count/parse \"involved\" descriptors starting from\n\t * the head of the chain.\n\t *\n\t * To prevent loops, we could be more complicated and\n\t * check whether we're re-visiting a previously visited\n\t * index, but we just abort if the count gets excessive.\n\t */\n\t*pidx = next = vq->vq_avail->va_ring[idx & (vq->vq_qsize - 1)];\n\tvq->vq_last_avail++;\n\tfor (i = 0; i < VQ_MAX_DESCRIPTORS; next = vdir->vd_next) {\n\t\tif (next >= vq->vq_qsize) {\n\t\t\tfprintf(stderr,\n\t\t\t    \"%s: descriptor index %u out of range, \"\n\t\t\t    \"driver confused?\\r\\n\",\n\t\t\t    name, next);\n\t\t\treturn (-1);\n\t\t}\n\t\tvdir = &vq->vq_desc[next];\n\t\tif ((vdir->vd_flags & VRING_DESC_F_INDIRECT) == 0) {\n\t\t\t_vq_record(i, vdir, iov, n_iov, flags);\n\t\t\ti++;\n\t\t} else if ((vs->vs_vc->vc_hv_caps &\n\t\t    VIRTIO_RING_F_INDIRECT_DESC) == 0) {\n\t\t\tfprintf(stderr,\n\t\t\t    \"%s: descriptor has forbidden INDIRECT flag, \"\n\t\t\t    \"driver confused?\\r\\n\",\n\t\t\t    name);\n\t\t\treturn (-1);\n\t\t} else {\n\t\t\tn_indir = vdir->vd_len / 16;\n\t\t\tif ((vdir->vd_len & 0xf) || n_indir == 0) {\n\t\t\t\tfprintf(stderr,\n\t\t\t\t    \"%s: invalid indir len 0x%x, \"\n\t\t\t\t    \"driver confused?\\r\\n\",\n\t\t\t\t    name, (u_int)vdir->vd_len);\n\t\t\t\treturn (-1);\n\t\t\t}\n\t\t\tvindir = paddr_guest2host(vdir->vd_addr, vdir->vd_len);\n\t\t\t/*\n\t\t\t * Indirects start at the 0th, then follow\n\t\t\t * their own embedded \"next\"s until those run\n\t\t\t * out.  Each one's indirect flag must be off\n\t\t\t * (we don't really have to check, could just\n\t\t\t * ignore errors...).\n\t\t\t */\n\t\t\tnext = 0;\n\t\t\tfor (;;) {\n\t\t\t\tvp = &vindir[next];\n\t\t\t\tif (vp->vd_flags & VRING_DESC_F_INDIRECT) {\n\t\t\t\t\tfprintf(stderr,\n\t\t\t\t\t    \"%s: indirect desc has INDIR flag,\"\n\t\t\t\t\t    \" driver confused?\\r\\n\",\n\t\t\t\t\t    name);\n\t\t\t\t\treturn (-1);\n\t\t\t\t}\n\t\t\t\t_vq_record(i, vp, iov, n_iov, flags);\n\t\t\t\tif (++i > VQ_MAX_DESCRIPTORS)\n\t\t\t\t\tgoto loopy;\n\t\t\t\tif ((vp->vd_flags & VRING_DESC_F_NEXT) == 0)\n\t\t\t\t\tbreak;\n\t\t\t\tnext = vp->vd_next;\n\t\t\t\tif (next >= n_indir) {\n\t\t\t\t\tfprintf(stderr,\n\t\t\t\t\t    \"%s: invalid next %u > %u, \"\n\t\t\t\t\t    \"driver confused?\\r\\n\",\n\t\t\t\t\t    name, (u_int)next, n_indir);\n\t\t\t\t\treturn (-1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif ((vdir->vd_flags & VRING_DESC_F_NEXT) == 0)\n\t\t\treturn (i);\n\t}\nloopy:\n\tfprintf(stderr,\n\t    \"%s: descriptor loop? count > %d - driver confused?\\r\\n\",\n\t    name, i);\n\treturn (-1);\n}\n\n/*\n * Return the currently-first request chain back to the available queue.\n *\n * (This chain is the one you handled when you called vq_getchain()\n * and used its positive return value.)\n */\nvoid\nvq_retchain(struct vqueue_info *vq)\n{\n\n\tvq->vq_last_avail--;\n}\n\n/*\n * Return specified request chain to the guest, setting its I/O length\n * to the provided value.\n *\n * (This chain is the one you handled when you called vq_getchain()\n * and used its positive return value.)\n */\nvoid\nvq_relchain(struct vqueue_info *vq, uint16_t idx, uint32_t iolen)\n{\n\tuint16_t uidx, mask;\n\tvolatile struct vring_used *vuh;\n\tvolatile struct virtio_used *vue;\n\n\t/*\n\t * Notes:\n\t *  - mask is N-1 where N is a power of 2 so computes x % N\n\t *  - vuh points to the \"used\" data shared with guest\n\t *  - vue points to the \"used\" ring entry we want to update\n\t *  - head is the same value we compute in vq_iovecs().\n\t *\n\t * (I apologize for the two fields named vu_idx; the\n\t * virtio spec calls the one that vue points to, \"id\"...)\n\t */\n\tmask = vq->vq_qsize - 1;\n\tvuh = vq->vq_used;\n\n\tuidx = vuh->vu_idx;\n\tvue = &vuh->vu_ring[uidx++ & mask];\n\tvue->vu_idx = idx;\n\tvue->vu_tlen = iolen;\n\tvuh->vu_idx = uidx;\n}\n\n/*\n * Driver has finished processing \"available\" chains and calling\n * vq_relchain on each one.  If driver used all the available\n * chains, used_all should be set.\n *\n * If the \"used\" index moved we may need to inform the guest, i.e.,\n * deliver an interrupt.  Even if the used index did NOT move we\n * may need to deliver an interrupt, if the avail ring is empty and\n * we are supposed to interrupt on empty.\n *\n * Note that used_all_avail is provided by the caller because it's\n * a snapshot of the ring state when he decided to finish interrupt\n * processing -- it's possible that descriptors became available after\n * that point.  (It's also typically a constant 1/True as well.)\n */\nvoid\nvq_endchains(struct vqueue_info *vq, int used_all_avail)\n{\n\tstruct virtio_softc *vs;\n\tuint16_t event_idx, new_idx, old_idx;\n\tint intr;\n\n\t/*\n\t * Interrupt generation: if we're using EVENT_IDX,\n\t * interrupt if we've crossed the event threshold.\n\t * Otherwise interrupt is generated if we added \"used\" entries,\n\t * but suppressed by VRING_AVAIL_F_NO_INTERRUPT.\n\t *\n\t * In any case, though, if NOTIFY_ON_EMPTY is set and the\n\t * entire avail was processed, we need to interrupt always.\n\t */\n\tvs = vq->vq_vs;\n\told_idx = vq->vq_save_used;\n\tvq->vq_save_used = new_idx = vq->vq_used->vu_idx;\n\tif (used_all_avail &&\n\t    (vs->vs_negotiated_caps & VIRTIO_F_NOTIFY_ON_EMPTY))\n\t\tintr = 1;\n\telse if (vs->vs_negotiated_caps & VIRTIO_RING_F_EVENT_IDX) {\n\t\tevent_idx = VQ_USED_EVENT_IDX(vq);\n\t\t/*\n\t\t * This calculation is per docs and the kernel\n\t\t * (see src/sys/dev/virtio/virtio_ring.h).\n\t\t */\n\t\tintr = (uint16_t)(new_idx - event_idx - 1) <\n\t\t\t(uint16_t)(new_idx - old_idx);\n\t} else {\n\t\tintr = new_idx != old_idx &&\n\t\t    !(vq->vq_avail->va_flags & VRING_AVAIL_F_NO_INTERRUPT);\n\t}\n\tif (intr)\n\t\tvq_interrupt(vs, vq);\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n/* Note: these are in sorted order to make for a fast search */\nstatic struct config_reg {\n\tuint16_t\tcr_offset;\t/* register offset */\n\tuint8_t\t\tcr_size;\t/* size (bytes) */\n\tuint8_t\t\tcr_ro;\t\t/* true => reg is read only */\n\tconst char\t*cr_name;\t/* name of reg */\n} config_regs[] = {\n\t{ VTCFG_R_HOSTCAP,\t4, 1, \"HOSTCAP\" },\n\t{ VTCFG_R_GUESTCAP,\t4, 0, \"GUESTCAP\" },\n\t{ VTCFG_R_PFN,\t\t4, 0, \"PFN\" },\n\t{ VTCFG_R_QNUM,\t\t2, 1, \"QNUM\" },\n\t{ VTCFG_R_QSEL,\t\t2, 0, \"QSEL\" },\n\t{ VTCFG_R_QNOTIFY,\t2, 0, \"QNOTIFY\" },\n\t{ VTCFG_R_STATUS,\t1, 0, \"STATUS\" },\n\t{ VTCFG_R_ISR,\t\t1, 0, \"ISR\" },\n\t{ VTCFG_R_CFGVEC,\t2, 0, \"CFGVEC\" },\n\t{ VTCFG_R_QVEC,\t\t2, 0, \"QVEC\" },\n};\n#pragma clang diagnostic pop\n\nstatic inline struct config_reg *\nvi_find_cr(int offset) {\n\tu_int hi, lo, mid;\n\tstruct config_reg *cr;\n\n\tlo = 0;\n\thi = sizeof(config_regs) / sizeof(*config_regs) - 1;\n\twhile (hi >= lo) {\n\t\tmid = (hi + lo) >> 1;\n\t\tcr = &config_regs[mid];\n\t\tif (cr->cr_offset == offset)\n\t\t\treturn (cr);\n\t\tif (cr->cr_offset < offset)\n\t\t\tlo = mid + 1;\n\t\telse\n\t\t\thi = mid - 1;\n\t}\n\treturn (NULL);\n}\n\n/*\n * Handle pci config space reads.\n * If it's to the MSI-X info, do that.\n * If it's part of the virtio standard stuff, do that.\n * Otherwise dispatch to the actual driver.\n */\nuint64_t\nvi_pci_read(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size)\n{\n\tstruct virtio_softc *vs = pi->pi_arg;\n\tstruct virtio_consts *vc;\n\tstruct config_reg *cr;\n\tuint64_t virtio_config_size, max;\n\tconst char *name;\n\tuint32_t newoff;\n\tuint32_t value;\n\tint error;\n\n\tif (vs->vs_flags & VIRTIO_USE_MSIX) {\n\t\tif (baridx == pci_msix_table_bar(pi) ||\n\t\t    baridx == pci_msix_pba_bar(pi)) {\n\t\t\treturn (pci_emul_msix_tread(pi, offset, size));\n\t\t}\n\t}\n\n\t/* XXX probably should do something better than just assert() */\n\tassert(baridx == 0);\n\n\tif (vs->vs_mtx)\n\t\tpthread_mutex_lock(vs->vs_mtx);\n\n\tvc = vs->vs_vc;\n\tname = vc->vc_name;\n\tvalue = size == 1 ? 0xff : size == 2 ? 0xffff : 0xffffffff;\n\n\tif (size != 1 && size != 2 && size != 4)\n\t\tgoto bad;\n\n\tif (pci_msix_enabled(pi))\n\t\tvirtio_config_size = VTCFG_R_CFG1;\n\telse\n\t\tvirtio_config_size = VTCFG_R_CFG0;\n\n\tif (offset >= virtio_config_size) {\n\t\t/*\n\t\t * Subtract off the standard size (including MSI-X\n\t\t * registers if enabled) and dispatch to underlying driver.\n\t\t * If that fails, fall into general code.\n\t\t */\n\t\tnewoff = (uint32_t) (offset - virtio_config_size);\n\t\tmax = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000;\n\t\tif ((newoff + ((unsigned) size)) > max)\n\t\t\tgoto bad;\n\t\terror = (*vc->vc_cfgread)(DEV_SOFTC(vs), ((int) newoff), size, &value);\n\t\tif (!error)\n\t\t\tgoto done;\n\t}\n\nbad:\n\tcr = vi_find_cr((int) offset);\n\tif (cr == NULL || cr->cr_size != size) {\n\t\tif (cr != NULL) {\n\t\t\t/* offset must be OK, so size must be bad */\n\t\t\tfprintf(stderr,\n\t\t\t    \"%s: read from %s: bad size %d\\r\\n\",\n\t\t\t    name, cr->cr_name, size);\n\t\t} else {\n\t\t\tfprintf(stderr,\n\t\t\t    \"%s: read from bad offset/size %jd/%d\\r\\n\",\n\t\t\t    name, (uintmax_t)offset, size);\n\t\t}\n\t\tgoto done;\n\t}\n\n\tswitch (offset) {\n\tcase VTCFG_R_HOSTCAP:\n\t\tvalue = (uint32_t) vc->vc_hv_caps;\n\t\tbreak;\n\tcase VTCFG_R_GUESTCAP:\n\t\tvalue = vs->vs_negotiated_caps;\n\t\tbreak;\n\tcase VTCFG_R_PFN:\n\t\tif (vs->vs_curq < vc->vc_nvq)\n\t\t\tvalue = vs->vs_queues[vs->vs_curq].vq_pfn;\n\t\tbreak;\n\tcase VTCFG_R_QNUM:\n\t\tvalue = vs->vs_curq < vc->vc_nvq ?\n\t\t    vs->vs_queues[vs->vs_curq].vq_qsize : 0;\n\t\tbreak;\n\tcase VTCFG_R_QSEL:\n\t\tvalue = (uint32_t) (vs->vs_curq);\n\t\tbreak;\n\tcase VTCFG_R_QNOTIFY:\n\t\tvalue = 0;\t/* XXX */\n\t\tbreak;\n\tcase VTCFG_R_STATUS:\n\t\tvalue = vs->vs_status;\n\t\tbreak;\n\tcase VTCFG_R_ISR:\n\t\tvalue = vs->vs_isr;\n\t\tvs->vs_isr = 0;\t\t/* a read clears this flag */\n\t\tif (value)\n\t\t\tpci_lintr_deassert(pi);\n\t\tbreak;\n\tcase VTCFG_R_CFGVEC:\n\t\tvalue = vs->vs_msix_cfg_idx;\n\t\tbreak;\n\tcase VTCFG_R_QVEC:\n\t\tvalue = vs->vs_curq < vc->vc_nvq ?\n\t\t    vs->vs_queues[vs->vs_curq].vq_msix_idx :\n\t\t    VIRTIO_MSI_NO_VECTOR;\n\t\tbreak;\n\t}\ndone:\n\tif (vs->vs_mtx)\n\t\tpthread_mutex_unlock(vs->vs_mtx);\n\treturn (value);\n}\n\n/*\n * Handle pci config space writes.\n * If it's to the MSI-X info, do that.\n * If it's part of the virtio standard stuff, do that.\n * Otherwise dispatch to the actual driver.\n */\nvoid\nvi_pci_write(UNUSED int vcpu, struct pci_devinst *pi, int baridx,\n\tuint64_t offset, int size, uint64_t value)\n{\n\tstruct virtio_softc *vs = pi->pi_arg;\n\tstruct vqueue_info *vq;\n\tstruct virtio_consts *vc;\n\tstruct config_reg *cr;\n\tuint64_t virtio_config_size, max;\n\tconst char *name;\n\tuint32_t newoff;\n\tint error;\n\n\tif (vs->vs_flags & VIRTIO_USE_MSIX) {\n\t\tif (baridx == pci_msix_table_bar(pi) ||\n\t\t    baridx == pci_msix_pba_bar(pi)) {\n\t\t\tpci_emul_msix_twrite(pi, offset, size, value);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* XXX probably should do something better than just assert() */\n\tassert(baridx == 0);\n\n\tif (vs->vs_mtx)\n\t\tpthread_mutex_lock(vs->vs_mtx);\n\n\tvc = vs->vs_vc;\n\tname = vc->vc_name;\n\n\tif (size != 1 && size != 2 && size != 4)\n\t\tgoto bad;\n\n\tif (pci_msix_enabled(pi))\n\t\tvirtio_config_size = VTCFG_R_CFG1;\n\telse\n\t\tvirtio_config_size = VTCFG_R_CFG0;\n\n\tif (offset >= virtio_config_size) {\n\t\t/*\n\t\t * Subtract off the standard size (including MSI-X\n\t\t * registers if enabled) and dispatch to underlying driver.\n\t\t */\n\t\tnewoff = (uint32_t) (offset - virtio_config_size);\n\t\tmax = vc->vc_cfgsize ? vc->vc_cfgsize : 0x100000000;\n\t\tif ((newoff + ((unsigned) size)) > max)\n\t\t\tgoto bad;\n\t\terror = (*vc->vc_cfgwrite)(DEV_SOFTC(vs), ((int) newoff), size,\n\t\t\t((uint32_t) value));\n\t\tif (!error)\n\t\t\tgoto done;\n\t}\n\nbad:\n\tcr = vi_find_cr((int) offset);\n\tif (cr == NULL || cr->cr_size != size || cr->cr_ro) {\n\t\tif (cr != NULL) {\n\t\t\t/* offset must be OK, wrong size and/or reg is R/O */\n\t\t\tif (cr->cr_size != size)\n\t\t\t\tfprintf(stderr,\n\t\t\t\t    \"%s: write to %s: bad size %d\\r\\n\",\n\t\t\t\t    name, cr->cr_name, size);\n\t\t\tif (cr->cr_ro)\n\t\t\t\tfprintf(stderr,\n\t\t\t\t    \"%s: write to read-only reg %s\\r\\n\",\n\t\t\t\t    name, cr->cr_name);\n\t\t} else {\n\t\t\tfprintf(stderr,\n\t\t\t    \"%s: write to bad offset/size %jd/%d\\r\\n\",\n\t\t\t    name, (uintmax_t)offset, size);\n\t\t}\n\t\tgoto done;\n\t}\n\n\tswitch (offset) {\n\tcase VTCFG_R_GUESTCAP:\n\t\tvs->vs_negotiated_caps = (uint32_t) (value & vc->vc_hv_caps);\n\t\tif (vc->vc_apply_features)\n\t\t\t(*vc->vc_apply_features)(DEV_SOFTC(vs),\n\t\t\t    vs->vs_negotiated_caps);\n\t\tbreak;\n\tcase VTCFG_R_PFN:\n\t\tif (vs->vs_curq >= vc->vc_nvq)\n\t\t\tgoto bad_qindex;\n\t\tvi_vq_init(vs, ((uint32_t) value));\n\t\tbreak;\n\tcase VTCFG_R_QSEL:\n\t\t/*\n\t\t * Note that the guest is allowed to select an\n\t\t * invalid queue; we just need to return a QNUM\n\t\t * of 0 while the bad queue is selected.\n\t\t */\n\t\tvs->vs_curq = (int) value;\n\t\tbreak;\n\tcase VTCFG_R_QNOTIFY:\n\t\tif (value >= ((uint64_t) vc->vc_nvq)) {\n\t\t\tfprintf(stderr, \"%s: queue %d notify out of range\\r\\n\",\n\t\t\t\tname, (int)value);\n\t\t\tgoto done;\n\t\t}\n\t\tvq = &vs->vs_queues[value];\n\t\tif (vq->vq_notify)\n\t\t\t(*vq->vq_notify)(DEV_SOFTC(vs), vq);\n\t\telse if (vc->vc_qnotify)\n\t\t\t(*vc->vc_qnotify)(DEV_SOFTC(vs), vq);\n\t\telse\n\t\t\tfprintf(stderr,\n\t\t\t    \"%s: qnotify queue %d: missing vq/vc notify\\r\\n\",\n\t\t\t\tname, (int)value);\n\t\tbreak;\n\tcase VTCFG_R_STATUS:\n\t\tvs->vs_status = (uint8_t) value;\n\t\tif (value == 0)\n\t\t\t(*vc->vc_reset)(DEV_SOFTC(vs));\n\t\tbreak;\n\tcase VTCFG_R_CFGVEC:\n\t\tvs->vs_msix_cfg_idx = (uint16_t) value;\n\t\tbreak;\n\tcase VTCFG_R_QVEC:\n\t\tif (vs->vs_curq >= vc->vc_nvq)\n\t\t\tgoto bad_qindex;\n\t\tvq = &vs->vs_queues[vs->vs_curq];\n\t\tvq->vq_msix_idx = (uint16_t) value;\n\t\tbreak;\n\t}\n\tgoto done;\n\nbad_qindex:\n\tfprintf(stderr,\n\t    \"%s: write config reg %s: curq %d >= max %d\\r\\n\",\n\t    name, cr->cr_name, vs->vs_curq, vc->vc_nvq);\ndone:\n\tif (vs->vs_mtx)\n\t\tpthread_mutex_unlock(vs->vs_mtx);\n}\n"
  },
  {
    "path": "src/vmm/intel/vmcs.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <errno.h>\n#include <xhyve/vmm/intel/vmx.h>\n#include <xhyve/vmm/intel/vmcs.h>\n\nstatic uint64_t\nvmcs_fix_regval(uint32_t encoding, uint64_t val)\n{\n\n\tswitch (encoding) {\n\tcase VMCS_GUEST_CR0:\n\t\tval = vmx_fix_cr0(val);\n\t\tbreak;\n\tcase VMCS_GUEST_CR4:\n\t\tval = vmx_fix_cr4(val);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn (val);\n}\n\nstatic uint32_t\nvmcs_field_encoding(int ident)\n{\n\tswitch (ident) {\n\tcase VM_REG_GUEST_CR0:\n\t\treturn (VMCS_GUEST_CR0);\n\tcase VM_REG_GUEST_CR3:\n\t\treturn (VMCS_GUEST_CR3);\n\tcase VM_REG_GUEST_CR4:\n\t\treturn (VMCS_GUEST_CR4);\n\tcase VM_REG_GUEST_DR7:\n\t\treturn (VMCS_GUEST_DR7);\n\tcase VM_REG_GUEST_RSP:\n\t\treturn (VMCS_GUEST_RSP);\n\tcase VM_REG_GUEST_RIP:\n\t\treturn (VMCS_GUEST_RIP);\n\tcase VM_REG_GUEST_RFLAGS:\n\t\treturn (VMCS_GUEST_RFLAGS);\n\tcase VM_REG_GUEST_ES:\n\t\treturn (VMCS_GUEST_ES_SELECTOR);\n\tcase VM_REG_GUEST_CS:\n\t\treturn (VMCS_GUEST_CS_SELECTOR);\n\tcase VM_REG_GUEST_SS:\n\t\treturn (VMCS_GUEST_SS_SELECTOR);\n\tcase VM_REG_GUEST_DS:\n\t\treturn (VMCS_GUEST_DS_SELECTOR);\n\tcase VM_REG_GUEST_FS:\n\t\treturn (VMCS_GUEST_FS_SELECTOR);\n\tcase VM_REG_GUEST_GS:\n\t\treturn (VMCS_GUEST_GS_SELECTOR);\n\tcase VM_REG_GUEST_TR:\n\t\treturn (VMCS_GUEST_TR_SELECTOR);\n\tcase VM_REG_GUEST_LDTR:\n\t\treturn (VMCS_GUEST_LDTR_SELECTOR);\n\tcase VM_REG_GUEST_EFER:\n\t\treturn (VMCS_GUEST_IA32_EFER);\n\tcase VM_REG_GUEST_PDPTE0:\n\t\treturn (VMCS_GUEST_PDPTE0);\n\tcase VM_REG_GUEST_PDPTE1:\n\t\treturn (VMCS_GUEST_PDPTE1);\n\tcase VM_REG_GUEST_PDPTE2:\n\t\treturn (VMCS_GUEST_PDPTE2);\n\tcase VM_REG_GUEST_PDPTE3:\n\t\treturn (VMCS_GUEST_PDPTE3);\n\tdefault:\n\t\treturn ((uint32_t) -1);\n\t}\n\n}\n\nstatic int\nvmcs_seg_desc_encoding(int seg, uint32_t *base, uint32_t *lim, uint32_t *acc)\n{\n\n\tswitch (seg) {\n\tcase VM_REG_GUEST_ES:\n\t\t*base = VMCS_GUEST_ES_BASE;\n\t\t*lim = VMCS_GUEST_ES_LIMIT;\n\t\t*acc = VMCS_GUEST_ES_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_CS:\n\t\t*base = VMCS_GUEST_CS_BASE;\n\t\t*lim = VMCS_GUEST_CS_LIMIT;\n\t\t*acc = VMCS_GUEST_CS_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_SS:\n\t\t*base = VMCS_GUEST_SS_BASE;\n\t\t*lim = VMCS_GUEST_SS_LIMIT;\n\t\t*acc = VMCS_GUEST_SS_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_DS:\n\t\t*base = VMCS_GUEST_DS_BASE;\n\t\t*lim = VMCS_GUEST_DS_LIMIT;\n\t\t*acc = VMCS_GUEST_DS_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_FS:\n\t\t*base = VMCS_GUEST_FS_BASE;\n\t\t*lim = VMCS_GUEST_FS_LIMIT;\n\t\t*acc = VMCS_GUEST_FS_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_GS:\n\t\t*base = VMCS_GUEST_GS_BASE;\n\t\t*lim = VMCS_GUEST_GS_LIMIT;\n\t\t*acc = VMCS_GUEST_GS_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_TR:\n\t\t*base = VMCS_GUEST_TR_BASE;\n\t\t*lim = VMCS_GUEST_TR_LIMIT;\n\t\t*acc = VMCS_GUEST_TR_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_LDTR:\n\t\t*base = VMCS_GUEST_LDTR_BASE;\n\t\t*lim = VMCS_GUEST_LDTR_LIMIT;\n\t\t*acc = VMCS_GUEST_LDTR_ACCESS_RIGHTS;\n\t\tbreak;\n\tcase VM_REG_GUEST_IDTR:\n\t\t*base = VMCS_GUEST_IDTR_BASE;\n\t\t*lim = VMCS_GUEST_IDTR_LIMIT;\n\t\t*acc = VMCS_INVALID_ENCODING;\n\t\tbreak;\n\tcase VM_REG_GUEST_GDTR:\n\t\t*base = VMCS_GUEST_GDTR_BASE;\n\t\t*lim = VMCS_GUEST_GDTR_LIMIT;\n\t\t*acc = VMCS_INVALID_ENCODING;\n\t\tbreak;\n\tdefault:\n\t\treturn (EINVAL);\n\t}\n\n\treturn (0);\n}\n\nint\nvmcs_getreg(int vcpuid, int ident, uint64_t *retval)\n{\n\tuint32_t encoding;\n\n\t/*\n\t * If we need to get at vmx-specific state in the VMCS we can bypass\n\t * the translation of 'ident' to 'encoding' by simply setting the\n\t * sign bit. As it so happens the upper 16 bits are reserved (i.e\n\t * set to 0) in the encodings for the VMCS so we are free to use the\n\t * sign bit.\n\t */\n\tif (ident < 0)\n\t\tencoding = ident & 0x7fffffff;\n\telse\n\t\tencoding = vmcs_field_encoding(ident);\n\n\tif (encoding == (uint32_t)-1)\n\t\treturn (EINVAL);\n\n\t*retval = vmcs_read(vcpuid, encoding);\n\n\treturn (0);\n}\n\nint\nvmcs_setreg(int vcpuid, int ident, uint64_t val)\n{\n\tuint32_t encoding;\n\n\tif (ident < 0)\n\t\tencoding = ident & 0x7fffffff;\n\telse\n\t\tencoding = vmcs_field_encoding(ident);\n\n\tif (encoding == (uint32_t)-1)\n\t\treturn (EINVAL);\n\n\tval = vmcs_fix_regval(encoding, val);\n\n\tvmcs_write(vcpuid, encoding, val);\n\n\treturn (0);\n}\n\nint\nvmcs_setdesc(int vcpuid, int seg, struct seg_desc *desc)\n{\n\tint error;\n\tuint32_t base, limit, access;\n\n\terror = vmcs_seg_desc_encoding(seg, &base, &limit, &access);\n\tif (error != 0)\n\t\txhyve_abort(\"vmcs_setdesc: invalid segment register %d\\n\", seg);\n\n\tvmcs_write(vcpuid, base, desc->base);\n\tvmcs_write(vcpuid, limit, desc->limit);\n\tif (access != VMCS_INVALID_ENCODING) {\n\t\tvmcs_write(vcpuid, access, desc->access);\n\t}\n\n\treturn (0);\n}\n\nint\nvmcs_getdesc(int vcpuid, int seg, struct seg_desc *desc)\n{\n\tint error;\n\tuint32_t base, limit, access;\n\n\terror = vmcs_seg_desc_encoding(seg, &base, &limit, &access);\n\tif (error != 0)\n\t\txhyve_abort(\"vmcs_setdesc: invalid segment register %d\\n\", seg);\n\n\tdesc->base = vmcs_read(vcpuid, base);\n\tdesc->limit = (uint32_t) vmcs_read(vcpuid, limit);\n\tif (access != VMCS_INVALID_ENCODING) {\n\t\tdesc->access = (uint32_t) vmcs_read(vcpuid, access);\n\t}\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/vmm/intel/vmx.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include <errno.h>\n#include <assert.h>\n#include <Hypervisor/hv.h>\n#include <Hypervisor/hv_vmx.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/psl.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_instruction_emul.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/vmm_host.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/vmm_stat.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vlapic.h>\n#include <xhyve/vmm/io/vlapic_priv.h>\n#include <xhyve/vmm/intel/vmx.h>\n#include <xhyve/vmm/intel/vmx_msr.h>\n#include <xhyve/vmm/x86.h>\n#include <xhyve/vmm/intel/vmx_controls.h>\n\n#define PROCBASED_CTLS_WINDOW_SETTING \\\n\t(PROCBASED_INT_WINDOW_EXITING | \\\n\t PROCBASED_NMI_WINDOW_EXITING)\n#define PROCBASED_CTLS_ONE_SETTING \\\n\t(PROCBASED_SECONDARY_CONTROLS | \\\n\t PROCBASED_MWAIT_EXITING | \\\n\t PROCBASED_MONITOR_EXITING | \\\n\t PROCBASED_IO_EXITING | \\\n\t PROCBASED_MSR_BITMAPS | \\\n\t PROCBASED_CTLS_WINDOW_SETTING | \\\n\t PROCBASED_CR8_LOAD_EXITING | \\\n\t PROCBASED_CR8_STORE_EXITING | \\\n\t PROCBASED_HLT_EXITING | \\\n\t PROCBASED_TSC_OFFSET)\n#define PROCBASED_CTLS_ZERO_SETTING \\\n\t(PROCBASED_CR3_LOAD_EXITING | \\\n\t PROCBASED_CR3_STORE_EXITING | \\\n\t PROCBASED_IO_BITMAPS | \\\n\t PROCBASED_RDTSC_EXITING | \\\n\t PROCBASED_USE_TPR_SHADOW | \\\n\t PROCBASED_MOV_DR_EXITING | \\\n\t PROCBASED_MTF | \\\n\t PROCBASED_INVLPG_EXITING | \\\n\t PROCBASED_PAUSE_EXITING)\n#define PROCBASED_CTLS2_ONE_SETTING \\\n\t(PROCBASED2_ENABLE_EPT | \\\n\t PROCBASED2_UNRESTRICTED_GUEST | \\\n\t PROCBASED2_ENABLE_VPID | \\\n\t PROCBASED2_ENABLE_RDTSCP)\n#define PROCBASED_CTLS2_ZERO_SETTING \\\n\t(PROCBASED2_VIRTUALIZE_APIC_ACCESSES | \\\n\t PROCBASED2_DESC_TABLE_EXITING | \\\n\t PROCBASED2_WBINVD_EXITING | \\\n\t PROCBASED2_PAUSE_LOOP_EXITING /* FIXME */ | \\\n\t PROCBASED2_RDRAND_EXITING | \\\n\t PROCBASED2_ENABLE_INVPCID /* FIXME */ | \\\n\t PROCBASED2_RDSEED_EXITING | \\\n\t PROCBASED2_ENABLE_XSAVES_XRSTORS | \\\n\t PROCBASED2_VMCS_SHADOW )\n#define PINBASED_CTLS_ONE_SETTING \\\n\t(PINBASED_EXTINT_EXITING | \\\n\t PINBASED_NMI_EXITING | \\\n\t PINBASED_VIRTUAL_NMI)\n#define PINBASED_CTLS_ZERO_SETTING \\\n\t(PINBASED_PREMPTION_TIMER)\n#define VM_ENTRY_CTLS_ONE_SETTING \\\n\t(VM_ENTRY_LOAD_EFER)\n#define VM_ENTRY_CTLS_ZERO_SETTING \\\n\t(VM_ENTRY_INTO_SMM | \\\n\t VM_ENTRY_DEACTIVATE_DUAL_MONITOR | \\\n\t VM_ENTRY_LOAD_PERF_GLOBAL_CTRL | \\\n\t VM_ENTRY_GUEST_LMA)\n#define  VM_EXIT_CTLS_ONE_SETTING \\\n\t(VM_EXIT_HOST_LMA | \\\n\t VM_EXIT_LOAD_EFER)\n#define VM_EXIT_CTLS_ZERO_SETTING \\\n\t(VM_EXIT_SAVE_PREEMPTION_TIMER | \\\n\t VM_EXIT_SAVE_EFER | \\\n\t VM_EXIT_LOAD_PERF_GLOBAL_CTRL)\n#define NMI_BLOCKING \\\n\t(VMCS_INTERRUPTIBILITY_NMI_BLOCKING | \\\n\t VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)\n#define HWINTR_BLOCKING \\\n\t(VMCS_INTERRUPTIBILITY_STI_BLOCKING | \\\n\t VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)\n\n#define\tHANDLED\t\t1\n#define\tUNHANDLED\t0\n\nstatic uint64_t cr0_ones_mask, cr0_zeros_mask;\nstatic uint64_t cr4_ones_mask, cr4_zeros_mask;\n\n/*\n * Optional capabilities\n */\n\nstatic int cap_halt_exit;\nstatic int cap_pause_exit;\n// static int cap_unrestricted_guest;\nstatic int cap_monitor_trap;\n// static int cap_invpcid;\n// static int pirvec = -1;\n// static struct unrhdr *vpid_unr;\n// static u_int vpid_alloc_failed;\n\n/*\n * Use the last page below 4GB as the APIC access address. This address is\n * occupied by the boot firmware so it is guaranteed that it will not conflict\n * with a page in system memory.\n */\n// #define\tAPIC_ACCESS_ADDRESS\t0xFFFFF000\n\nstatic int vmx_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc);\nstatic int vmx_getreg(void *arg, int vcpu, int reg, uint64_t *retval);\n\nstatic __inline uint64_t\nreg_read(int vcpuid, hv_x86_reg_t reg) {\n\tuint64_t val;\n\n\thv_vcpu_read_register(((hv_vcpuid_t) vcpuid), reg, &val);\n\treturn val;\n}\n\nstatic __inline void\nreg_write(int vcpuid, hv_x86_reg_t reg, uint64_t val) {\n\thv_vcpu_write_register(((hv_vcpuid_t) vcpuid), reg, val);\n}\n\nstatic void hvdump(int vcpu) {\n\tprintf(\"VMCS_PIN_BASED_CTLS:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_PIN_BASED_CTLS));\n\tprintf(\"VMCS_PRI_PROC_BASED_CTLS:      0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_PRI_PROC_BASED_CTLS));\n\tprintf(\"VMCS_SEC_PROC_BASED_CTLS:      0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_SEC_PROC_BASED_CTLS));\n\tprintf(\"VMCS_ENTRY_CTLS:               0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_ENTRY_CTLS));\n\tprintf(\"VMCS_EXCEPTION_BITMAP:         0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_EXCEPTION_BITMAP));\n\tprintf(\"VMCS_CR0_MASK:                 0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_CR0_MASK));\n\tprintf(\"VMCS_CR0_SHADOW:               0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_CR0_SHADOW));\n\tprintf(\"VMCS_CR4_MASK:                 0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_CR4_MASK));\n\tprintf(\"VMCS_CR4_SHADOW:               0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_CR4_SHADOW));\n\tprintf(\"VMCS_GUEST_CS_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CS_SELECTOR));\n\tprintf(\"VMCS_GUEST_CS_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CS_LIMIT));\n\tprintf(\"VMCS_GUEST_CS_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CS_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_CS_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CS_BASE));\n\tprintf(\"VMCS_GUEST_DS_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_DS_SELECTOR));\n\tprintf(\"VMCS_GUEST_DS_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_DS_LIMIT));\n\tprintf(\"VMCS_GUEST_DS_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_DS_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_DS_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_DS_BASE));\n\tprintf(\"VMCS_GUEST_ES_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_ES_SELECTOR));\n\tprintf(\"VMCS_GUEST_ES_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_ES_LIMIT));\n\tprintf(\"VMCS_GUEST_ES_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_ES_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_ES_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_ES_BASE));\n\tprintf(\"VMCS_GUEST_FS_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_FS_SELECTOR));\n\tprintf(\"VMCS_GUEST_FS_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_FS_LIMIT));\n\tprintf(\"VMCS_GUEST_FS_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_FS_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_FS_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_FS_BASE));\n\tprintf(\"VMCS_GUEST_GS_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_GS_SELECTOR));\n\tprintf(\"VMCS_GUEST_GS_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_GS_LIMIT));\n\tprintf(\"VMCS_GUEST_GS_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_GS_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_GS_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_GS_BASE));\n\tprintf(\"VMCS_GUEST_SS_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_SS_SELECTOR));\n\tprintf(\"VMCS_GUEST_SS_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_SS_LIMIT));\n\tprintf(\"VMCS_GUEST_SS_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_SS_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_SS_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_SS_BASE));\n\tprintf(\"VMCS_GUEST_LDTR_SELECTOR:      0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_LDTR_SELECTOR));\n\tprintf(\"VMCS_GUEST_LDTR_LIMIT:         0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_LDTR_LIMIT));\n\tprintf(\"VMCS_GUEST_LDTR_ACCESS_RIGHTS: 0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_LDTR_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_LDTR_BASE:          0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_LDTR_BASE));\n\tprintf(\"VMCS_GUEST_TR_SELECTOR:        0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_TR_SELECTOR));\n\tprintf(\"VMCS_GUEST_TR_LIMIT:           0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_TR_LIMIT));\n\tprintf(\"VMCS_GUEST_TR_ACCESS_RIGHTS:   0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS));\n\tprintf(\"VMCS_GUEST_TR_BASE:            0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_TR_BASE));\n\tprintf(\"VMCS_GUEST_GDTR_LIMIT:         0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_GDTR_LIMIT));\n\tprintf(\"VMCS_GUEST_GDTR_BASE:          0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_GDTR_BASE));\n\tprintf(\"VMCS_GUEST_IDTR_LIMIT:         0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_LDTR_LIMIT));\n\tprintf(\"VMCS_GUEST_IDTR_BASE:          0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_LDTR_BASE));\n\tprintf(\"VMCS_GUEST_CR0:                0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CR0));\n\tprintf(\"VMCS_GUEST_CR3:                0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CR3));\n\tprintf(\"VMCS_GUEST_CR4:                0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_CR4));\n\tprintf(\"VMCS_GUEST_IA32_EFER:          0x%016llx\\n\",\n\t\tvmcs_read(vcpu, VMCS_GUEST_IA32_EFER));\n\tprintf(\"\\n\");\n\tprintf(\"rip: 0x%016llx rfl: 0x%016llx cr2: 0x%016llx\\n\",\n\t\treg_read(vcpu, HV_X86_RIP), reg_read(vcpu, HV_X86_RFLAGS),\n\t\treg_read(vcpu, HV_X86_CR2));\n\tprintf(\"rax: 0x%016llx rbx: 0x%016llx rcx: 0x%016llx rdx: 0x%016llx\\n\",\n\t\treg_read(vcpu, HV_X86_RAX), reg_read(vcpu, HV_X86_RBX),\n\t\treg_read(vcpu, HV_X86_RCX), reg_read(vcpu, HV_X86_RDX));\n\tprintf(\"rsi: 0x%016llx rdi: 0x%016llx rbp: 0x%016llx rsp: 0x%016llx\\n\",\n\t\treg_read(vcpu, HV_X86_RSI), reg_read(vcpu, HV_X86_RDI),\n\t\treg_read(vcpu, HV_X86_RBP), reg_read(vcpu, HV_X86_RSP));\n\tprintf(\"r8:  0x%016llx r9:  0x%016llx r10: 0x%016llx r11: 0x%016llx\\n\",\n\t\treg_read(vcpu, HV_X86_R8), reg_read(vcpu, HV_X86_R9),\n\t\treg_read(vcpu, HV_X86_R10), reg_read(vcpu, HV_X86_R11));\n\tprintf(\"r12: 0x%016llx r13: 0x%016llx r14: 0x%016llx r15: 0x%016llx\\n\",\n\t\treg_read(vcpu, HV_X86_R12), reg_read(vcpu, HV_X86_R12),\n\t\treg_read(vcpu, HV_X86_R14), reg_read(vcpu, HV_X86_R15));\n}\n\n#ifdef XHYVE_CONFIG_TRACE\nstatic const char *\nexit_reason_to_str(int reason)\n{\n\tstatic char reasonbuf[32];\n\n\tswitch (reason) {\n\tcase EXIT_REASON_EXCEPTION:\n\t\treturn \"exception\";\n\tcase EXIT_REASON_EXT_INTR:\n\t\treturn \"extint\";\n\tcase EXIT_REASON_TRIPLE_FAULT:\n\t\treturn \"triplefault\";\n\tcase EXIT_REASON_INIT:\n\t\treturn \"init\";\n\tcase EXIT_REASON_SIPI:\n\t\treturn \"sipi\";\n\tcase EXIT_REASON_IO_SMI:\n\t\treturn \"iosmi\";\n\tcase EXIT_REASON_SMI:\n\t\treturn \"smi\";\n\tcase EXIT_REASON_INTR_WINDOW:\n\t\treturn \"intrwindow\";\n\tcase EXIT_REASON_NMI_WINDOW:\n\t\treturn \"nmiwindow\";\n\tcase EXIT_REASON_TASK_SWITCH:\n\t\treturn \"taskswitch\";\n\tcase EXIT_REASON_CPUID:\n\t\treturn \"cpuid\";\n\tcase EXIT_REASON_GETSEC:\n\t\treturn \"getsec\";\n\tcase EXIT_REASON_HLT:\n\t\treturn \"hlt\";\n\tcase EXIT_REASON_INVD:\n\t\treturn \"invd\";\n\tcase EXIT_REASON_INVLPG:\n\t\treturn \"invlpg\";\n\tcase EXIT_REASON_RDPMC:\n\t\treturn \"rdpmc\";\n\tcase EXIT_REASON_RDTSC:\n\t\treturn \"rdtsc\";\n\tcase EXIT_REASON_RSM:\n\t\treturn \"rsm\";\n\tcase EXIT_REASON_VMCALL:\n\t\treturn \"vmcall\";\n\tcase EXIT_REASON_VMCLEAR:\n\t\treturn \"vmclear\";\n\tcase EXIT_REASON_VMLAUNCH:\n\t\treturn \"vmlaunch\";\n\tcase EXIT_REASON_VMPTRLD:\n\t\treturn \"vmptrld\";\n\tcase EXIT_REASON_VMPTRST:\n\t\treturn \"vmptrst\";\n\tcase EXIT_REASON_VMREAD:\n\t\treturn \"vmread\";\n\tcase EXIT_REASON_VMRESUME:\n\t\treturn \"vmresume\";\n\tcase EXIT_REASON_VMWRITE:\n\t\treturn \"vmwrite\";\n\tcase EXIT_REASON_VMXOFF:\n\t\treturn \"vmxoff\";\n\tcase EXIT_REASON_VMXON:\n\t\treturn \"vmxon\";\n\tcase EXIT_REASON_CR_ACCESS:\n\t\treturn \"craccess\";\n\tcase EXIT_REASON_DR_ACCESS:\n\t\treturn \"draccess\";\n\tcase EXIT_REASON_INOUT:\n\t\treturn \"inout\";\n\tcase EXIT_REASON_RDMSR:\n\t\treturn \"rdmsr\";\n\tcase EXIT_REASON_WRMSR:\n\t\treturn \"wrmsr\";\n\tcase EXIT_REASON_INVAL_VMCS:\n\t\treturn \"invalvmcs\";\n\tcase EXIT_REASON_INVAL_MSR:\n\t\treturn \"invalmsr\";\n\tcase EXIT_REASON_MWAIT:\n\t\treturn \"mwait\";\n\tcase EXIT_REASON_MTF:\n\t\treturn \"mtf\";\n\tcase EXIT_REASON_MONITOR:\n\t\treturn \"monitor\";\n\tcase EXIT_REASON_PAUSE:\n\t\treturn \"pause\";\n\tcase EXIT_REASON_MCE_DURING_ENTRY:\n\t\treturn \"mce-during-entry\";\n\tcase EXIT_REASON_TPR:\n\t\treturn \"tpr\";\n\tcase EXIT_REASON_APIC_ACCESS:\n\t\treturn \"apic-access\";\n\tcase EXIT_REASON_GDTR_IDTR:\n\t\treturn \"gdtridtr\";\n\tcase EXIT_REASON_LDTR_TR:\n\t\treturn \"ldtrtr\";\n\tcase EXIT_REASON_EPT_FAULT:\n\t\treturn \"eptfault\";\n\tcase EXIT_REASON_EPT_MISCONFIG:\n\t\treturn \"eptmisconfig\";\n\tcase EXIT_REASON_INVEPT:\n\t\treturn \"invept\";\n\tcase EXIT_REASON_RDTSCP:\n\t\treturn \"rdtscp\";\n\tcase EXIT_REASON_VMX_PREEMPT:\n\t\treturn \"vmxpreempt\";\n\tcase EXIT_REASON_INVVPID:\n\t\treturn \"invvpid\";\n\tcase EXIT_REASON_WBINVD:\n\t\treturn \"wbinvd\";\n\tcase EXIT_REASON_XSETBV:\n\t\treturn \"xsetbv\";\n\tcase EXIT_REASON_APIC_WRITE:\n\t\treturn \"apic-write\";\n\tdefault:\n\t\tsnprintf(reasonbuf, sizeof(reasonbuf), \"%d\", reason);\n\t\treturn (reasonbuf);\n\t}\n}\n#endif\t/* XHYVE_CONFIG_TRACE */\n\n// static int\n// vmx_allow_x2apic_msrs(struct vmx *vmx)\n// {\n// \tint i, error;\n\n// \terror = 0;\n\n// \t/*\n// \t * Allow readonly access to the following x2APIC MSRs from the guest.\n// \t */\n// \terror += guest_msr_ro(vmx, MSR_APIC_ID);\n// \terror += guest_msr_ro(vmx, MSR_APIC_VERSION);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LDR);\n// \terror += guest_msr_ro(vmx, MSR_APIC_SVR);\n\n// \tfor (i = 0; i < 8; i++)\n// \t\terror += guest_msr_ro(vmx, MSR_APIC_ISR0 + i);\n\n// \tfor (i = 0; i < 8; i++)\n// \t\terror += guest_msr_ro(vmx, MSR_APIC_TMR0 + i);\n\t\n// \tfor (i = 0; i < 8; i++)\n// \t\terror += guest_msr_ro(vmx, MSR_APIC_IRR0 + i);\n\n// \terror += guest_msr_ro(vmx, MSR_APIC_ESR);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LVT_TIMER);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LVT_THERMAL);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LVT_PCINT);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LVT_LINT0);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LVT_LINT1);\n// \terror += guest_msr_ro(vmx, MSR_APIC_LVT_ERROR);\n// \terror += guest_msr_ro(vmx, MSR_APIC_ICR_TIMER);\n// \terror += guest_msr_ro(vmx, MSR_APIC_DCR_TIMER);\n// \terror += guest_msr_ro(vmx, MSR_APIC_ICR);\n\n// \t/*\n// \t * Allow TPR, EOI and SELF_IPI MSRs to be read and written by the guest.\n// \t *\n// \t * These registers get special treatment described in the section\n// \t * \"Virtualizing MSR-Based APIC Accesses\".\n// \t */\n// \terror += guest_msr_rw(vmx, MSR_APIC_TPR);\n// \terror += guest_msr_rw(vmx, MSR_APIC_EOI);\n// \terror += guest_msr_rw(vmx, MSR_APIC_SELF_IPI);\n\n// \treturn (error);\n// }\n\nu_long\nvmx_fix_cr0(u_long cr0)\n{\n\treturn ((cr0 | cr0_ones_mask) & ~cr0_zeros_mask);\n}\n\nu_long\nvmx_fix_cr4(u_long cr4)\n{\n\treturn ((cr4 | cr4_ones_mask) & ~cr4_zeros_mask);\n}\n\nstatic int\nvmx_cleanup(void)\n{\n\treturn (0);\n}\n\nstatic int\nvmx_init(void)\n{\n\tint error = hv_vm_create(HV_VM_DEFAULT);\n\tswitch (error) {\n\t\tcase HV_SUCCESS:\n\t\t\tbreak;\n\t\tcase HV_ERROR:\n\t\t\t/* Don't know if this can happen, report to us */\n\t\t\txhyve_abort(\"hv_vm_create HV_ERROR\\n\");\n\t\tcase HV_BUSY:\n\t\t\t/* Should never happen, report to us (perhaps we need to retry) */\n\t\t\txhyve_abort(\"hv_vm_create HV_BUSY\\n\");\n\t\tcase HV_BAD_ARGUMENT:\n\t\t\t/* Should never happen, report to Apple */\n\t\t\txhyve_abort(\"hv_vm_create HV_BAD_ARGUMENT\\n\");\n\t\tcase HV_NO_RESOURCES:\n\t\t\t/* Don't know if this can happen, report to us */\n\t\t\txhyve_abort(\"hv_vm_create HV_NO_RESOURCES\\n\");\n\t\tcase HV_NO_DEVICE:\n\t\t\tprintf(\"vmx_init: processor not supported by \"\n\t\t\t       \"Hypervisor.framework\\n\");\n\t\t\treturn (error);\n\t\tcase HV_UNSUPPORTED:\n\t\t\t/* Don't know if this can happen, report to us */\n\t\t\txhyve_abort(\"hv_vm_create HV_UNSUPPORTED\\n\");\n\t\tdefault:\n\t\t\t/* Should never happen, report to Apple */\n\t\t\txhyve_abort(\"hv_vm_create unknown error %d\\n\", error);\n\t}\n\n\t/*\n\t * Check support for optional features by testing them\n\t * as individual bits\n\t */\n\tcap_halt_exit = 1;\n\tcap_monitor_trap = 1;\n\tcap_pause_exit = 1;\n\t// cap_unrestricted_guest = 1;\n\t// cap_invpcid = 1;\n\n\t/* FIXME */\n  \tcr0_ones_mask = cr4_ones_mask = 0;\n  \tcr0_zeros_mask = cr4_zeros_mask = 0;\n\n  \tcr0_ones_mask |= (CR0_NE | CR0_ET);\n  \tcr0_zeros_mask |= (CR0_NW | CR0_CD);\n  \tcr4_ones_mask = 0x2000;\n\n\tvmx_msr_init();\n\n\treturn (0);\n}\n\nstatic int\nvmx_setup_cr_shadow(int vcpuid, int which, uint32_t initial)\n{\n\tint error, mask_ident, shadow_ident;\n\tuint64_t mask_value;\n\n\tif (which != 0 && which != 4)\n\t\txhyve_abort(\"vmx_setup_cr_shadow: unknown cr%d\", which);\n\n\tif (which == 0) {\n\t\tmask_ident = VMCS_CR0_MASK;\n\t\tmask_value = (cr0_ones_mask | cr0_zeros_mask) | (CR0_PG | CR0_PE);\n\t\tshadow_ident = VMCS_CR0_SHADOW;\n\t} else {\n\t\tmask_ident = VMCS_CR4_MASK;\n\t\tmask_value = cr4_ones_mask | cr4_zeros_mask;\n\t\tshadow_ident = VMCS_CR4_SHADOW;\n\t}\n\n\terror = vmcs_setreg(vcpuid, VMCS_IDENT(mask_ident), mask_value);\n\tif (error)\n\t\treturn (error);\n\n\terror = vmcs_setreg(vcpuid, VMCS_IDENT(shadow_ident), initial);\n\tif (error)\n\t\treturn (error);\n\n\treturn (0);\n}\n#define\tvmx_setup_cr0_shadow(vcpuid,init) vmx_setup_cr_shadow(vcpuid, 0, (init))\n#define\tvmx_setup_cr4_shadow(vcpuid,init) vmx_setup_cr_shadow(vcpuid, 4, (init))\n\nstatic void *\nvmx_vm_init(struct vm *vm)\n{\n\tstruct vmx *vmx;\n\n\tvmx = malloc(sizeof(struct vmx));\n\tassert(vmx);\n\tbzero(vmx, sizeof(struct vmx));\n\tvmx->vm = vm;\n\n\treturn (vmx);\n}\n\nstatic int\nvmx_vcpu_init(void *arg, int vcpuid) {\n\tuint32_t exc_bitmap;\n\tstruct vmx *vmx;\n\thv_vcpuid_t hvid;\n\tint error;\n\n\tvmx = (struct vmx *) arg;\n\n\tif (hv_vcpu_create(&hvid, HV_VCPU_DEFAULT)) {\n\t\txhyve_abort(\"hv_vcpu_create failed\\n\");\n\t}\n\n\tif (hvid != ((hv_vcpuid_t) vcpuid)) {\n\t\t/* FIXME */\n\t\txhyve_abort(\"vcpu id mismatch\\n\");\n\t}\n\n\tif (hv_vcpu_enable_native_msr(hvid, MSR_GSBASE, 1) ||\n\t\thv_vcpu_enable_native_msr(hvid, MSR_FSBASE, 1) ||\n\t\thv_vcpu_enable_native_msr(hvid, MSR_SYSENTER_CS_MSR, 1) ||\n\t\thv_vcpu_enable_native_msr(hvid, MSR_SYSENTER_ESP_MSR, 1) ||\n\t\thv_vcpu_enable_native_msr(hvid, MSR_SYSENTER_EIP_MSR, 1) ||\n\t\thv_vcpu_enable_native_msr(hvid, MSR_TSC, 1) ||\n\t\thv_vcpu_enable_native_msr(hvid, MSR_IA32_TSC_AUX, 1))\n\t{\n\t\txhyve_abort(\"vmx_vcpu_init: error setting guest msr access\\n\");\n\t}\n\n\tvmx_msr_guest_init(vmx, vcpuid);\n\n\tuint32_t pinbased_ctls = 0;\n\tuint32_t procbased_ctls = 0;\n\tuint32_t procbased_ctls2 = 0;\n\tuint32_t exit_ctls = 0;\n\tvmx->state[vcpuid].entry_ctls = 0;\n\t\n\t/* Check support for primary processor-based VM-execution controls */\n\terror = vmx_set_ctlreg(vcpuid, VMCS_PRI_PROC_BASED_CTLS,\n\t\t\t\t\t\t   HV_VMX_CAP_PROCBASED,\n\t\t\t\t\t\t   PROCBASED_CTLS_ONE_SETTING,\n\t\t\t\t\t\t   PROCBASED_CTLS_ZERO_SETTING, &procbased_ctls);\n\tif (error) {\n\t\tprintf(\"vmx_init: processor does not support desired primary \"\n\t\t\t   \"processor-based controls\\n\");\n\t\treturn (error);\n\t}\n\t\n\t/* Clear the processor-based ctl bits that are set on demand */\n\tprocbased_ctls &= ~PROCBASED_CTLS_WINDOW_SETTING;\n\t\n\t/* Check support for secondary processor-based VM-execution controls */\n\terror = vmx_set_ctlreg(vcpuid, VMCS_SEC_PROC_BASED_CTLS, HV_VMX_CAP_PROCBASED2,\n\t\t\t\t\t\t   PROCBASED_CTLS2_ONE_SETTING,\n\t\t\t\t\t\t   PROCBASED_CTLS2_ZERO_SETTING, &procbased_ctls2);\n\tif (error) {\n\t\tprintf(\"vmx_init: processor does not support desired secondary \"\n\t\t\t   \"processor-based controls\\n\");\n\t\treturn (error);\n\t}\n\t\n\t/* Check support for pin-based VM-execution controls */\n\terror = vmx_set_ctlreg(vcpuid, VMCS_PIN_BASED_CTLS, HV_VMX_CAP_PINBASED,\n\t\t\t\t\t\t   PINBASED_CTLS_ONE_SETTING,\n\t\t\t\t\t\t   PINBASED_CTLS_ZERO_SETTING, &pinbased_ctls);\n\tif (error) {\n\t\tprintf(\"vmx_init: processor does not support desired \"\n\t\t\t   \"pin-based controls\\n\");\n\t\treturn (error);\n\t}\n\t\n\t/* Check support for VM-exit controls */\n\terror = vmx_set_ctlreg(vcpuid, VMCS_EXIT_CTLS, HV_VMX_CAP_EXIT,\n\t\t\t\t\t\t   VM_EXIT_CTLS_ONE_SETTING,\n\t\t\t\t\t\t   VM_EXIT_CTLS_ZERO_SETTING,\n\t\t\t\t\t\t   &exit_ctls);\n\tif (error) {\n\t\tprintf(\"vmx_init: processor does not support desired \"\n\t\t\t   \"exit controls\\n\");\n\t\treturn (error);\n\t}\n\t\n\t/* Check support for VM-entry controls */\n\terror = vmx_set_ctlreg(vcpuid, VMCS_ENTRY_CTLS, HV_VMX_CAP_ENTRY,\n\t\t\t\t\t\t   VM_ENTRY_CTLS_ONE_SETTING, VM_ENTRY_CTLS_ZERO_SETTING,\n\t\t\t\t\t\t   &vmx->state[vcpuid].entry_ctls);\n\tif (error) {\n\t\tprintf(\"vmx_init: processor does not support desired \"\n\t\t\t   \"entry controls\\n\");\n\t\treturn (error);\n\t}\n\t\n\tvmcs_write(vcpuid, VMCS_PIN_BASED_CTLS, pinbased_ctls);\n\tvmcs_write(vcpuid, VMCS_PRI_PROC_BASED_CTLS, procbased_ctls);\n\tvmcs_write(vcpuid, VMCS_SEC_PROC_BASED_CTLS, procbased_ctls2);\n\tvmcs_write(vcpuid, VMCS_EXIT_CTLS, exit_ctls);\n\tvmcs_write(vcpuid, VMCS_ENTRY_CTLS, vmx->state[vcpuid].entry_ctls);\n\n\t/* exception bitmap */\n\tif (vcpu_trace_exceptions())\n\t\texc_bitmap = 0xffffffff;\n\telse\n\t\texc_bitmap = 1 << IDT_MC;\n\n\tvmcs_write(vcpuid, VMCS_EXCEPTION_BITMAP, exc_bitmap);\n\n\tvmx->cap[vcpuid].set = 0;\n\tvmx->cap[vcpuid].proc_ctls = procbased_ctls;\n\tvmx->cap[vcpuid].proc_ctls2 = procbased_ctls2;\n\tvmx->state[vcpuid].nextrip = ~(uint64_t) 0;\n\n\t/*\n\t * Set up the CR0/4 shadows, and init the read shadow\n\t * to the power-on register value from the Intel Sys Arch.\n\t *  CR0 - 0x60000010\n\t *  CR4 - 0\n\t */\n\terror = vmx_setup_cr0_shadow(vcpuid, 0x60000010);\n\tif (error != 0)\n\t\txhyve_abort(\"vmx_setup_cr0_shadow %d\\n\", error);\n\n\terror = vmx_setup_cr4_shadow(vcpuid, 0);\n\n\tif (error != 0)\n\t\txhyve_abort(\"vmx_setup_cr4_shadow %d\\n\", error);\n\n\treturn (0);\n}\n\nstatic int\nvmx_handle_cpuid(struct vm *vm, int vcpuid)\n{\n\tuint32_t eax, ebx, ecx, edx;\n\tint error;\n\t\n\teax = (uint32_t) reg_read(vcpuid, HV_X86_RAX);\n\tebx = (uint32_t) reg_read(vcpuid, HV_X86_RBX);\n\tecx = (uint32_t) reg_read(vcpuid, HV_X86_RCX);\n\tedx = (uint32_t) reg_read(vcpuid, HV_X86_RDX);\n\n\terror = x86_emulate_cpuid(vm, vcpuid, &eax, &ebx, &ecx, &edx);\n\n\treg_write(vcpuid, HV_X86_RAX, eax);\n\treg_write(vcpuid, HV_X86_RBX, ebx);\n\treg_write(vcpuid, HV_X86_RCX, ecx);\n\treg_write(vcpuid, HV_X86_RDX, edx);\n\n\treturn (error);\n}\n\nstatic __inline void\nvmx_run_trace(struct vmx *vmx, int vcpu)\n{\n#ifdef XHYVE_CONFIG_TRACE\n\tVCPU_CTR1(vmx->vm, vcpu, \"Resume execution at %#llx\", vmcs_guest_rip(vcpu));\n#else\n\t(void) vmx;\n\t(void) vcpu;\n#endif\n}\n\nstatic __inline void\nvmx_exit_trace(struct vmx *vmx, int vcpu, uint64_t rip, uint32_t exit_reason,\n\t       int handled)\n{\n#ifdef XHYVE_CONFIG_TRACE\n\tVCPU_CTR3(vmx->vm, vcpu, \"%s %s vmexit at 0x%0llx\",\n\t\t handled ? \"handled\" : \"unhandled\",\n\t\t exit_reason_to_str((int) exit_reason), rip);\n#else\n\t(void) vmx;\n\t(void) vcpu;\n\t(void) rip;\n\t(void) exit_reason;\n\t(void) handled;\n#endif\n}\n\n/*\n * We depend on 'procbased_ctls' to have the Interrupt Window Exiting bit set.\n */\nCTASSERT((PROCBASED_CTLS_ONE_SETTING & PROCBASED_INT_WINDOW_EXITING) != 0);\n\nstatic void __inline\nvmx_set_int_window_exiting(struct vmx *vmx, int vcpu)\n{\n\tif ((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) == 0) {\n\t\tvmx->cap[vcpu].proc_ctls |= PROCBASED_INT_WINDOW_EXITING;\n\t\tvmcs_write(vcpu, VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);\n\t\tVCPU_CTR0(vmx->vm, vcpu, \"Enabling interrupt window exiting\");\n\t}\n}\n\nstatic void __inline\nvmx_clear_int_window_exiting(struct vmx *vmx, int vcpu)\n{\n\tKASSERT((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) != 0,\n\t    (\"intr_window_exiting not set: %#x\", vmx->cap[vcpu].proc_ctls));\n\tvmx->cap[vcpu].proc_ctls &= ~PROCBASED_INT_WINDOW_EXITING;\n\tvmcs_write(vcpu, VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);\n\tVCPU_CTR0(vmx->vm, vcpu, \"Disabling interrupt window exiting\");\n}\n\nstatic void __inline\nvmx_set_nmi_window_exiting(struct vmx *vmx, int vcpu)\n{\n\n\tif ((vmx->cap[vcpu].proc_ctls & PROCBASED_NMI_WINDOW_EXITING) == 0) {\n\t\tvmx->cap[vcpu].proc_ctls |= PROCBASED_NMI_WINDOW_EXITING;\n\t\tvmcs_write(vcpu, VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);\n\t\tVCPU_CTR0(vmx->vm, vcpu, \"Enabling NMI window exiting\");\n\t}\n}\n\nstatic void __inline\nvmx_clear_nmi_window_exiting(struct vmx *vmx, int vcpu)\n{\n\n\tKASSERT((vmx->cap[vcpu].proc_ctls & PROCBASED_NMI_WINDOW_EXITING) != 0,\n\t    (\"nmi_window_exiting not set %#x\", vmx->cap[vcpu].proc_ctls));\n\tvmx->cap[vcpu].proc_ctls &= ~PROCBASED_NMI_WINDOW_EXITING;\n\tvmcs_write(vcpu, VMCS_PRI_PROC_BASED_CTLS, vmx->cap[vcpu].proc_ctls);\n\tVCPU_CTR0(vmx->vm, vcpu, \"Disabling NMI window exiting\");\n}\n\nstatic void\nvmx_inject_nmi(struct vmx *vmx, int vcpu)\n{\n\tuint32_t gi, info;\n\n\tgi = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_INTERRUPTIBILITY);\n\tKASSERT((gi & NMI_BLOCKING) == 0, (\"vmx_inject_nmi: invalid guest \"\n\t    \"interruptibility-state %#x\", gi));\n\n\tinfo = (uint32_t) vmcs_read(vcpu, VMCS_ENTRY_INTR_INFO);\n\tKASSERT((info & VMCS_INTR_VALID) == 0, (\"vmx_inject_nmi: invalid \"\n\t    \"VM-entry interruption information %#x\", info));\n\n\t/*\n\t * Inject the virtual NMI. The vector must be the NMI IDT entry\n\t * or the VMCS entry check will fail.\n\t */\n\tinfo = IDT_NMI | VMCS_INTR_T_NMI | VMCS_INTR_VALID;\n\tvmcs_write(vcpu, VMCS_ENTRY_INTR_INFO, info);\n\n\tVCPU_CTR0(vmx->vm, vcpu, \"Injecting vNMI\");\n\n\t/* Clear the request */\n\tvm_nmi_clear(vmx->vm, vcpu);\n}\n\nstatic void\nvmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic,\n    uint64_t guestrip)\n{\n\tint vector, need_nmi_exiting, extint_pending;\n\tuint64_t rflags, entryinfo;\n\tuint32_t gi, info;\n\n\tif (vmx->state[vcpu].nextrip != guestrip) {\n\t\tgi = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_INTERRUPTIBILITY);\n\t\tif (gi & HWINTR_BLOCKING) {\n\t\t\tVCPU_CTR2(vmx->vm, vcpu, \"Guest interrupt blocking \"\n\t\t\t    \"cleared due to rip change: %#llx/%#llx\",\n\t\t\t    vmx->state[vcpu].nextrip, guestrip);\n\t\t\tgi &= ~HWINTR_BLOCKING;\n\t\t\tvmcs_write(vcpu, VMCS_GUEST_INTERRUPTIBILITY, gi);\n\t\t}\n\t}\n\n\tif (vm_entry_intinfo(vmx->vm, vcpu, &entryinfo)) {\n\t\tKASSERT((entryinfo & VMCS_INTR_VALID) != 0, (\"%s: entry \"\n\t\t    \"intinfo is not valid: %#llx\", __func__, entryinfo));\n\n\t\tinfo = (uint32_t) vmcs_read(vcpu, VMCS_ENTRY_INTR_INFO);\n\t\tKASSERT((info & VMCS_INTR_VALID) == 0, (\"%s: cannot inject \"\n\t\t     \"pending exception: %#llx/%#x\", __func__, entryinfo, info));\n\n\t\tinfo = (uint32_t) entryinfo;\n\t\tvector = info & 0xff;\n\t\tif (vector == IDT_BP || vector == IDT_OF) {\n\t\t\t/*\n\t\t\t * VT-x requires #BP and #OF to be injected as software\n\t\t\t * exceptions.\n\t\t\t */\n\t\t\tinfo &= ~VMCS_INTR_T_MASK;\n\t\t\tinfo |= VMCS_INTR_T_SWEXCEPTION;\n\t\t}\n\n\t\tif (info & VMCS_INTR_DEL_ERRCODE)\n\t\t\tvmcs_write(vcpu, VMCS_ENTRY_EXCEPTION_ERROR, entryinfo >> 32);\n\n\t\tvmcs_write(vcpu, VMCS_ENTRY_INTR_INFO, info);\n\t}\n\n\tif (vm_nmi_pending(vmx->vm, vcpu)) {\n\t\t/*\n\t\t * If there are no conditions blocking NMI injection then\n\t\t * inject it directly here otherwise enable \"NMI window\n\t\t * exiting\" to inject it as soon as we can.\n\t\t *\n\t\t * We also check for STI_BLOCKING because some implementations\n\t\t * don't allow NMI injection in this case. If we are running\n\t\t * on a processor that doesn't have this restriction it will\n\t\t * immediately exit and the NMI will be injected in the\n\t\t * \"NMI window exiting\" handler.\n\t\t */\n\t\tneed_nmi_exiting = 1;\n\t\tgi = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_INTERRUPTIBILITY);\n\t\tif ((gi & (HWINTR_BLOCKING | NMI_BLOCKING)) == 0) {\n\t\t\tinfo = (uint32_t) vmcs_read(vcpu, VMCS_ENTRY_INTR_INFO);\n\t\t\tif ((info & VMCS_INTR_VALID) == 0) {\n\t\t\t\tvmx_inject_nmi(vmx, vcpu);\n\t\t\t\tneed_nmi_exiting = 0;\n\t\t\t} else {\n\t\t\t\tVCPU_CTR1(vmx->vm, vcpu, \"Cannot inject NMI \"\n\t\t\t\t    \"due to VM-entry intr info %#x\", info);\n\t\t\t}\n\t\t} else {\n\t\t\tVCPU_CTR1(vmx->vm, vcpu, \"Cannot inject NMI due to \"\n\t\t\t    \"Guest Interruptibility-state %#x\", gi);\n\t\t}\n\n\t\tif (need_nmi_exiting)\n\t\t\tvmx_set_nmi_window_exiting(vmx, vcpu);\n\t}\n\n\textint_pending = vm_extint_pending(vmx->vm, vcpu);\n\n\t/*\n\t * If interrupt-window exiting is already in effect then don't bother\n\t * checking for pending interrupts. This is just an optimization and\n\t * not needed for correctness.\n\t */\n\tif ((vmx->cap[vcpu].proc_ctls & PROCBASED_INT_WINDOW_EXITING) != 0) {\n\t\tVCPU_CTR0(vmx->vm, vcpu, \"Skip interrupt injection due to \"\n\t\t    \"pending int_window_exiting\");\n\t\treturn;\n\t}\n\n\tif (!extint_pending) {\n\t\t/* Ask the local apic for a vector to inject */\n\t\tif (!vlapic_pending_intr(vlapic, &vector))\n\t\t\treturn;\n\n\t\t/*\n\t\t * From the Intel SDM, Volume 3, Section \"Maskable\n\t\t * Hardware Interrupts\":\n\t\t * - maskable interrupt vectors [16,255] can be delivered\n\t\t *   through the local APIC.\n\t\t*/\n\t\tKASSERT(vector >= 16 && vector <= 255,\n\t\t    (\"invalid vector %d from local APIC\", vector));\n\t} else {\n\t\t/* Ask the legacy pic for a vector to inject */\n\t\tvatpic_pending_intr(vmx->vm, &vector);\n\n\t\t/*\n\t\t * From the Intel SDM, Volume 3, Section \"Maskable\n\t\t * Hardware Interrupts\":\n\t\t * - maskable interrupt vectors [0,255] can be delivered\n\t\t *   through the INTR pin.\n\t\t */\n\t\tKASSERT(vector >= 0 && vector <= 255,\n\t\t    (\"invalid vector %d from INTR\", vector));\n\t}\n\n\t/* Check RFLAGS.IF and the interruptibility state of the guest */\n\trflags = vmcs_read(vcpu, VMCS_GUEST_RFLAGS);\n\tif ((rflags & PSL_I) == 0) {\n\t\tVCPU_CTR2(vmx->vm, vcpu, \"Cannot inject vector %d due to \"\n\t\t    \"rflags %#llx\", vector, rflags);\n\t\tgoto cantinject;\n\t}\n\n\tgi = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_INTERRUPTIBILITY);\n\tif (gi & HWINTR_BLOCKING) {\n\t\tVCPU_CTR2(vmx->vm, vcpu, \"Cannot inject vector %d due to \"\n\t\t    \"Guest Interruptibility-state %#x\", vector, gi);\n\t\tgoto cantinject;\n\t}\n\n\tinfo = (uint32_t) vmcs_read(vcpu, VMCS_ENTRY_INTR_INFO);\n\tif (info & VMCS_INTR_VALID) {\n\t\t/*\n\t\t * This is expected and could happen for multiple reasons:\n\t\t * - A vectoring VM-entry was aborted due to astpending\n\t\t * - A VM-exit happened during event injection.\n\t\t * - An exception was injected above.\n\t\t * - An NMI was injected above or after \"NMI window exiting\"\n\t\t */\n\t\tVCPU_CTR2(vmx->vm, vcpu, \"Cannot inject vector %d due to \"\n\t\t    \"VM-entry intr info %#x\", vector, info);\n\t\tgoto cantinject;\n\t}\n\n\t/* Inject the interrupt */\n\tinfo = VMCS_INTR_T_HWINTR | VMCS_INTR_VALID;\n\tinfo |= (uint32_t) vector;\n\tvmcs_write(vcpu, VMCS_ENTRY_INTR_INFO, info);\n\n\tif (!extint_pending) {\n\t\t/* Update the Local APIC ISR */\n\t\tvlapic_intr_accepted(vlapic, vector);\n\t} else {\n\t\tvm_extint_clear(vmx->vm, vcpu);\n\t\tvatpic_intr_accepted(vmx->vm, vector);\n\n\t\t/*\n\t\t * After we accepted the current ExtINT the PIC may\n\t\t * have posted another one.  If that is the case, set\n\t\t * the Interrupt Window Exiting execution control so\n\t\t * we can inject that one too.\n\t\t *\n\t\t * Also, interrupt window exiting allows us to inject any\n\t\t * pending APIC vector that was preempted by the ExtINT\n\t\t * as soon as possible. This applies both for the software\n\t\t * emulated vlapic and the hardware assisted virtual APIC.\n\t\t */\n\t\tvmx_set_int_window_exiting(vmx, vcpu);\n\t}\n\n\tVCPU_CTR1(vmx->vm, vcpu, \"Injecting hwintr at vector %d\", vector);\n\n\treturn;\n\ncantinject:\n\t/*\n\t * Set the Interrupt Window Exiting execution control so we can inject\n\t * the interrupt as soon as blocking condition goes away.\n\t */\n\tvmx_set_int_window_exiting(vmx, vcpu);\n}\n\n/*\n * If the Virtual NMIs execution control is '1' then the logical processor\n * tracks virtual-NMI blocking in the Guest Interruptibility-state field of\n * the VMCS. An IRET instruction in VMX non-root operation will remove any\n * virtual-NMI blocking.\n *\n * This unblocking occurs even if the IRET causes a fault. In this case the\n * hypervisor needs to restore virtual-NMI blocking before resuming the guest.\n */\nstatic void\nvmx_restore_nmi_blocking(struct vmx *vmx, int vcpuid)\n{\n\tuint32_t gi;\n\n\tVCPU_CTR0(vmx->vm, vcpuid, \"Restore Virtual-NMI blocking\");\n\tgi = (uint32_t) vmcs_read(vcpuid, VMCS_GUEST_INTERRUPTIBILITY);\n\tgi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING;\n\tvmcs_write(vcpuid, VMCS_GUEST_INTERRUPTIBILITY, gi);\n}\n\nstatic void\nvmx_clear_nmi_blocking(struct vmx *vmx, int vcpuid)\n{\n\tuint32_t gi;\n\n\tVCPU_CTR0(vmx->vm, vcpuid, \"Clear Virtual-NMI blocking\");\n\tgi = (uint32_t) vmcs_read(vcpuid, VMCS_GUEST_INTERRUPTIBILITY);\n\tgi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING;\n\tvmcs_write(vcpuid, VMCS_GUEST_INTERRUPTIBILITY, gi);\n}\n\nstatic void\nvmx_assert_nmi_blocking(int vcpuid)\n{\n\tuint32_t gi;\n\n\tgi = (uint32_t) vmcs_read(vcpuid, VMCS_GUEST_INTERRUPTIBILITY);\n\tKASSERT(gi & VMCS_INTERRUPTIBILITY_NMI_BLOCKING,\n\t    (\"NMI blocking is not in effect %#x\", gi));\n}\n\nstatic int\nvmx_emulate_xsetbv(struct vmx *vmx, int vcpu)\n{\n\tuint64_t xcrval;\n\tconst struct xsave_limits *limits;\n\n\tlimits = vmm_get_xsave_limits();\n\n\t/*\n\t * Note that the processor raises a GP# fault on its own if\n\t * xsetbv is executed for CPL != 0, so we do not have to\n\t * emulate that fault here.\n\t */\n\n\t/* Only xcr0 is supported. */\n\tif (reg_read(vcpu, HV_X86_RCX) != 0) {\n\t\tvm_inject_gp(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\t/* We only handle xcr0 if both the host and guest have XSAVE enabled. */\n\tif (!limits->xsave_enabled ||\n\t\t!(vmcs_read(vcpu, VMCS_GUEST_CR4) & CR4_XSAVE))\n\t{\n\t\tvm_inject_ud(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\txcrval = reg_read(vcpu, HV_X86_RDX) << 32\n\t\t| (reg_read(vcpu, HV_X86_RAX) & 0xffffffff);\n\n\tif ((xcrval & ~limits->xcr0_allowed) != 0) {\n\t\tvm_inject_gp(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\tif (!(xcrval & XFEATURE_ENABLED_X87)) {\n\t\tvm_inject_gp(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\t/* AVX (YMM_Hi128) requires SSE. */\n\tif (xcrval & XFEATURE_ENABLED_AVX &&\n\t    (xcrval & XFEATURE_AVX) != XFEATURE_AVX) {\n\t\tvm_inject_gp(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\t/*\n\t * AVX512 requires base AVX (YMM_Hi128) as well as OpMask,\n\t * ZMM_Hi256, and Hi16_ZMM.\n\t */\n\tif (xcrval & XFEATURE_AVX512 &&\n\t    (xcrval & (XFEATURE_AVX512 | XFEATURE_AVX)) !=\n\t    (XFEATURE_AVX512 | XFEATURE_AVX)) {\n\t\tvm_inject_gp(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\t/*\n\t * Intel MPX requires both bound register state flags to be\n\t * set.\n\t */\n\tif (((xcrval & XFEATURE_ENABLED_BNDREGS) != 0) !=\n\t    ((xcrval & XFEATURE_ENABLED_BNDCSR) != 0)) {\n\t\tvm_inject_gp(vmx->vm, vcpu);\n\t\treturn (HANDLED);\n\t}\n\n\treg_write(vcpu, HV_X86_XCR0, xcrval);\n\treturn (HANDLED);\n}\n\nstatic uint64_t\nvmx_get_guest_reg(int vcpu, int ident)\n{\n\tswitch (ident) {\n\tcase 0:\n\t\treturn (reg_read(vcpu, HV_X86_RAX));\n\tcase 1:\n\t\treturn (reg_read(vcpu, HV_X86_RCX));\n\tcase 2:\n\t\treturn (reg_read(vcpu, HV_X86_RDX));\n\tcase 3:\n\t\treturn (reg_read(vcpu, HV_X86_RBX));\n\tcase 4:\n\t\treturn (vmcs_read(vcpu, VMCS_GUEST_RSP));\n\tcase 5:\n\t\treturn (reg_read(vcpu, HV_X86_RBP));\n\tcase 6:\n\t\treturn (reg_read(vcpu, HV_X86_RSI));\n\tcase 7:\n\t\treturn (reg_read(vcpu, HV_X86_RDI));\n\tcase 8:\n\t\treturn (reg_read(vcpu, HV_X86_R8));\n\tcase 9:\n\t\treturn (reg_read(vcpu, HV_X86_R9));\n\tcase 10:\n\t\treturn (reg_read(vcpu, HV_X86_R10));\n\tcase 11:\n\t\treturn (reg_read(vcpu, HV_X86_R11));\n\tcase 12:\n\t\treturn (reg_read(vcpu, HV_X86_R12));\n\tcase 13:\n\t\treturn (reg_read(vcpu, HV_X86_R13));\n\tcase 14:\n\t\treturn (reg_read(vcpu, HV_X86_R14));\n\tcase 15:\n\t\treturn (reg_read(vcpu, HV_X86_R15));\n\tdefault:\n\t\txhyve_abort(\"invalid vmx register %d\", ident);\n\t}\n}\n\nstatic void\nvmx_set_guest_reg(int vcpu, int ident, uint64_t regval)\n{\n\tswitch (ident) {\n\tcase 0:\n\t\treg_write(vcpu, HV_X86_RAX, regval);\n\t\tbreak;\n\tcase 1:\n\t\treg_write(vcpu, HV_X86_RCX, regval);\n\t\tbreak;\n\tcase 2:\n\t\treg_write(vcpu, HV_X86_RDX, regval);\n\t\tbreak;\n\tcase 3:\n\t\treg_write(vcpu, HV_X86_RBX, regval);\n\t\tbreak;\n\tcase 4:\n\t\tvmcs_write(vcpu, VMCS_GUEST_RSP, regval);\n\t\tbreak;\n\tcase 5:\n\t\treg_write(vcpu, HV_X86_RBP, regval);\n\t\tbreak;\n\tcase 6:\n\t\treg_write(vcpu, HV_X86_RSI, regval);\n\t\tbreak;\n\tcase 7:\n\t\treg_write(vcpu, HV_X86_RDI, regval);\n\t\tbreak;\n\tcase 8:\n\t\treg_write(vcpu, HV_X86_R8, regval);\n\t\tbreak;\n\tcase 9:\n\t\treg_write(vcpu, HV_X86_R9, regval);\n\t\tbreak;\n\tcase 10:\n\t\treg_write(vcpu, HV_X86_R10, regval);\n\t\tbreak;\n\tcase 11:\n\t\treg_write(vcpu, HV_X86_R11, regval);\n\t\tbreak;\n\tcase 12:\n\t\treg_write(vcpu, HV_X86_R12, regval);\n\t\tbreak;\n\tcase 13:\n\t\treg_write(vcpu, HV_X86_R13, regval);\n\t\tbreak;\n\tcase 14:\n\t\treg_write(vcpu, HV_X86_R14, regval);\n\t\tbreak;\n\tcase 15:\n\t\treg_write(vcpu, HV_X86_R15, regval);\n\t\tbreak;\n\tdefault:\n\t\txhyve_abort(\"invalid vmx register %d\", ident);\n\t}\n}\n\nstatic int\nvmx_emulate_cr0_access(UNUSED struct vm *vm, int vcpu, uint64_t exitqual)\n{\n\tuint64_t crval, efer, entryctls, regval;\n\t// *pt;\n\n\t/* We only handle mov to %cr0 at this time */\n\tif ((exitqual & 0xf0) != 0x00)\n\t\treturn (UNHANDLED);\n\n\tregval = vmx_get_guest_reg(vcpu, (exitqual >> 8) & 0xf);\n\n\tvmcs_write(vcpu, VMCS_CR0_SHADOW, regval);\n\n\tcrval = regval | cr0_ones_mask;\n\tcrval &= ~cr0_zeros_mask;\n\t// printf(\"cr0: v:0x%016llx 1:0x%08llx 0:0x%08llx v:0x%016llx\\n\",\n\t// \tregval, cr0_ones_mask, cr0_zeros_mask, crval);\n\tvmcs_write(vcpu, VMCS_GUEST_CR0, crval);\n\n\tefer = vmcs_read(vcpu, VMCS_GUEST_IA32_EFER);\n\n\tif (regval & CR0_PG) {\n\t\t/*\n\t\t * If CR0.PG is 1 and EFER.LME is 1 then EFER.LMA and\n\t\t * the \"IA-32e mode guest\" bit in VM-entry control must be\n\t\t * equal.\n\t\t */\n\t\tif (efer & EFER_LME) {\n\t\t\tefer |= EFER_LMA;\n\t\t\tvmcs_write(vcpu, VMCS_GUEST_IA32_EFER, efer);\n\t\t\tentryctls = vmcs_read(vcpu, VMCS_ENTRY_CTLS);\n\t\t\tentryctls |= VM_ENTRY_GUEST_LMA;\n\t\t\tvmcs_write(vcpu, VMCS_ENTRY_CTLS, entryctls);\n\t\t}\n\n\t\t// if (vmcs_read(vcpu, VMCS_GUEST_CR4) & CR4_PAE) {\n\t\t// \tif (!(pt = (uint64_t *) vm_gpa2hva(vm,\n\t\t// \t\tvmcs_read(vcpu, VMCS_GUEST_CR3), sizeof(uint64_t) * 4)))\n\t\t// \t{\n\t\t// \t\txhyve_abort(\"invalid cr3\\n\");\n\t\t// \t}\n\n\t\t// \tvmcs_write(vcpu, VMCS_GUEST_PDPTE0, pt[0]);\n\t\t// \tvmcs_write(vcpu, VMCS_GUEST_PDPTE1, pt[1]);\n\t\t// \tvmcs_write(vcpu, VMCS_GUEST_PDPTE2, pt[2]);\n\t\t// \tvmcs_write(vcpu, VMCS_GUEST_PDPTE3, pt[3]);\n\t\t// }\n\t} else {\n\t\t/*\n\t\t * If CR0.PG is 0 and EFER.LMA is 1, this is a\n\t\t * switch out of IA32e mode so emulate that.\n\t\t */\n\t\tif (efer & EFER_LMA) {\n\t\t\tefer &= ~(uint64_t)EFER_LMA;\n\t\t\tvmcs_write(vcpu, VMCS_GUEST_IA32_EFER, efer);\n\t\t\tentryctls = vmcs_read(vcpu, VMCS_ENTRY_CTLS);\n\t\t\tentryctls &= ~VM_ENTRY_GUEST_LMA;\n\t\t\tvmcs_write(vcpu, VMCS_ENTRY_CTLS, entryctls);\n\t\t}\n\t}\n\n\treturn (HANDLED);\n}\n\nstatic int\nvmx_emulate_cr4_access(int vcpu, uint64_t exitqual)\n{\n\tuint64_t crval, regval;\n\n\t/* We only handle mov to %cr4 at this time */\n\tif ((exitqual & 0xf0) != 0x00)\n\t\treturn (UNHANDLED);\n\n\tregval = vmx_get_guest_reg(vcpu, (exitqual >> 8) & 0xf);\n\n\tvmcs_write(vcpu, VMCS_CR4_SHADOW, regval);\n\n\tcrval = regval | cr4_ones_mask;\n\tcrval &= ~cr4_zeros_mask;\n\tvmcs_write(vcpu, VMCS_GUEST_CR4, crval);\n\n\treturn (HANDLED);\n}\n\nstatic int\nvmx_emulate_cr8_access(struct vmx *vmx, int vcpu, uint64_t exitqual)\n{\n\tstruct vlapic *vlapic;\n\tuint64_t cr8;\n\tint regnum;\n\n\t/* We only handle mov %cr8 to/from a register at this time. */\n\tif ((exitqual & 0xe0) != 0x00) {\n\t\treturn (UNHANDLED);\n\t}\n\n\tvlapic = vm_lapic(vmx->vm, vcpu);\n\tregnum = (exitqual >> 8) & 0xf;\n\tif (exitqual & 0x10) {\n\t\tcr8 = vlapic_get_cr8(vlapic);\n\t\tvmx_set_guest_reg(vcpu, regnum, cr8);\n\t} else {\n\t\tcr8 = vmx_get_guest_reg(vcpu, regnum);\n\t\tvlapic_set_cr8(vlapic, cr8);\n\t}\n\n\treturn (HANDLED);\n}\n\n/*\n * From section \"Guest Register State\" in the Intel SDM: CPL = SS.DPL\n */\nstatic int\nvmx_cpl(int vcpu)\n{\n\tuint32_t ssar;\n\n\tssar = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_SS_ACCESS_RIGHTS);\n\treturn ((ssar >> 5) & 0x3);\n}\n\nstatic enum vm_cpu_mode\nvmx_cpu_mode(int vcpu)\n{\n\tuint32_t csar;\n\n\tif (vmcs_read(vcpu, VMCS_GUEST_IA32_EFER) & EFER_LMA) {\n\t\tcsar = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_CS_ACCESS_RIGHTS);\n\t\tif (csar & 0x2000)\n\t\t\treturn (CPU_MODE_64BIT);\t/* CS.L = 1 */\n\t\telse\n\t\t\treturn (CPU_MODE_COMPATIBILITY);\n\t} else if (vmcs_read(vcpu, VMCS_GUEST_CR0) & CR0_PE) {\n\t\treturn (CPU_MODE_PROTECTED);\n\t} else {\n\t\treturn (CPU_MODE_REAL);\n\t}\n}\n\nstatic enum vm_paging_mode\nvmx_paging_mode(int vcpu)\n{\n\n\tif (!(vmcs_read(vcpu, VMCS_GUEST_CR0) & CR0_PG))\n\t\treturn (PAGING_MODE_FLAT);\n\tif (!(vmcs_read(vcpu, VMCS_GUEST_CR4) & CR4_PAE))\n\t\treturn (PAGING_MODE_32);\n\tif (vmcs_read(vcpu, VMCS_GUEST_IA32_EFER) & EFER_LME)\n\t\treturn (PAGING_MODE_64);\n\telse\n\t\treturn (PAGING_MODE_PAE);\n}\n\nstatic uint64_t\ninout_str_index(struct vmx *vmx, int vcpuid, int in)\n{\n\tuint64_t val;\n\tint error;\n\tenum vm_reg_name reg;\n\n\treg = in ? VM_REG_GUEST_RDI : VM_REG_GUEST_RSI;\n\terror = vmx_getreg(vmx, vcpuid, (int) reg, &val);\n\tKASSERT(error == 0, (\"%s: vmx_getreg error %d\", __func__, error));\n\treturn (val);\n}\n\nstatic uint64_t\ninout_str_count(struct vmx *vmx, int vcpuid, int rep)\n{\n\tuint64_t val;\n\tint error;\n\n\tif (rep) {\n\t\terror = vmx_getreg(vmx, vcpuid, VM_REG_GUEST_RCX, &val);\n\t\tKASSERT(!error, (\"%s: vmx_getreg error %d\", __func__, error));\n\t} else {\n\t\tval = 1;\n\t}\n\treturn (val);\n}\n\nstatic int\ninout_str_addrsize(uint32_t inst_info)\n{\n\tuint32_t size;\n\n\tsize = (inst_info >> 7) & 0x7;\n\tswitch (size) {\n\tcase 0:\n\t\treturn (2);\t/* 16 bit */\n\tcase 1:\n\t\treturn (4);\t/* 32 bit */\n\tcase 2:\n\t\treturn (8);\t/* 64 bit */\n\tdefault:\n\t\txhyve_abort(\"%s: invalid size encoding %d\", __func__, size);\n\t}\n}\n\nstatic void\ninout_str_seginfo(struct vmx *vmx, int vcpuid, uint32_t inst_info, int in,\n    struct vm_inout_str *vis)\n{\n\tint error, s;\n\n\tif (in) {\n\t\tvis->seg_name = VM_REG_GUEST_ES;\n\t} else {\n\t\ts = (inst_info >> 15) & 0x7;\n\t\tvis->seg_name = vm_segment_name(s);\n\t}\n\n\terror = vmx_getdesc(vmx, vcpuid, (int) vis->seg_name, &vis->seg_desc);\n\tKASSERT(error == 0, (\"%s: vmx_getdesc error %d\", __func__, error));\n}\n\nstatic void\nvmx_paging_info(struct vm_guest_paging *paging, int vcpu)\n{\n\tpaging->cr3 = vmcs_guest_cr3(vcpu);\n\tpaging->cpl = vmx_cpl(vcpu);\n\tpaging->cpu_mode = vmx_cpu_mode(vcpu);\n\tpaging->paging_mode = vmx_paging_mode(vcpu);\n}\n\nstatic void\nvmexit_inst_emul(struct vm_exit *vmexit, uint64_t gpa, uint64_t gla, int vcpu)\n{\n\tstruct vm_guest_paging *paging;\n\tuint32_t csar;\n\n\tpaging = &vmexit->u.inst_emul.paging;\n\n\tvmexit->exitcode = VM_EXITCODE_INST_EMUL;\n\tvmexit->u.inst_emul.gpa = gpa;\n\tvmexit->u.inst_emul.gla = gla;\n\tvmx_paging_info(paging, vcpu);\n\tswitch (paging->cpu_mode) {\n\tcase CPU_MODE_REAL:\n\t\tvmexit->u.inst_emul.cs_base = vmcs_read(vcpu, VMCS_GUEST_CS_BASE);\n\t\tvmexit->u.inst_emul.cs_d = 0;\n\t\tbreak;\n\tcase CPU_MODE_PROTECTED:\n\tcase CPU_MODE_COMPATIBILITY:\n\t\tvmexit->u.inst_emul.cs_base = vmcs_read(vcpu, VMCS_GUEST_CS_BASE);\n\t\tcsar = (uint32_t) vmcs_read(vcpu, VMCS_GUEST_CS_ACCESS_RIGHTS);\n\t\tvmexit->u.inst_emul.cs_d = SEG_DESC_DEF32(csar);\n\t\tbreak;\n\tcase CPU_MODE_64BIT:\n\t\tvmexit->u.inst_emul.cs_base = 0;\n\t\tvmexit->u.inst_emul.cs_d = 0;\n\t\tbreak;\n\t}\n\tvie_init(&vmexit->u.inst_emul.vie, NULL, 0);\n}\n\nstatic int\nept_fault_type(uint64_t ept_qual)\n{\n\tint fault_type;\n\n\tif (ept_qual & EPT_VIOLATION_DATA_WRITE)\n\t\tfault_type = XHYVE_PROT_WRITE;\n\telse if (ept_qual & EPT_VIOLATION_INST_FETCH)\n\t\tfault_type = XHYVE_PROT_EXECUTE;\n\telse\n\t\tfault_type= XHYVE_PROT_READ;\n\n\treturn (fault_type);\n}\n\nstatic bool\nept_emulation_fault(uint64_t ept_qual)\n{\n\tint read, write;\n\n\t/* EPT fault on an instruction fetch doesn't make sense here */\n\tif (ept_qual & EPT_VIOLATION_INST_FETCH)\n\t\treturn (FALSE);\n\n\t/* EPT fault must be a read fault or a write fault */\n\tread = ept_qual & EPT_VIOLATION_DATA_READ ? 1 : 0;\n\twrite = ept_qual & EPT_VIOLATION_DATA_WRITE ? 1 : 0;\n\tif ((read | write) == 0)\n\t\treturn (FALSE);\n\n\t/*\n\t * The EPT violation must have been caused by accessing a\n\t * guest-physical address that is a translation of a guest-linear\n\t * address.\n\t */\n\tif ((ept_qual & EPT_VIOLATION_GLA_VALID) == 0 ||\n\t    (ept_qual & EPT_VIOLATION_XLAT_VALID) == 0) {\n\t\treturn (FALSE);\n\t}\n\n\treturn (TRUE);\n}\n\nstatic __inline int\napic_access_virtualization(struct vmx *vmx, int vcpuid)\n{\n\tuint32_t proc_ctls2;\n\n\tproc_ctls2 = vmx->cap[vcpuid].proc_ctls2;\n\treturn ((proc_ctls2 & PROCBASED2_VIRTUALIZE_APIC_ACCESSES) ? 1 : 0);\n}\n\nstatic __inline int\nx2apic_virtualization(struct vmx *vmx, int vcpuid)\n{\n\tuint32_t proc_ctls2;\n\n\tproc_ctls2 = vmx->cap[vcpuid].proc_ctls2;\n\treturn ((proc_ctls2 & PROCBASED2_VIRTUALIZE_X2APIC_MODE) ? 1 : 0);\n}\n\nstatic int\nvmx_handle_apic_write(struct vmx *vmx, int vcpuid, struct vlapic *vlapic,\n    uint64_t qual)\n{\n\tint error, handled, offset;\n\tuint32_t *apic_regs, vector;\n\tbool retu;\n\n\thandled = HANDLED;\n\toffset = APIC_WRITE_OFFSET(qual);\n\n\tif (!apic_access_virtualization(vmx, vcpuid)) {\n\t\t/*\n\t\t * In general there should not be any APIC write VM-exits\n\t\t * unless APIC-access virtualization is enabled.\n\t\t *\n\t\t * However self-IPI virtualization can legitimately trigger\n\t\t * an APIC-write VM-exit so treat it specially.\n\t\t */\n\t\tif (x2apic_virtualization(vmx, vcpuid) &&\n\t\t    offset == APIC_OFFSET_SELF_IPI) {\n\t\t\tapic_regs = (uint32_t *)(vlapic->apic_page);\n\t\t\tvector = apic_regs[APIC_OFFSET_SELF_IPI / 4];\n\t\t\tvlapic_self_ipi_handler(vlapic, vector);\n\t\t\treturn (HANDLED);\n\t\t} else\n\t\t\treturn (UNHANDLED);\n\t}\n\n\tswitch (offset) {\n\tcase APIC_OFFSET_ID:\n\t\tvlapic_id_write_handler(vlapic);\n\t\tbreak;\n\tcase APIC_OFFSET_LDR:\n\t\tvlapic_ldr_write_handler(vlapic);\n\t\tbreak;\n\tcase APIC_OFFSET_DFR:\n\t\tvlapic_dfr_write_handler(vlapic);\n\t\tbreak;\n\tcase APIC_OFFSET_SVR:\n\t\tvlapic_svr_write_handler(vlapic);\n\t\tbreak;\n\tcase APIC_OFFSET_ESR:\n\t\tvlapic_esr_write_handler(vlapic);\n\t\tbreak;\n\tcase APIC_OFFSET_ICR_LOW:\n\t\tretu = false;\n\t\terror = vlapic_icrlo_write_handler(vlapic, &retu);\n\t\tif (error != 0 || retu)\n\t\t\thandled = UNHANDLED;\n\t\tbreak;\n\tcase APIC_OFFSET_CMCI_LVT:\n\tcase APIC_OFFSET_TIMER_LVT:\n\tcase APIC_OFFSET_THERM_LVT:\n\tcase APIC_OFFSET_PERF_LVT:\n\tcase APIC_OFFSET_LINT0_LVT:\n\tcase APIC_OFFSET_LINT1_LVT:\n\tcase APIC_OFFSET_ERROR_LVT:\n\t\tvlapic_lvt_write_handler(vlapic, ((uint32_t) offset));\n\t\tbreak;\n\tcase APIC_OFFSET_TIMER_ICR:\n\t\tvlapic_icrtmr_write_handler(vlapic);\n\t\tbreak;\n\tcase APIC_OFFSET_TIMER_DCR:\n\t\tvlapic_dcr_write_handler(vlapic);\n\t\tbreak;\n\tdefault:\n\t\thandled = UNHANDLED;\n\t\tbreak;\n\t}\n\treturn (handled);\n}\n\nstatic bool\napic_access_fault(struct vmx *vmx, int vcpuid, uint64_t gpa)\n{\n\n\tif (apic_access_virtualization(vmx, vcpuid) &&\n\t    (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + XHYVE_PAGE_SIZE))\n\t\treturn (true);\n\telse\n\t\treturn (false);\n}\n\nstatic int\nvmx_handle_apic_access(struct vmx *vmx, int vcpuid, struct vm_exit *vmexit)\n{\n\tuint64_t qual;\n\tint access_type, offset, allowed;\n\n\tif (!apic_access_virtualization(vmx, vcpuid))\n\t\treturn (UNHANDLED);\n\n\tqual = vmexit->u.vmx.exit_qualification;\n\taccess_type = APIC_ACCESS_TYPE(qual);\n\toffset = APIC_ACCESS_OFFSET(qual);\n\n\tallowed = 0;\n\tif (access_type == 0) {\n\t\t/*\n\t\t * Read data access to the following registers is expected.\n\t\t */\n\t\tswitch (offset) {\n\t\tcase APIC_OFFSET_APR:\n\t\tcase APIC_OFFSET_PPR:\n\t\tcase APIC_OFFSET_RRR:\n\t\tcase APIC_OFFSET_CMCI_LVT:\n\t\tcase APIC_OFFSET_TIMER_CCR:\n\t\t\tallowed = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t} else if (access_type == 1) {\n\t\t/*\n\t\t * Write data access to the following registers is expected.\n\t\t */\n\t\tswitch (offset) {\n\t\tcase APIC_OFFSET_VER:\n\t\tcase APIC_OFFSET_APR:\n\t\tcase APIC_OFFSET_PPR:\n\t\tcase APIC_OFFSET_RRR:\n\t\tcase APIC_OFFSET_ISR0:\n\t\tcase APIC_OFFSET_ISR1:\n\t\tcase APIC_OFFSET_ISR2:\n\t\tcase APIC_OFFSET_ISR3:\n\t\tcase APIC_OFFSET_ISR4:\n\t\tcase APIC_OFFSET_ISR5:\n\t\tcase APIC_OFFSET_ISR6:\n\t\tcase APIC_OFFSET_ISR7:\n\t\tcase APIC_OFFSET_TMR0:\n\t\tcase APIC_OFFSET_TMR1:\n\t\tcase APIC_OFFSET_TMR2:\n\t\tcase APIC_OFFSET_TMR3:\n\t\tcase APIC_OFFSET_TMR4:\n\t\tcase APIC_OFFSET_TMR5:\n\t\tcase APIC_OFFSET_TMR6:\n\t\tcase APIC_OFFSET_TMR7:\n\t\tcase APIC_OFFSET_IRR0:\n\t\tcase APIC_OFFSET_IRR1:\n\t\tcase APIC_OFFSET_IRR2:\n\t\tcase APIC_OFFSET_IRR3:\n\t\tcase APIC_OFFSET_IRR4:\n\t\tcase APIC_OFFSET_IRR5:\n\t\tcase APIC_OFFSET_IRR6:\n\t\tcase APIC_OFFSET_IRR7:\n\t\tcase APIC_OFFSET_CMCI_LVT:\n\t\tcase APIC_OFFSET_TIMER_CCR:\n\t\t\tallowed = 1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (allowed) {\n\t\tvmexit_inst_emul(vmexit, DEFAULT_APIC_BASE + ((uint32_t) offset),\n\t\t    VIE_INVALID_GLA, vcpuid);\n\t}\n\n\t/*\n\t * Regardless of whether the APIC-access is allowed this handler\n\t * always returns UNHANDLED:\n\t * - if the access is allowed then it is handled by emulating the\n\t *   instruction that caused the VM-exit (outside the critical section)\n\t * - if the access is not allowed then it will be converted to an\n\t *   exitcode of VM_EXITCODE_VMX and will be dealt with in userland.\n\t */\n\treturn (UNHANDLED);\n}\n\nstatic enum task_switch_reason\nvmx_task_switch_reason(uint64_t qual)\n{\n\tint reason;\n\n\treason = (qual >> 30) & 0x3;\n\tswitch (reason) {\n\tcase 0:\n\t\treturn (TSR_CALL);\n\tcase 1:\n\t\treturn (TSR_IRET);\n\tcase 2:\n\t\treturn (TSR_JMP);\n\tcase 3:\n\t\treturn (TSR_IDT_GATE);\n\tdefault:\n\t\txhyve_abort(\"%s: invalid reason %d\", __func__, reason);\n\t}\n}\n\nstatic int\nemulate_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val, bool *retu)\n{\n\tint error;\n\n\tif (lapic_msr(num))\n\t\terror = lapic_wrmsr(vmx->vm, vcpuid, num, val, retu);\n\telse\n\t\terror = vmx_wrmsr(vmx, vcpuid, num, val);\n\n\treturn (error);\n}\n\nstatic int\nemulate_rdmsr(struct vmx *vmx, int vcpuid, u_int num, bool *retu)\n{\n\tuint64_t result;\n\tuint32_t eax, edx;\n\tint error;\n\n\tif (lapic_msr(num))\n\t\terror = lapic_rdmsr(vmx->vm, vcpuid, num, &result, retu);\n\telse\n\t\terror = vmx_rdmsr(vmx, vcpuid, num, &result);\n\n\tif (error == 0) {\n\t\teax = (uint32_t) result;\n\t\treg_write(vcpuid, HV_X86_RAX, eax);\n\t\tedx = (uint32_t) (result >> 32);\n\t\treg_write(vcpuid, HV_X86_RDX, edx);\n\t}\n\n\treturn (error);\n}\n\nstatic int\nvmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)\n{\n\tint error, errcode, errcode_valid, handled, in;\n\tstruct vlapic *vlapic;\n\tstruct vm_inout_str *vis;\n\tstruct vm_task_switch *ts;\n\tuint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, inst_info;\n\tuint32_t intr_type, intr_vec, reason;\n\tuint64_t exitintinfo, qual, gpa;\n\tbool retu;\n\n\tCTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0);\n\tCTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_NMI_EXITING) != 0);\n\n\thandled = UNHANDLED;\n\n\tqual = vmexit->u.vmx.exit_qualification;\n\treason = vmexit->u.vmx.exit_reason;\n\tvmexit->exitcode = VM_EXITCODE_BOGUS;\n\n\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_COUNT, 1);\n\n\t/*\n\t * VM exits that can be triggered during event delivery need to\n\t * be handled specially by re-injecting the event if the IDT\n\t * vectoring information field's valid bit is set.\n\t *\n\t * See \"Information for VM Exits During Event Delivery\" in Intel SDM\n\t * for details.\n\t */\n\tidtvec_info = (uint32_t) vmcs_idt_vectoring_info(vcpu);\n\tif (idtvec_info & VMCS_IDT_VEC_VALID) {\n\t\tidtvec_info &= ~(1u << 12); /* clear undefined bit */\n\t\texitintinfo = idtvec_info;\n\t\tif (idtvec_info & VMCS_IDT_VEC_ERRCODE_VALID) {\n\t\t\tidtvec_err = (uint32_t) vmcs_idt_vectoring_err(vcpu);\n\t\t\texitintinfo |= (uint64_t)idtvec_err << 32;\n\t\t}\n\t\terror = vm_exit_intinfo(vmx->vm, vcpu, exitintinfo);\n\t\tKASSERT(error == 0, (\"%s: vm_set_intinfo error %d\",\n\t\t    __func__, error));\n\n\t\t/*\n\t\t * If 'virtual NMIs' are being used and the VM-exit\n\t\t * happened while injecting an NMI during the previous\n\t\t * VM-entry, then clear \"blocking by NMI\" in the\n\t\t * Guest Interruptibility-State so the NMI can be\n\t\t * reinjected on the subsequent VM-entry.\n\t\t *\n\t\t * However, if the NMI was being delivered through a task\n\t\t * gate, then the new task must start execution with NMIs\n\t\t * blocked so don't clear NMI blocking in this case.\n\t\t */\n\t\tintr_type = idtvec_info & VMCS_INTR_T_MASK;\n\t\tif (intr_type == VMCS_INTR_T_NMI) {\n\t\t\tif (reason != EXIT_REASON_TASK_SWITCH)\n\t\t\t\tvmx_clear_nmi_blocking(vmx, vcpu);\n\t\t\telse\n\t\t\t\tvmx_assert_nmi_blocking(vcpu);\n\t\t}\n\n\t\t/*\n\t\t * Update VM-entry instruction length if the event being\n\t\t * delivered was a software interrupt or software exception.\n\t\t */\n\t\tif (intr_type == VMCS_INTR_T_SWINTR ||\n\t\t    intr_type == VMCS_INTR_T_PRIV_SWEXCEPTION ||\n\t\t    intr_type == VMCS_INTR_T_SWEXCEPTION) {\n\t\t\tvmcs_write(vcpu, VMCS_ENTRY_INST_LENGTH,\n\t\t\t\t((uint64_t) vmexit->inst_length));\n\t\t}\n\t}\n\n\tswitch (reason) {\n\tcase EXIT_REASON_TASK_SWITCH:\n\t\tts = &vmexit->u.task_switch;\n\t\tts->tsssel = qual & 0xffff;\n\t\tts->reason = vmx_task_switch_reason(qual);\n\t\tts->ext = 0;\n\t\tts->errcode_valid = 0;\n\t\tvmx_paging_info(&ts->paging, vcpu);\n\t\t/*\n\t\t * If the task switch was due to a CALL, JMP, IRET, software\n\t\t * interrupt (INT n) or software exception (INT3, INTO),\n\t\t * then the saved %rip references the instruction that caused\n\t\t * the task switch. The instruction length field in the VMCS\n\t\t * is valid in this case.\n\t\t *\n\t\t * In all other cases (e.g., NMI, hardware exception) the\n\t\t * saved %rip is one that would have been saved in the old TSS\n\t\t * had the task switch completed normally so the instruction\n\t\t * length field is not needed in this case and is explicitly\n\t\t * set to 0.\n\t\t */\n\t\tif (ts->reason == TSR_IDT_GATE) {\n\t\t\tKASSERT(idtvec_info & VMCS_IDT_VEC_VALID,\n\t\t\t    (\"invalid idtvec_info %#x for IDT task switch\",\n\t\t\t    idtvec_info));\n\t\t\tintr_type = idtvec_info & VMCS_INTR_T_MASK;\n\t\t\tif (intr_type != VMCS_INTR_T_SWINTR &&\n\t\t\t    intr_type != VMCS_INTR_T_SWEXCEPTION &&\n\t\t\t    intr_type != VMCS_INTR_T_PRIV_SWEXCEPTION) {\n\t\t\t\t/* Task switch triggered by external event */\n\t\t\t\tts->ext = 1;\n\t\t\t\tvmexit->inst_length = 0;\n\t\t\t\tif (idtvec_info & VMCS_IDT_VEC_ERRCODE_VALID) {\n\t\t\t\t\tts->errcode_valid = 1;\n\t\t\t\t\tts->errcode = (uint32_t) vmcs_idt_vectoring_err(vcpu);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvmexit->exitcode = VM_EXITCODE_TASK_SWITCH;\n\t\tVCPU_CTR4(vmx->vm, vcpu, \"task switch reason %d, tss 0x%04x, \"\n\t\t    \"%s errcode 0x%016llx\", ts->reason, ts->tsssel,\n\t\t    ts->ext ? \"external\" : \"internal\",\n\t\t    ((uint64_t)ts->errcode << 32) | ((uint64_t) ts->errcode_valid));\n\t\tbreak;\n\tcase EXIT_REASON_CR_ACCESS:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_CR_ACCESS, 1);\n\t\tswitch (qual & 0xf) {\n\t\tcase 0:\n\t\t\thandled = vmx_emulate_cr0_access(vmx->vm, vcpu, qual);\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\thandled = vmx_emulate_cr4_access(vcpu, qual);\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\thandled = vmx_emulate_cr8_access(vmx, vcpu, qual);\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase EXIT_REASON_RDMSR:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_RDMSR, 1);\n\t\tretu = false;\n\t\tecx = (uint32_t) reg_read(vcpu, HV_X86_RCX);\n\t\tVCPU_CTR1(vmx->vm, vcpu, \"rdmsr 0x%08x\", ecx);\n\t\t// printf(\"EXIT_REASON_RDMSR 0x%08x\\n\", ecx);\n\t\terror = emulate_rdmsr(vmx, vcpu, ecx, &retu);\n\t\tif (error) {\n\t\t\tvmexit->exitcode = VM_EXITCODE_RDMSR;\n\t\t\tvmexit->u.msr.code = ecx;\n\t\t} else if (!retu) {\n\t\t\thandled = HANDLED;\n\t\t} else {\n\t\t\t/* Return to userspace with a valid exitcode */\n\t\t\tKASSERT(vmexit->exitcode != VM_EXITCODE_BOGUS,\n\t\t\t    (\"emulate_rdmsr retu with bogus exitcode\"));\n\t\t}\n\t\tbreak;\n\tcase EXIT_REASON_WRMSR:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_WRMSR, 1);\n\t\tretu = false;\n\t\teax = (uint32_t) reg_read(vcpu, HV_X86_RAX);\n\t\tecx = (uint32_t) reg_read(vcpu, HV_X86_RCX);\n\t\tedx = (uint32_t) reg_read(vcpu, HV_X86_RDX);\n\t\tVCPU_CTR2(vmx->vm, vcpu, \"wrmsr 0x%08x value 0x%016llx\",\n\t\t    ecx, (uint64_t)edx << 32 | eax);\n\t\t// printf(\"EXIT_REASON_WRMSR 0x%08x value 0x%016llx\\n\",\n\t\t//     ecx, (uint64_t)edx << 32 | eax);\n\t\terror = emulate_wrmsr(vmx, vcpu, ecx,\n\t\t    (uint64_t)edx << 32 | eax, &retu);\n\t\tif (error) {\n\t\t\tvmexit->exitcode = VM_EXITCODE_WRMSR;\n\t\t\tvmexit->u.msr.code = ecx;\n\t\t\tvmexit->u.msr.wval = (uint64_t)edx << 32 | eax;\n\t\t} else if (!retu) {\n\t\t\thandled = HANDLED;\n\t\t} else {\n\t\t\t/* Return to userspace with a valid exitcode */\n\t\t\tKASSERT(vmexit->exitcode != VM_EXITCODE_BOGUS,\n\t\t\t    (\"emulate_wrmsr retu with bogus exitcode\"));\n\t\t}\n\t\tbreak;\n\tcase EXIT_REASON_HLT:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_HLT, 1);\n\t\tvmexit->exitcode = VM_EXITCODE_HLT;\n\t\tvmexit->u.hlt.rflags = vmcs_read(vcpu, VMCS_GUEST_RFLAGS);\n\t\tbreak;\n\tcase EXIT_REASON_MTF:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_MTRAP, 1);\n\t\tvmexit->exitcode = VM_EXITCODE_MTRAP;\n\t\tvmexit->inst_length = 0;\n\t\tbreak;\n\tcase EXIT_REASON_PAUSE:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_PAUSE, 1);\n\t\tvmexit->exitcode = VM_EXITCODE_PAUSE;\n\t\tbreak;\n\tcase EXIT_REASON_INTR_WINDOW:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_INTR_WINDOW, 1);\n\t\tvmx_clear_int_window_exiting(vmx, vcpu);\n\t\treturn (1);\n\tcase EXIT_REASON_EXT_INTR:\n\t\t/*\n\t\t * External interrupts serve only to cause VM exits and allow\n\t\t * the host interrupt handler to run.\n\t\t *\n\t\t * If this external interrupt triggers a virtual interrupt\n\t\t * to a VM, then that state will be recorded by the\n\t\t * host interrupt handler in the VM's softc. We will inject\n\t\t * this virtual interrupt during the subsequent VM enter.\n\t\t */\n\t\tintr_info = (uint32_t) vmcs_read(vcpu, VMCS_EXIT_INTR_INFO);\n\n\t\t/*\n\t\t * XXX: Ignore this exit if VMCS_INTR_VALID is not set.\n\t\t * This appears to be a bug in VMware Fusion?\n\t\t */\n\t\tif (!(intr_info & VMCS_INTR_VALID))\n\t\t\treturn (1);\n\t\tKASSERT((intr_info & VMCS_INTR_VALID) != 0 &&\n\t\t    (intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_HWINTR,\n\t\t    (\"VM exit interruption info invalid: %#x\", intr_info));\n\n\t\t/*\n\t\t * This is special. We want to treat this as an 'handled'\n\t\t * VM-exit but not increment the instruction pointer.\n\t\t */\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_EXTINT, 1);\n\t\treturn (1);\n\tcase EXIT_REASON_NMI_WINDOW:\n\t\t/* Exit to allow the pending virtual NMI to be injected */\n\t\tif (vm_nmi_pending(vmx->vm, vcpu))\n\t\t\tvmx_inject_nmi(vmx, vcpu);\n\t\tvmx_clear_nmi_window_exiting(vmx, vcpu);\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1);\n\t\treturn (1);\n\tcase EXIT_REASON_INOUT:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1);\n\t\tvmexit->exitcode = VM_EXITCODE_INOUT;\n\t\tvmexit->u.inout.bytes = (qual & 0x7) + 1;\n\t\tvmexit->u.inout.in = in = (qual & 0x8) ? 1 : 0;\n\t\tvmexit->u.inout.string = (qual & 0x10) ? 1 : 0;\n\t\tvmexit->u.inout.rep = (qual & 0x20) ? 1 : 0;\n\t\tvmexit->u.inout.port = (uint16_t)(qual >> 16);\n\t\tvmexit->u.inout.eax = (uint32_t) reg_read(vcpu, HV_X86_RAX);\n\t\t// if ((vmexit->u.inout.port == 0x0020) ||\n\t\t// \t(vmexit->u.inout.port == 0x0021) ||\n\t\t// \t(vmexit->u.inout.port == 0x00a0) ||\n\t\t// \t(vmexit->u.inout.port == 0x00a1))\n\t\t// {\n\t\t// \tprintf(\"EXIT_REASON_INOUT port 0x%03x in %d\\n\",\n\t\t// \t\tvmexit->u.inout.port, vmexit->u.inout.in);\n\t\t// }\n\t\tif (vmexit->u.inout.string) {\n\t\t\tinst_info = (uint32_t) vmcs_read(vcpu, VMCS_EXIT_INSTRUCTION_INFO);\n\t\t\tvmexit->exitcode = VM_EXITCODE_INOUT_STR;\n\t\t\tvis = &vmexit->u.inout_str;\n\t\t\tvmx_paging_info(&vis->paging, vcpu);\n\t\t\tvis->rflags = vmcs_read(vcpu, VMCS_GUEST_RFLAGS);\n\t\t\tvis->cr0 = vmcs_read(vcpu, VMCS_GUEST_CR0);\n\t\t\tvis->index = inout_str_index(vmx, vcpu, in);\n\t\t\tvis->count = inout_str_count(vmx, vcpu, vis->inout.rep);\n\t\t\tvis->addrsize = inout_str_addrsize(inst_info);\n\t\t\tinout_str_seginfo(vmx, vcpu, inst_info, in, vis);\n\t\t}\n\t\tbreak;\n\tcase EXIT_REASON_CPUID:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_CPUID, 1);\n\t\thandled = vmx_handle_cpuid(vmx->vm, vcpu);\n\t\tbreak;\n\tcase EXIT_REASON_EXCEPTION:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_EXCEPTION, 1);\n\t\tintr_info = (uint32_t) vmcs_read(vcpu, VMCS_EXIT_INTR_INFO);\n\t\tKASSERT((intr_info & VMCS_INTR_VALID) != 0,\n\t\t    (\"VM exit interruption info invalid: %#x\", intr_info));\n\n\t\tintr_vec = intr_info & 0xff;\n\t\tintr_type = intr_info & VMCS_INTR_T_MASK;\n\n\t\t/*\n\t\t * If Virtual NMIs control is 1 and the VM-exit is due to a\n\t\t * fault encountered during the execution of IRET then we must\n\t\t * restore the state of \"virtual-NMI blocking\" before resuming\n\t\t * the guest.\n\t\t *\n\t\t * See \"Resuming Guest Software after Handling an Exception\".\n\t\t * See \"Information for VM Exits Due to Vectored Events\".\n\t\t */\n\t\tif ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 &&\n\t\t    (intr_vec != IDT_DF) &&\n\t\t    (intr_info & EXIT_QUAL_NMIUDTI) != 0)\n\t\t\tvmx_restore_nmi_blocking(vmx, vcpu);\n\n\t\t/*\n\t\t * The NMI has already been handled in vmx_exit_handle_nmi().\n\t\t */\n\t\tif (intr_type == VMCS_INTR_T_NMI)\n\t\t\treturn (1);\n\n\t\tif (intr_vec == IDT_PF) {\n\t\t\treg_write(vcpu, HV_X86_CR2, qual);\n\t\t}\n\n\t\t/*\n\t\t * Software exceptions exhibit trap-like behavior. This in\n\t\t * turn requires populating the VM-entry instruction length\n\t\t * so that the %rip in the trap frame is past the INT3/INTO\n\t\t * instruction.\n\t\t */\n\t\tif (intr_type == VMCS_INTR_T_SWEXCEPTION)\n\t\t\tvmcs_write(vcpu, VMCS_ENTRY_INST_LENGTH,\n\t\t\t\t((uint64_t) vmexit->inst_length));\n\n\t\t/* Reflect all other exceptions back into the guest */\n\t\terrcode_valid = errcode = 0;\n\t\tif (intr_info & VMCS_INTR_DEL_ERRCODE) {\n\t\t\terrcode_valid = 1;\n\t\t\terrcode = (int) vmcs_read(vcpu, VMCS_EXIT_INTR_ERRCODE);\n\t\t}\n\t\tVCPU_CTR2(vmx->vm, vcpu, \"Reflecting exception %d/%#x into \"\n\t\t    \"the guest\", intr_vec, errcode);\n\t\terror = vm_inject_exception(vmx->vm, vcpu, ((int) intr_vec),\n\t\t    errcode_valid, ((uint32_t) errcode), 0);\n\t\tKASSERT(error == 0, (\"%s: vm_inject_exception error %d\",\n\t\t    __func__, error));\n\t\treturn (1);\n\n\tcase EXIT_REASON_EPT_FAULT:\n\t\t/*\n\t\t * If 'gpa' lies within the address space allocated to\n\t\t * memory then this must be a nested page fault otherwise\n\t\t * this must be an instruction that accesses MMIO space.\n\t\t */\n\t\tgpa = vmcs_gpa(vcpu);\n\t\tif (vm_mem_allocated(vmx->vm, gpa) ||\n\t\t    apic_access_fault(vmx, vcpu, gpa)) {\n\t\t\tvmexit->exitcode = VM_EXITCODE_PAGING;\n\t\t\tvmexit->inst_length = 0;\n\t\t\tvmexit->u.paging.gpa = gpa;\n\t\t\tvmexit->u.paging.fault_type = ept_fault_type(qual);\n\t\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_NESTED_FAULT, 1);\n\t\t} else if (ept_emulation_fault(qual)) {\n\t\t\tvmexit_inst_emul(vmexit, gpa, vmcs_gla(vcpu), vcpu);\n\t\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_INST_EMUL, 1);\n\t\t}\n\t\t/*\n\t\t * If Virtual NMIs control is 1 and the VM-exit is due to an\n\t\t * EPT fault during the execution of IRET then we must restore\n\t\t * the state of \"virtual-NMI blocking\" before resuming.\n\t\t *\n\t\t * See description of \"NMI unblocking due to IRET\" in\n\t\t * \"Exit Qualification for EPT Violations\".\n\t\t */\n\t\tif ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 &&\n\t\t    (qual & EXIT_QUAL_NMIUDTI) != 0)\n\t\t\tvmx_restore_nmi_blocking(vmx, vcpu);\n\t\tbreak;\n\tcase EXIT_REASON_VIRTUALIZED_EOI:\n\t\tvmexit->exitcode = VM_EXITCODE_IOAPIC_EOI;\n\t\tvmexit->u.ioapic_eoi.vector = qual & 0xFF;\n\t\tvmexit->inst_length = 0;\t/* trap-like */\n\t\tbreak;\n\tcase EXIT_REASON_APIC_ACCESS:\n\t\thandled = vmx_handle_apic_access(vmx, vcpu, vmexit);\n\t\tbreak;\n\tcase EXIT_REASON_APIC_WRITE:\n\t\t/*\n\t\t * APIC-write VM exit is trap-like so the %rip is already\n\t\t * pointing to the next instruction.\n\t\t */\n\t\tvmexit->inst_length = 0;\n\t\tvlapic = vm_lapic(vmx->vm, vcpu);\n\t\thandled = vmx_handle_apic_write(vmx, vcpu, vlapic, qual);\n\t\tbreak;\n\tcase EXIT_REASON_XSETBV:\n\t\thandled = vmx_emulate_xsetbv(vmx, vcpu);\n\t\tbreak;\n\tcase EXIT_REASON_MONITOR:\n\t\tvmexit->exitcode = VM_EXITCODE_MONITOR;\n\t\tbreak;\n\tcase EXIT_REASON_MWAIT:\n\t\tvmexit->exitcode = VM_EXITCODE_MWAIT;\n\t\tbreak;\n\tdefault:\n\t\tvmm_stat_incr(vmx->vm, vcpu, VMEXIT_UNKNOWN, 1);\n\t\tbreak;\n\t}\n\n\tif (handled) {\n\t\t/*\n\t\t * It is possible that control is returned to userland\n\t\t * even though we were able to handle the VM exit in the\n\t\t * kernel.\n\t\t *\n\t\t * In such a case we want to make sure that the userland\n\t\t * restarts guest execution at the instruction *after*\n\t\t * the one we just processed. Therefore we update the\n\t\t * guest rip in the VMCS and in 'vmexit'.\n\t\t */\n\t\tvmexit->rip += (uint64_t) vmexit->inst_length;\n\t\tvmexit->inst_length = 0;\n\t\tvmcs_write(vcpu, VMCS_GUEST_RIP, vmexit->rip);\n\t} else {\n\t\tif (vmexit->exitcode == VM_EXITCODE_BOGUS) {\n\t\t\t/*\n\t\t\t * If this VM exit was not claimed by anybody then\n\t\t\t * treat it as a generic VMX exit.\n\t\t\t */\n\t\t\tvmexit->exitcode = VM_EXITCODE_VMX;\n\t\t\tvmexit->u.vmx.status = VM_SUCCESS;\n\t\t\tvmexit->u.vmx.inst_type = 0;\n\t\t\tvmexit->u.vmx.inst_error = 0;\n\t\t} else {\n\t\t\t/*\n\t\t\t * The exitcode and collateral have been populated.\n\t\t\t * The VM exit will be processed further in userland.\n\t\t\t */\n\t\t}\n\t}\n\treturn (handled);\n}\n\nstatic int\nvmx_run(void *arg, int vcpu, register_t rip, void *rendezvous_cookie,\n\tvoid *suspend_cookie)\n{\n\tint handled;\n\tstruct vmx *vmx;\n\tstruct vm *vm;\n\tstruct vm_exit *vmexit;\n\tstruct vlapic *vlapic;\n\tuint32_t exit_reason;\n\thv_return_t hvr;\n\n\tvmx = arg;\n\tvm = vmx->vm;\n\tvlapic = vm_lapic(vm, vcpu);\n\tvmexit = vm_exitinfo(vm, vcpu);\n\n\tvmcs_write(vcpu, VMCS_GUEST_RIP, ((uint64_t) rip));\n\n\tdo {\n\t\tKASSERT(vmcs_guest_rip(vcpu) == ((uint64_t) rip),\n\t\t\t(\"%s: vmcs guest rip mismatch %#llx/%#llx\",\n\t\t\t\t__func__, vmcs_guest_rip(vcpu), ((uint64_t) rip)));\n\n\t\thandled = UNHANDLED;\n\n\t\tvmx_inject_interrupts(vmx, vcpu, vlapic, ((uint64_t) rip));\n\n\t\t/*\n\t\t * Check for vcpu suspension after injecting events because\n\t\t * vmx_inject_interrupts() can suspend the vcpu due to a\n\t\t * triple fault.\n\t\t */\n\t\tif (vcpu_suspended(suspend_cookie)) {\n\t\t\tvm_exit_suspended(vmx->vm, vcpu, ((uint64_t) rip));\n\t\t\tbreak;\n\t\t}\n\n\t\tif (vcpu_rendezvous_pending(rendezvous_cookie)) {\n\t\t\tvm_exit_rendezvous(vmx->vm, vcpu, ((uint64_t) rip));\n\t\t\tbreak;\n\t\t}\n\n\t\tvmx_run_trace(vmx, vcpu);\n\t\thvr = hv_vcpu_run((hv_vcpuid_t) vcpu);\n\t\t/* Collect some information for VM exit processing */\n\t\trip = (register_t) vmcs_guest_rip(vcpu);\n\t\tvmexit->rip = (uint64_t) rip;\n\t\tvmexit->inst_length = (int) vmexit_instruction_length(vcpu);\n\t\tvmexit->u.vmx.exit_reason = exit_reason = vmcs_exit_reason(vcpu);\n\t\tvmexit->u.vmx.exit_qualification = vmcs_exit_qualification(vcpu);\n\t\t/* Update 'nextrip' */\n\t\tvmx->state[vcpu].nextrip = (uint64_t) rip;\n\t\tif (hvr == HV_SUCCESS) {\n\t\t\thandled = vmx_exit_process(vmx, vcpu, vmexit);\n\t\t} else {\n\t\t\thvdump(vcpu);\n\t\t\txhyve_abort(\"vmentry error\\n\");\n\t\t}\n\t\tvmx_exit_trace(vmx, vcpu, ((uint64_t) rip), exit_reason, handled);\n\t\trip = (register_t) vmexit->rip;\n\t} while (handled);\n\n\t/*\n\t * If a VM exit has been handled then the exitcode must be BOGUS\n\t * If a VM exit is not handled then the exitcode must not be BOGUS\n\t */\n\tif ((handled && vmexit->exitcode != VM_EXITCODE_BOGUS) ||\n\t    (!handled && vmexit->exitcode == VM_EXITCODE_BOGUS)) {\n\t\txhyve_abort(\"Mismatch between handled (%d) and exitcode (%d)\",\n\t\t      handled, vmexit->exitcode);\n\t}\n\n\tif (!handled)\n\t\tvmm_stat_incr(vm, vcpu, VMEXIT_USERSPACE, 1);\n\n\tVCPU_CTR1(vm, vcpu, \"returning from vmx_run: exitcode %d\",\n\t    vmexit->exitcode);\n\n\treturn (0);\n}\n\nstatic void\nvmx_vm_cleanup(void *arg)\n{\n\tstruct vmx *vmx = arg;\n\n\tfree(vmx);\n\n\treturn;\n}\n\nstatic void\nvmx_vcpu_cleanup(void *arg, int vcpuid) {\n\tif (arg || vcpuid) xhyve_abort(\"vmx_vcpu_cleanup\\n\");\n}\n\n\nstatic int\nvmx_get_intr_shadow(int vcpu, uint64_t *retval)\n{\n\tuint64_t gi;\n\tint error;\n\n\terror = vmcs_getreg(vcpu, VMCS_IDENT(VMCS_GUEST_INTERRUPTIBILITY), &gi);\n\t*retval = (gi & HWINTR_BLOCKING) ? 1 : 0;\n\treturn (error);\n}\n\nstatic int\nvmx_modify_intr_shadow(struct vmx *vmx, int vcpu, uint64_t val)\n{\n\tuint64_t gi;\n\tint error, ident;\n\n\t/*\n\t * Forcing the vcpu into an interrupt shadow is not supported.\n\t */\n\tif (val) {\n\t\terror = EINVAL;\n\t\tgoto done;\n\t}\n\n\tident = VMCS_IDENT(VMCS_GUEST_INTERRUPTIBILITY);\n\terror = vmcs_getreg(vcpu, ident, &gi);\n\tif (error == 0) {\n\t\tgi &= ~HWINTR_BLOCKING;\n\t\terror = vmcs_setreg(vcpu, ident, gi);\n\t}\ndone:\n\tVCPU_CTR2(vmx->vm, vcpu, \"Setting intr_shadow to %#llx %s\", val,\n\t    error ? \"failed\" : \"succeeded\");\n\treturn (error);\n}\n\nstatic int\nvmx_shadow_reg(int reg)\n{\n\tint shreg;\n\n\tshreg = -1;\n\n\tswitch (reg) {\n\tcase VM_REG_GUEST_CR0:\n\t\tshreg = VMCS_CR0_SHADOW;\n                break;\n        case VM_REG_GUEST_CR4:\n\t\tshreg = VMCS_CR4_SHADOW;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn (shreg);\n}\n\nstatic const hv_x86_reg_t hvregs[] = {\n\tHV_X86_RAX,\n\tHV_X86_RBX,\n\tHV_X86_RCX,\n\tHV_X86_RDX,\n\tHV_X86_RSI,\n\tHV_X86_RDI,\n\tHV_X86_RBP,\n\tHV_X86_R8,\n\tHV_X86_R9,\n\tHV_X86_R10,\n\tHV_X86_R11,\n\tHV_X86_R12,\n\tHV_X86_R13,\n\tHV_X86_R14,\n\tHV_X86_R15,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_CR2,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX,\n\tHV_X86_REGISTERS_MAX\n};\n\nstatic int\nvmx_getreg(UNUSED void *arg, int vcpu, int reg, uint64_t *retval)\n{\n\thv_x86_reg_t hvreg;\n\n\tif (reg == VM_REG_GUEST_INTR_SHADOW)\n\t\treturn (vmx_get_intr_shadow(vcpu, retval));\n\n\thvreg = hvregs[reg];\n\tif (hvreg != HV_X86_REGISTERS_MAX) {\n\t\t*retval = reg_read(vcpu, hvreg);\n\t\treturn (0);\n\t}\n\n\treturn (vmcs_getreg(vcpu, reg, retval));\n}\n\nstatic int\nvmx_setreg(void *arg, int vcpu, int reg, uint64_t val)\n{\n\tint error, shadow;\n\tuint64_t ctls;\n\thv_x86_reg_t hvreg;\n\tstruct vmx *vmx = arg;\n\n\tif (reg == VM_REG_GUEST_INTR_SHADOW)\n\t\treturn (vmx_modify_intr_shadow(vmx, vcpu, val));\n\n\thvreg = hvregs[reg];\n\tif (hvreg != HV_X86_REGISTERS_MAX) {\n\t\treg_write(vcpu, hvreg, val);\n\t\treturn (0);\n\t}\n\n\terror = vmcs_setreg(vcpu, reg, val);\n\n\tif (error == 0) {\n\t\t/*\n\t\t * If the \"load EFER\" VM-entry control is 1 then the\n\t\t * value of EFER.LMA must be identical to \"IA-32e mode guest\"\n\t\t * bit in the VM-entry control.\n\t\t */\n\t\tif ((vmx->state[vcpu].entry_ctls & VM_ENTRY_LOAD_EFER) != 0 &&\n\t\t\t(reg == VM_REG_GUEST_EFER)) {\n\t\t\tvmcs_getreg(vcpu, VMCS_IDENT(VMCS_ENTRY_CTLS), &ctls);\n\t\t\tif (val & EFER_LMA)\n\t\t\t\tctls |= VM_ENTRY_GUEST_LMA;\n\t\t\telse\n\t\t\t\tctls &= ~VM_ENTRY_GUEST_LMA;\n\t\t\tvmcs_setreg(vcpu, VMCS_IDENT(VMCS_ENTRY_CTLS), ctls);\n\t\t}\n\n\t\tshadow = vmx_shadow_reg(reg);\n\t\tif (shadow > 0) {\n\t\t\t/*\n\t\t\t * Store the unmodified value in the shadow\n\t\t\t */\t\t\t\n\t\t\terror = vmcs_setreg(vcpu, VMCS_IDENT(shadow), val);\n\t\t}\n\n\t\tif (reg == VM_REG_GUEST_CR3) {\n\t\t\t/*\n\t\t\t * Invalidate the guest vcpu's TLB mappings to emulate\n\t\t\t * the behavior of updating %cr3.\n\t\t\t */\n\t\t\thv_vcpu_invalidate_tlb((hv_vcpuid_t) vcpu);\n\t\t}\n\t}\n\n\treturn (error);\n}\n\nstatic int\nvmx_getdesc(UNUSED void *arg, int vcpu, int reg, struct seg_desc *desc)\n{\n\treturn (vmcs_getdesc(vcpu, reg, desc));\n}\n\nstatic int\nvmx_setdesc(UNUSED void *arg, int vcpu, int reg, struct seg_desc *desc)\n{\n\treturn (vmcs_setdesc(vcpu, reg, desc));\n}\n\nstatic int\nvmx_getcap(void *arg, int vcpu, int type, int *retval)\n{\n\tstruct vmx *vmx = arg;\n\tint vcap;\n\tint ret;\n\n\tret = ENOENT;\n\n\tvcap = vmx->cap[vcpu].set;\n\n\tswitch (type) {\n\tcase VM_CAP_HALT_EXIT:\n\t\tif (cap_halt_exit)\n\t\t\tret = 0;\n\t\tbreak;\n\tcase VM_CAP_PAUSE_EXIT:\n\t\tif (cap_pause_exit)\n\t\t\tret = 0;\n\t\tbreak;\n\tcase VM_CAP_MTRAP_EXIT:\n\t\tif (cap_monitor_trap)\n\t\t\tret = 0;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (ret == 0)\n\t\t*retval = (vcap & (1 << type)) ? 1 : 0;\n\n\treturn (ret);\n}\n\nstatic int\nvmx_setcap(void *arg, int vcpu, int type, int val)\n{\n\tstruct vmx *vmx = arg;\n\tuint32_t baseval;\n\tuint32_t *pptr;\n\tuint32_t reg;\n\tuint32_t flag;\n\tint retval;\n\n\tretval = ENOENT;\n\tpptr = NULL;\n\tbaseval = 0;\n\treg = 0;\n\tflag = 0;\n\n\tswitch (type) {\n\tcase VM_CAP_HALT_EXIT:\n\t\tif (cap_halt_exit) {\n\t\t\tretval = 0;\n\t\t\tpptr = &vmx->cap[vcpu].proc_ctls;\n\t\t\tbaseval = *pptr;\n\t\t\tflag = PROCBASED_HLT_EXITING;\n\t\t\treg = VMCS_PRI_PROC_BASED_CTLS;\n\t\t}\n\t\tbreak;\n\tcase VM_CAP_MTRAP_EXIT:\n\t\tif (cap_monitor_trap) {\n\t\t\tretval = 0;\n\t\t\tpptr = &vmx->cap[vcpu].proc_ctls;\n\t\t\tbaseval = *pptr;\n\t\t\tflag = PROCBASED_MTF;\n\t\t\treg = VMCS_PRI_PROC_BASED_CTLS;\n\t\t}\n\t\tbreak;\n\tcase VM_CAP_PAUSE_EXIT:\n\t\tif (cap_pause_exit) {\n\t\t\tretval = 0;\n\t\t\tpptr = &vmx->cap[vcpu].proc_ctls;\n\t\t\tbaseval = *pptr;\n\t\t\tflag = PROCBASED_PAUSE_EXITING;\n\t\t\treg = VMCS_PRI_PROC_BASED_CTLS;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\txhyve_abort(\"vmx_setcap\\n\");\n\t}\n\n\tif (retval == 0) {\n\t\tif (val) {\n\t\t\tbaseval |= flag;\n\t\t} else {\n\t\t\tbaseval &= ~flag;\n\t\t}\n\n\t\tvmcs_write(vcpu, reg, baseval);\n\n\t\t/*\n\t\t * Update optional stored flags, and record\n\t\t * setting\n\t\t */\n\t\tif (pptr != NULL) {\n\t\t\t*pptr = baseval;\n\t\t}\n\n\t\tif (val) {\n\t\t\tvmx->cap[vcpu].set |= (1 << type);\n\t\t} else {\n\t\t\tvmx->cap[vcpu].set &= ~(1 << type);\n\t\t}\n\n\t}\n\n\treturn (retval);\n}\n\nstruct vlapic_vtx {\n\tstruct vlapic vlapic;\n\tstruct pir_desc *pir_desc;\n\tstruct vmx *vmx;\n};\n\n// #define\tVMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg)\t\\\n// do {\t\t\t\t\t\t\t\t\t\\\n// \tVCPU_CTR2(vm, vcpuid, msg \" assert %s-triggered vector %d\",\t\\\n// \t    level ? \"level\" : \"edge\", vector);\t\t\t\t\\\n// \tVCPU_CTR1(vm, vcpuid, msg \" pir0 0x%016lx\", pir_desc->pir[0]);\t\\\n// \tVCPU_CTR1(vm, vcpuid, msg \" pir1 0x%016lx\", pir_desc->pir[1]);\t\\\n// \tVCPU_CTR1(vm, vcpuid, msg \" pir2 0x%016lx\", pir_desc->pir[2]);\t\\\n// \tVCPU_CTR1(vm, vcpuid, msg \" pir3 0x%016lx\", pir_desc->pir[3]);\t\\\n// \tVCPU_CTR1(vm, vcpuid, msg \" notify: %s\", notify ? \"yes\" : \"no\");\\\n// } while (0)\n\n// /*\n//  * vlapic->ops handlers that utilize the APICv hardware assist described in\n//  * Chapter 29 of the Intel SDM.\n//  */\n// static int\n// vmx_set_intr_ready(struct vlapic *vlapic, int vector, bool level)\n// {\n// \tstruct vlapic_vtx *vlapic_vtx;\n// \tstruct pir_desc *pir_desc;\n// \tuint64_t mask;\n// \tint idx, notify;\n\n// \tvlapic_vtx = (struct vlapic_vtx *)vlapic;\n// \tpir_desc = vlapic_vtx->pir_desc;\n\n// \t/*\n// \t * Keep track of interrupt requests in the PIR descriptor. This is\n// \t * because the virtual APIC page pointed to by the VMCS cannot be\n// \t * modified if the vcpu is running.\n// \t */\n// \tidx = vector / 64;\n// \tmask = 1UL << (vector % 64);\n// \tatomic_set_long(&pir_desc->pir[idx], mask);\n// \tnotify = atomic_cmpset_long(&pir_desc->pending, 0, 1);\n\n// \tVMX_CTR_PIR(vlapic->vm, vlapic->vcpuid, pir_desc, notify, vector,\n// \t    level, \"vmx_set_intr_ready\");\n// \treturn (notify);\n// }\n\n// static int\n// vmx_pending_intr(struct vlapic *vlapic, int *vecptr)\n// {\n// \tstruct vlapic_vtx *vlapic_vtx;\n// \tstruct pir_desc *pir_desc;\n// \tstruct LAPIC *lapic;\n// \tuint64_t pending, pirval;\n// \tuint32_t ppr, vpr;\n// \tint i;\n\n// \t/*\n// \t * This function is only expected to be called from the 'HLT' exit\n// \t * handler which does not care about the vector that is pending.\n// \t */\n// \tKASSERT(vecptr == NULL, (\"vmx_pending_intr: vecptr must be NULL\"));\n\n// \tvlapic_vtx = (struct vlapic_vtx *)vlapic;\n// \tpir_desc = vlapic_vtx->pir_desc;\n\n// \tpending = atomic_load_acq_long(&pir_desc->pending);\n// \tif (!pending)\n// \t\treturn (0);\t/* common case */\n\n// \t/*\n// \t * If there is an interrupt pending then it will be recognized only\n// \t * if its priority is greater than the processor priority.\n// \t *\n// \t * Special case: if the processor priority is zero then any pending\n// \t * interrupt will be recognized.\n// \t */\n// \tlapic = vlapic->apic_page;\n// \tppr = lapic->ppr & 0xf0;\n// \tif (ppr == 0)\n// \t\treturn (1);\n\n// \tVCPU_CTR1(vlapic->vm, vlapic->vcpuid, \"HLT with non-zero PPR %d\",\n// \t    lapic->ppr);\n\n// \tfor (i = 3; i >= 0; i--) {\n// \t\tpirval = pir_desc->pir[i];\n// \t\tif (pirval != 0) {\n// \t\t\tvpr = (i * 64 + flsl(pirval) - 1) & 0xf0;\n// \t\t\treturn (vpr > ppr);\n// \t\t}\n// \t}\n// \treturn (0);\n// }\n\n// static void\n// vmx_intr_accepted(struct vlapic *vlapic, int vector)\n// {\n\n// \txhyve_abort(\"vmx_intr_accepted: not expected to be called\");\n// }\n\n// static void\n// vmx_set_tmr(struct vlapic *vlapic, int vector, bool level)\n// {\n// \tstruct vlapic_vtx *vlapic_vtx;\n// \tstruct vmx *vmx;\n// \tstruct vmcs *vmcs;\n// \tuint64_t mask, val;\n\n// \tKASSERT(vector >= 0 && vector <= 255, (\"invalid vector %d\", vector));\n// \tKASSERT(!vcpu_is_running(vlapic->vm, vlapic->vcpuid, NULL),\n// \t    (\"vmx_set_tmr: vcpu cannot be running\"));\n\n// \tvlapic_vtx = (struct vlapic_vtx *)vlapic;\n// \tvmx = vlapic_vtx->vmx;\n// \tvmcs = &vmx->vmcs[vlapic->vcpuid];\n// \tmask = 1UL << (vector % 64);\n\n// \tVMPTRLD(vmcs);\n// \tval = vmcs_read(VMCS_EOI_EXIT(vector));\n// \tif (level)\n// \t\tval |= mask;\n// \telse\n// \t\tval &= ~mask;\n// \tvmcs_write(VMCS_EOI_EXIT(vector), val);\n// \tVMCLEAR(vmcs);\n// }\n\n// static void\n// vmx_enable_x2apic_mode(struct vlapic *vlapic)\n// {\n// \tstruct vmx *vmx;\n// \tstruct vmcs *vmcs;\n// \tuint32_t proc_ctls2;\n// \tint vcpuid, error;\n\n// \tvcpuid = vlapic->vcpuid;\n// \tvmx = ((struct vlapic_vtx *)vlapic)->vmx;\n// \tvmcs = &vmx->vmcs[vcpuid];\n\n// \tproc_ctls2 = vmx->cap[vcpuid].proc_ctls2;\n// \tKASSERT((proc_ctls2 & PROCBASED2_VIRTUALIZE_APIC_ACCESSES) != 0,\n// \t    (\"%s: invalid proc_ctls2 %#x\", __func__, proc_ctls2));\n\n// \tproc_ctls2 &= ~PROCBASED2_VIRTUALIZE_APIC_ACCESSES;\n// \tproc_ctls2 |= PROCBASED2_VIRTUALIZE_X2APIC_MODE;\n// \tvmx->cap[vcpuid].proc_ctls2 = proc_ctls2;\n\n// \tVMPTRLD(vmcs);\n// \tvmcs_write(VMCS_SEC_PROC_BASED_CTLS, proc_ctls2);\n// \tVMCLEAR(vmcs);\n\n// \tif (vlapic->vcpuid == 0) {\n// \t\t/*\n// \t\t * The nested page table mappings are shared by all vcpus\n// \t\t * so unmap the APIC access page just once.\n// \t\t */\n// \t\terror = vm_unmap_mmio(vmx->vm, DEFAULT_APIC_BASE, PAGE_SIZE);\n// \t\tKASSERT(error == 0, (\"%s: vm_unmap_mmio error %d\",\n// \t\t    __func__, error));\n\n// \t\t/*\n// \t\t * The MSR bitmap is shared by all vcpus so modify it only\n// \t\t * once in the context of vcpu 0.\n// \t\t */\n// \t\terror = vmx_allow_x2apic_msrs(vmx);\n// \t\tKASSERT(error == 0, (\"%s: vmx_allow_x2apic_msrs error %d\",\n// \t\t    __func__, error));\n// \t}\n// }\n\nstatic struct vlapic *\nvmx_vlapic_init(void *arg, int vcpuid)\n{\n\tstruct vmx *vmx;\n\tstruct vlapic *vlapic;\n\tstruct vlapic_vtx *vlapic_vtx;\n\t\n\tvmx = arg;\n\n\tvlapic = malloc(sizeof(struct vlapic_vtx));\n\tassert(vlapic);\n\tbzero(vlapic, sizeof(struct vlapic));\n\tvlapic->vm = vmx->vm;\n\tvlapic->vcpuid = vcpuid;\n\tvlapic->apic_page = (struct LAPIC *)&vmx->apic_page[vcpuid];\n\n\tvlapic_vtx = (struct vlapic_vtx *)vlapic;\n\tvlapic_vtx->vmx = vmx;\n\n\tvlapic_init(vlapic);\n\n\treturn (vlapic);\n}\n\nstatic void\nvmx_vlapic_cleanup(UNUSED void *arg, struct vlapic *vlapic)\n{\n\tvlapic_cleanup(vlapic);\n\tfree(vlapic);\n}\n\nstatic void\nvmx_vcpu_interrupt(int vcpu) {\n\thv_vcpuid_t hvvcpu;\n\n\thvvcpu = (hv_vcpuid_t) vcpu;\n\n\thv_vcpu_interrupt(&hvvcpu, 1);\n}\n\nstruct vmm_ops vmm_ops_intel = {\n\tvmx_init,\n\tvmx_cleanup,\n\tvmx_vm_init,\n\tvmx_vcpu_init,\n\tvmx_run,\n\tvmx_vm_cleanup,\n\tvmx_vcpu_cleanup,\n\tvmx_getreg,\n\tvmx_setreg,\n\tvmx_getdesc,\n\tvmx_setdesc,\n\tvmx_getcap,\n\tvmx_setcap,\n\tvmx_vlapic_init,\n\tvmx_vlapic_cleanup,\n\tvmx_vcpu_interrupt\n};\n"
  },
  {
    "path": "src/vmm/intel/vmx_msr.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <errno.h>\n#include <sys/sysctl.h>\n#include <Hypervisor/hv.h>\n#include <Hypervisor/hv_vmx.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/intel/vmx.h>\n#include <xhyve/vmm/intel/vmx_msr.h>\n\nstatic bool\nvmx_ctl_allows_one_setting(uint64_t msr_val, int bitpos)\n{\n\tif (msr_val & (1UL << (bitpos + 32)))\n\t\treturn (TRUE);\n\telse\n\t\treturn (FALSE);\n}\n\nstatic bool\nvmx_ctl_allows_zero_setting(uint64_t msr_val, int bitpos)\n{\n\tif ((msr_val & (1UL << bitpos)) == 0)\n\t\treturn (TRUE);\n\telse\n\t\treturn (FALSE);\n}\n\nint vmx_set_ctlreg(int vcpu_id, uint32_t field,\n\t\t\t\t   hv_vmx_capability_t cap_field, uint32_t ones_mask,\n\t\t\t\t   uint32_t zeros_mask, uint32_t *retval)\n{\n\tint i;\n\tuint64_t cap;\n\tbool one_allowed, zero_allowed;\n\n\t/* We cannot ask the same bit to be set to both '1' and '0' */\n\tif ((ones_mask ^ zeros_mask) != (ones_mask | zeros_mask)) {\n\t\treturn EINVAL;\n\t}\n\n\tif (hv_vmx_read_capability(cap_field, &cap)) {\n\t\treturn EINVAL;\n\t}\n\n\tuint64_t current = vmcs_read(vcpu_id, field);\n\n\tfor (i = 0; i < 32; i++) {\n\t\tone_allowed = vmx_ctl_allows_one_setting(cap, i);\n\t\tzero_allowed = vmx_ctl_allows_zero_setting(cap, i);\n\n\t\tif (zero_allowed && !one_allowed) {\n\t\t\t/* must be zero */\n\t\t\tif (ones_mask & (1 << i)) {\n\t\t\t\tfprintf(stderr,\n\t\t\t\t\t\"vmx_set_ctlreg: cap_field: %d bit: %d must be zero\\n\",\n\t\t\t\t\tcap_field, i);\n\t\t\t\treturn (EINVAL);\n\t\t\t}\n\t\t\t*retval &= ~(1 << i);\n\t\t} else if (one_allowed && !zero_allowed) {\n\t\t\t/* must be one */\n\t\t\tif (zeros_mask & (1 << i)) {\n\t\t\t\tfprintf(stderr,\n\t\t\t\t\t\"vmx_set_ctlreg: cap_field: %d bit: %d must be one\\n\",\n\t\t\t\t\tcap_field, i);\n\t\t\t\treturn (EINVAL);\n\t\t\t}\n\t\t\t*retval |= 1 << i;\n\t\t} else {\n\t\t\t/* don't care */\n\t\t\tif (zeros_mask & (1 << i)){\n\t\t\t\t*retval &= ~(1 << i);\n\t\t\t} else if (ones_mask & (1 << i)) {\n\t\t\t\t*retval |= 1 << i;\n\t\t\t} else {\n\t\t\t\t// Unknown: keep existing value.\n\t\t\t\t*retval = (*retval & ~(1 << i)) | (current & (1 << i));\n\t\t\t}\n\t\t}\n\t}\n\n\treturn (0);\n}\n\nstatic uint64_t misc_enable;\nstatic uint64_t platform_info;\nstatic uint64_t turbo_ratio_limit;\n\nstatic bool\npat_valid(uint64_t val)\n{\n\tint i, pa;\n\n\t/*\n\t * From Intel SDM: Table \"Memory Types That Can Be Encoded With PAT\"\n\t *\n\t * Extract PA0 through PA7 and validate that each one encodes a\n\t * valid memory type.\n\t */\n\tfor (i = 0; i < 8; i++) {\n\t\tpa = (val >> (i * 8)) & 0xff;\n\t\tif (pa == 2 || pa == 3 || pa >= 8)\n\t\t\treturn (false);\n\t}\n\treturn (true);\n}\n\nvoid\nvmx_msr_init(void) {\n\tuint64_t bus_freq, tsc_freq, ratio;\n\tsize_t length;\n\tint i;\n\t\n\tlength = sizeof(uint64_t);\n\n\tif (sysctlbyname(\"machdep.tsc.frequency\", &tsc_freq, &length, NULL, 0)) {\n\t  xhyve_abort(\"machdep.tsc.frequency\\n\");\n\t}\n\n\tif (sysctlbyname(\"hw.busfrequency\", &bus_freq, &length, NULL, 0)) {\n\t  xhyve_abort(\"hw.busfrequency\\n\");\n\t}\n\n\t/* Initialize emulated MSRs */\n\t/* FIXME */\n\tmisc_enable = 1;\n\t/*\n\t * Set mandatory bits\n\t *  11:   branch trace disabled\n\t *  12:   PEBS unavailable\n\t * Clear unsupported features\n\t *  16:   SpeedStep enable\n\t *  18:   enable MONITOR FSM\n\t */\n\tmisc_enable |= (1u << 12) | (1u << 11);\n\tmisc_enable &= ~((1u << 18) | (1u << 16));\n\n\t/*\n\t * XXXtime\n\t * The ratio should really be based on the virtual TSC frequency as\n\t * opposed to the host TSC.\n\t */\n\tratio = (tsc_freq / bus_freq) & 0xff;\n\n\t/*\n\t * The register definition is based on the micro-architecture\n\t * but the following bits are always the same:\n\t * [15:8]  Maximum Non-Turbo Ratio\n\t * [28]    Programmable Ratio Limit for Turbo Mode\n\t * [29]    Programmable TDC-TDP Limit for Turbo Mode\n\t * [47:40] Maximum Efficiency Ratio\n\t *\n\t * The other bits can be safely set to 0 on all\n\t * micro-architectures up to Haswell.\n\t */\n\tplatform_info = (ratio << 8) | (ratio << 40);\n\n\t/*\n\t * The number of valid bits in the MSR_TURBO_RATIO_LIMITx register is\n\t * dependent on the maximum cores per package supported by the micro-\n\t * architecture. For e.g., Westmere supports 6 cores per package and\n\t * uses the low 48 bits. Sandybridge support 8 cores per package and\n\t * uses up all 64 bits.\n\t *\n\t * However, the unused bits are reserved so we pretend that all bits\n\t * in this MSR are valid.\n\t */\n\tfor (i = 0; i < 8; i++) {\n\t  turbo_ratio_limit = (turbo_ratio_limit << 8) | ratio;\n\t}\n}\n\nvoid\nvmx_msr_guest_init(struct vmx *vmx, int vcpuid)\n{\n\tuint64_t *guest_msrs;\n\n\tguest_msrs = vmx->guest_msrs[vcpuid];\n\n\n\thv_vcpu_enable_native_msr(((hv_vcpuid_t) vcpuid), MSR_LSTAR, 1);\n\thv_vcpu_enable_native_msr(((hv_vcpuid_t) vcpuid), MSR_CSTAR, 1);\n\thv_vcpu_enable_native_msr(((hv_vcpuid_t) vcpuid), MSR_STAR, 1);\n\thv_vcpu_enable_native_msr(((hv_vcpuid_t) vcpuid), MSR_SF_MASK, 1);\n\thv_vcpu_enable_native_msr(((hv_vcpuid_t) vcpuid), MSR_KGSBASE, 1);\n\n\t/*\n\t * Initialize guest IA32_PAT MSR with default value after reset.\n\t */\n\tguest_msrs[IDX_MSR_PAT] = PAT_VALUE(0, PAT_WRITE_BACK) |\n\t\tPAT_VALUE(1, PAT_WRITE_THROUGH) |\n\t\tPAT_VALUE(2, PAT_UNCACHED)      |\n\t\tPAT_VALUE(3, PAT_UNCACHEABLE)   |\n\t\tPAT_VALUE(4, PAT_WRITE_BACK)    |\n\t\tPAT_VALUE(5, PAT_WRITE_THROUGH) |\n\t\tPAT_VALUE(6, PAT_UNCACHED)      |\n\t\tPAT_VALUE(7, PAT_UNCACHEABLE);\n\n\treturn;\n}\n\nint\nvmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val)\n{\n\tconst uint64_t *guest_msrs;\n\tint error;\n\n\tguest_msrs = vmx->guest_msrs[vcpuid];\n\terror = 0;\n\n\tswitch (num) {\n\tcase MSR_EFER:\n\t\t*val = vmcs_read(vcpuid, VMCS_GUEST_IA32_EFER);\n\t\tbreak;\n\tcase MSR_MCG_CAP:\n\tcase MSR_MCG_STATUS:\n\t\t*val = 0;\n\t\tbreak;\n\tcase MSR_MTRRcap:\n\tcase MSR_MTRRdefType:\n\tcase MSR_MTRR4kBase:\n\tcase MSR_MTRR4kBase + 1:\n\tcase MSR_MTRR4kBase + 2:\n\tcase MSR_MTRR4kBase + 3:\n\tcase MSR_MTRR4kBase + 4:\n\tcase MSR_MTRR4kBase + 5:\n\tcase MSR_MTRR4kBase + 6:\n\tcase MSR_MTRR4kBase + 7:\n\tcase MSR_MTRR4kBase + 8:\n\tcase MSR_MTRR16kBase:\n\tcase MSR_MTRR16kBase + 1:\n\tcase MSR_MTRR64kBase:\n\t\t*val = 0;\n\t\tbreak;\n\tcase MSR_IA32_MISC_ENABLE:\n\t\t*val = misc_enable;\n\t\tbreak;\n\tcase MSR_PLATFORM_INFO:\n\t\t*val = platform_info;\n\t\tbreak;\n\tcase MSR_TURBO_RATIO_LIMIT:\n\tcase MSR_TURBO_RATIO_LIMIT1:\n\t\t*val = turbo_ratio_limit;\n\t\tbreak;\n\tcase MSR_PAT:\n\t\t*val = guest_msrs[IDX_MSR_PAT];\n\t\tbreak;\n\tdefault:\n\t\terror = EINVAL;\n\t\tbreak;\n\t}\n\treturn (error);\n}\n\nint\nvmx_wrmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t val)\n{\n\tuint64_t *guest_msrs;\n\tuint64_t changed;\n\tint error;\n\t\n\tguest_msrs = vmx->guest_msrs[vcpuid];\n\terror = 0;\n\n\tswitch (num) {\n\tcase MSR_EFER:\n\t\tvmcs_write(vcpuid, VMCS_GUEST_IA32_EFER, val);\n\t\tbreak;\n\tcase MSR_MCG_CAP:\n\tcase MSR_MCG_STATUS:\n\t\tbreak;      /* ignore writes */\n\tcase MSR_MTRRcap:\n\t\tvm_inject_gp(vmx->vm, vcpuid);\n\t\tbreak;\n\tcase MSR_MTRRdefType:\n\tcase MSR_MTRR4kBase:\n\tcase MSR_MTRR4kBase + 1:\n\tcase MSR_MTRR4kBase + 2:\n\tcase MSR_MTRR4kBase + 3:\n\tcase MSR_MTRR4kBase + 4:\n\tcase MSR_MTRR4kBase + 5:\n\tcase MSR_MTRR4kBase + 6:\n\tcase MSR_MTRR4kBase + 7:\n\tcase MSR_MTRR4kBase + 8:\n\tcase MSR_MTRR16kBase:\n\tcase MSR_MTRR16kBase + 1:\n\tcase MSR_MTRR64kBase:\n\t\tbreak;      /* Ignore writes */\n\tcase MSR_IA32_MISC_ENABLE:\n\t\tchanged = val ^ misc_enable;\n\t\t/*\n\t\t * If the host has disabled the NX feature then the guest\n\t\t * also cannot use it. However, a Linux guest will try to\n\t\t * enable the NX feature by writing to the MISC_ENABLE MSR.\n\t\t *\n\t\t * This can be safely ignored because the memory management\n\t\t * code looks at CPUID.80000001H:EDX.NX to check if the\n\t\t * functionality is actually enabled.\n\t\t */\n\t\tchanged &= ~(1UL << 34);\n\n\t\t/*\n\t\t * Punt to userspace if any other bits are being modified.\n\t\t */\n\t\tif (changed)\n\t\t\terror = EINVAL;\n\n\t\tbreak;\n\tcase MSR_PAT:\n\t\tif (pat_valid(val))\n\t\t\tguest_msrs[IDX_MSR_PAT] = val;\n\t\telse\n\t\t\tvm_inject_gp(vmx->vm, vcpuid);\n\t\tbreak;\n\tdefault:\n\t\terror = EINVAL;\n\t\tbreak;\n\t}\n\n\treturn (error);\n}\n"
  },
  {
    "path": "src/vmm/io/vatpic.c",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <errno.h>\n#include <assert.h>\n#include <xhyve/lock.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/i8259.h>\n#include <xhyve/support/apicreg.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vioapic.h>\n\n#define VATPIC_LOCK_INIT(v) XHYVE_LOCK_INIT(v, lock)\n#define VATPIC_LOCK(v) XHYVE_LOCK(v, lock)\n#define VATPIC_UNLOCK(v) XHYVE_UNLOCK(v, lock)\n\nenum irqstate {\n\tIRQSTATE_ASSERT,\n\tIRQSTATE_DEASSERT,\n\tIRQSTATE_PULSE\n};\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct atpic {\n\tbool ready;\n\tint icw_num;\n\tint rd_cmd_reg;\n\tbool aeoi;\n\tbool poll;\n\tbool rotate;\n\tbool sfn; /* special fully-nested mode */\n\tint irq_base;\n\tuint8_t request; /* Interrupt Request Register (IIR) */\n\tuint8_t service; /* Interrupt Service (ISR) */\n\tuint8_t mask; /* Interrupt Mask Register (IMR) */\n\tuint8_t smm; /* special mask mode */\n\tint acnt[8]; /* sum of pin asserts and deasserts */\n\tint lowprio; /* lowest priority irq */\n\tbool intr_raised;\n};\n\nstruct vatpic {\n\tstruct vm *vm;\n\txhyve_lock_t lock;\n\tstruct atpic atpic[2];\n\tuint8_t elc[2];\n};\n#pragma clang diagnostic pop\n\n#define\tVATPIC_CTR0(vatpic, fmt)\t\t\t\t\t\\\n\tVM_CTR0((vatpic)->vm, fmt)\n\n#define\tVATPIC_CTR1(vatpic, fmt, a1)\t\t\t\t\t\\\n\tVM_CTR1((vatpic)->vm, fmt, a1)\n\n#define\tVATPIC_CTR2(vatpic, fmt, a1, a2)\t\t\t\t\\\n\tVM_CTR2((vatpic)->vm, fmt, a1, a2)\n\n#define\tVATPIC_CTR3(vatpic, fmt, a1, a2, a3)\t\t\t\t\\\n\tVM_CTR3((vatpic)->vm, fmt, a1, a2, a3)\n\n#define\tVATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4)\t\t\t\\\n\tVM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4)\n\n/*\n * Loop over all the pins in priority order from highest to lowest.\n */\n#define\tATPIC_PIN_FOREACH(pinvar, atpic, tmpvar)\t\t\t\\\n\tfor (tmpvar = 0, pinvar = (atpic->lowprio + 1) & 0x7;\t\t\\\n\t    tmpvar < 8;\t\t\t\t\t\t\t\\\n\t    tmpvar++, pinvar = (pinvar + 1) & 0x7)\n\nstatic void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);\n\nstatic __inline bool\nmaster_atpic(struct vatpic *vatpic, struct atpic *atpic)\n{\n\n\tif (atpic == &vatpic->atpic[0])\n\t\treturn (true);\n\telse\n\t\treturn (false);\n}\n\nstatic __inline int\nvatpic_get_highest_isrpin(struct atpic *atpic)\n{\n\tint bit, pin;\n\tint i;\n\n\tATPIC_PIN_FOREACH(pin, atpic, i) {\n                bit = (1 << pin);\n\n\t\tif (atpic->service & bit) {\n\t\t\t/*\n\t\t\t * An IS bit that is masked by an IMR bit will not be\n\t\t\t * cleared by a non-specific EOI in Special Mask Mode.\n\t\t\t */\n\t\t\tif (atpic->smm && (atpic->mask & bit) != 0)\n\t\t\t\tcontinue;\n\t\t\telse\n\t\t\t\treturn (pin);\n\t\t}\n\t}\n\n\treturn (-1);\n}\n\nstatic __inline int\nvatpic_get_highest_irrpin(struct atpic *atpic)\n{\n\tint serviced;\n\tint bit, pin, tmp;\n\n\t/*\n\t * In 'Special Fully-Nested Mode' when an interrupt request from\n\t * a slave is in service, the slave is not locked out from the\n\t * master's priority logic.\n\t */\n\tserviced = atpic->service;\n\tif (atpic->sfn)\n\t\tserviced &= ~(1 << 2);\n\n\t/*\n\t * In 'Special Mask Mode', when a mask bit is set in OCW1 it inhibits\n\t * further interrupts at that level and enables interrupts from all\n\t * other levels that are not masked. In other words the ISR has no\n\t * bearing on the levels that can generate interrupts.\n\t */\n\tif (atpic->smm)\n\t\tserviced = 0;\n\n\tATPIC_PIN_FOREACH(pin, atpic, tmp) {\n\t\tbit = 1 << pin;\n\n\t\t/*\n\t\t * If there is already an interrupt in service at the same\n\t\t * or higher priority then bail.\n\t\t */\n\t\tif ((serviced & bit) != 0)\n\t\t\tbreak;\n\n\t\t/*\n\t\t * If an interrupt is asserted and not masked then return\n\t\t * the corresponding 'pin' to the caller.\n\t\t */\n\t\tif ((atpic->request & bit) != 0 && (atpic->mask & bit) == 0)\n\t\t\treturn (pin);\n\t}\n\n\treturn (-1);\n}\n\nstatic void\nvatpic_notify_intr(struct vatpic *vatpic)\n{\n\tstruct atpic *atpic;\n\tint pin;\n\n\t/*\n\t * First check the slave.\n\t */\n\tatpic = &vatpic->atpic[1];\n\tif (!atpic->intr_raised &&\n\t    (pin = vatpic_get_highest_irrpin(atpic)) != -1) {\n\t\tVATPIC_CTR4(vatpic, \"atpic slave notify pin = %d \"\n\t\t    \"(imr 0x%x irr 0x%x isr 0x%x)\", pin,\n\t\t    atpic->mask, atpic->request, atpic->service);\n\n\t\t/*\n\t\t * Cascade the request from the slave to the master.\n\t\t */\n\t\tatpic->intr_raised = true;\n\t\tvatpic_set_pinstate(vatpic, 2, true);\n\t\tvatpic_set_pinstate(vatpic, 2, false);\n\t} else {\n\t\tVATPIC_CTR3(vatpic, \"atpic slave no eligible interrupts \"\n\t\t    \"(imr 0x%x irr 0x%x isr 0x%x)\",\n\t\t    atpic->mask, atpic->request, atpic->service);\n\t}\n\n\t/*\n\t * Then check the master.\n\t */\n\tatpic = &vatpic->atpic[0];\n\tif (!atpic->intr_raised &&\n\t    (pin = vatpic_get_highest_irrpin(atpic)) != -1) {\n\t\tVATPIC_CTR4(vatpic, \"atpic master notify pin = %d \"\n\t\t    \"(imr 0x%x irr 0x%x isr 0x%x)\", pin,\n\t\t    atpic->mask, atpic->request, atpic->service);\n\n\t\t/*\n\t\t * From Section 3.6.2, \"Interrupt Modes\", in the\n\t\t * MPtable Specification, Version 1.4\n\t\t *\n\t\t * PIC interrupts are routed to both the Local APIC\n\t\t * and the I/O APIC to support operation in 1 of 3\n\t\t * modes.\n\t\t *\n\t\t * 1. Legacy PIC Mode: the PIC effectively bypasses\n\t\t * all APIC components.  In this mode the local APIC is\n\t\t * disabled and LINT0 is reconfigured as INTR to\n\t\t * deliver the PIC interrupt directly to the CPU.\n\t\t *\n\t\t * 2. Virtual Wire Mode: the APIC is treated as a\n\t\t * virtual wire which delivers interrupts from the PIC\n\t\t * to the CPU.  In this mode LINT0 is programmed as\n\t\t * ExtINT to indicate that the PIC is the source of\n\t\t * the interrupt.\n\t\t *\n\t\t * 3. Virtual Wire Mode via I/O APIC: PIC interrupts are\n\t\t * fielded by the I/O APIC and delivered to the appropriate\n\t\t * CPU.  In this mode the I/O APIC input 0 is programmed\n\t\t * as ExtINT to indicate that the PIC is the source of the\n\t\t * interrupt.\n\t\t */\n\t\tatpic->intr_raised = true;\n\t\tlapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0);\n\t\tvioapic_pulse_irq(vatpic->vm, 0);\n\t} else {\n\t\tVATPIC_CTR3(vatpic, \"atpic master no eligible interrupts \"\n\t\t    \"(imr 0x%x irr 0x%x isr 0x%x)\",\n\t\t    atpic->mask, atpic->request, atpic->service);\n\t}\n}\n\nstatic int\nvatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic icw1 0x%x\", val);\n\n\tatpic->ready = false;\n\n\tatpic->icw_num = 1;\n\tatpic->request = 0;\n\tatpic->mask = 0;\n\tatpic->lowprio = 7;\n\tatpic->rd_cmd_reg = 0;\n\tatpic->poll = 0;\n\tatpic->smm = 0;\n\n\tif ((val & ICW1_SNGL) != 0) {\n\t\tVATPIC_CTR0(vatpic, \"vatpic cascade mode required\");\n\t\treturn (-1);\n\t}\n\n\tif ((val & ICW1_IC4) == 0) {\n\t\tVATPIC_CTR0(vatpic, \"vatpic icw4 required\");\n\t\treturn (-1);\n\t}\n\n\tatpic->icw_num++;\n\n\treturn (0);\n}\n\nstatic int\nvatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic icw2 0x%x\", val);\n\n\tatpic->irq_base = val & 0xf8;\n\n\tatpic->icw_num++;\n\n\treturn (0);\n}\n\nstatic int\nvatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic icw3 0x%x\", val);\n\n\tatpic->icw_num++;\n\n\treturn (0);\n}\n\nstatic int\nvatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic icw4 0x%x\", val);\n\n\tif ((val & ICW4_8086) == 0) {\n\t\tVATPIC_CTR0(vatpic, \"vatpic microprocessor mode required\");\n\t\treturn (-1);\n\t}\n\n\tif ((val & ICW4_AEOI) != 0)\n\t\tatpic->aeoi = true;\n\n\tif ((val & ICW4_SFNM) != 0) {\n\t\tif (master_atpic(vatpic, atpic)) {\n\t\t\tatpic->sfn = true;\n\t\t} else {\n\t\t\tVATPIC_CTR1(vatpic, \"Ignoring special fully nested \"\n\t\t\t    \"mode on slave atpic: %#x\", val);\n\t\t}\n\t}\n\n\tatpic->icw_num = 0;\n\tatpic->ready = true;\n\n\treturn (0);\n}\n\nstatic int\nvatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic ocw1 0x%x\", val);\n\n\tatpic->mask = val & 0xff;\n\n\treturn (0);\n}\n\nstatic int\nvatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic ocw2 0x%x\", val);\n\n\tatpic->rotate = ((val & OCW2_R) != 0);\n\n\tif ((val & OCW2_EOI) != 0) {\n\t\tint isr_bit;\n\n\t\tif ((val & OCW2_SL) != 0) {\n\t\t\t/* specific EOI */\n\t\t\tisr_bit = val & 0x7;\n\t\t} else {\n\t\t\t/* non-specific EOI */\n\t\t\tisr_bit = vatpic_get_highest_isrpin(atpic);\n\t\t}\n\n\t\tif (isr_bit != -1) {\n\t\t\tatpic->service &= ~(1 << isr_bit);\n\n\t\t\tif (atpic->rotate)\n\t\t\t\tatpic->lowprio = isr_bit;\n\t\t}\n\t} else if ((val & OCW2_SL) != 0 && atpic->rotate == true) {\n\t\t/* specific priority */\n\t\tatpic->lowprio = val & 0x7;\n\t}\n\n\treturn (0);\n}\n\nstatic int\nvatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)\n{\n\tVATPIC_CTR1(vatpic, \"atpic ocw3 0x%x\", val);\n\n\tif (val & OCW3_ESMM) {\n\t\tatpic->smm = val & OCW3_SMM ? 1 : 0;\n\t\tVATPIC_CTR2(vatpic, \"%s atpic special mask mode %s\",\n\t\t    master_atpic(vatpic, atpic) ? \"master\" : \"slave\",\n\t\t    atpic->smm ?  \"enabled\" : \"disabled\");\n\t}\n\n\tif (val & OCW3_RR) {\n\t\t/* read register command */\n\t\tatpic->rd_cmd_reg = val & OCW3_RIS;\n\n\t\t/* Polling mode */\n\t\tatpic->poll = ((val & OCW3_P) != 0);\n\t}\n\n\treturn (0);\n}\n\nstatic void\nvatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)\n{\n\tstruct atpic *atpic;\n\tint oldcnt, newcnt;\n\tbool level;\n\n\tKASSERT(pin >= 0 && pin < 16,\n\t    (\"vatpic_set_pinstate: invalid pin number %d\", pin));\n\n\tatpic = &vatpic->atpic[pin >> 3];\n\n\toldcnt = atpic->acnt[pin & 0x7];\n\tif (newstate)\n\t\tatpic->acnt[pin & 0x7]++;\n\telse\n\t\tatpic->acnt[pin & 0x7]--;\n\tnewcnt = atpic->acnt[pin & 0x7];\n\n\tif (newcnt < 0) {\n\t\tVATPIC_CTR2(vatpic, \"atpic pin%d: bad acnt %d\", pin, newcnt);\n\t}\n\n\tlevel = ((vatpic->elc[pin >> 3] & (1 << (pin & 0x7))) != 0);\n\n\tif ((oldcnt == 0 && newcnt == 1) || (newcnt > 0 && level == true)) {\n\t\t/* rising edge or level */\n\t\tVATPIC_CTR1(vatpic, \"atpic pin%d: asserted\", pin);\n\t\tatpic->request |= (1 << (pin & 0x7));\n\t} else if (oldcnt == 1 && newcnt == 0) {\n\t\t/* falling edge */\n\t\tVATPIC_CTR1(vatpic, \"atpic pin%d: deasserted\", pin);\n\t\tif (level)\n\t\t\tatpic->request &= ~(1 << (pin & 0x7));\n\t} else {\n\t\tVATPIC_CTR3(vatpic, \"atpic pin%d: %s, ignored, acnt %d\",\n\t\t    pin, newstate ? \"asserted\" : \"deasserted\", newcnt);\n\t}\n\n\tvatpic_notify_intr(vatpic);\n}\n\nstatic int\nvatpic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)\n{\n\tstruct vatpic *vatpic;\n\tstruct atpic *atpic;\n\n\tif (irq < 0 || irq > 15)\n\t\treturn (EINVAL);\n\n\tvatpic = vm_atpic(vm);\n\tatpic = &vatpic->atpic[irq >> 3];\n\n\tif (atpic->ready == false)\n\t\treturn (0);\n\n\tVATPIC_LOCK(vatpic);\n\tswitch (irqstate) {\n\tcase IRQSTATE_ASSERT:\n\t\tvatpic_set_pinstate(vatpic, irq, true);\n\t\tbreak;\n\tcase IRQSTATE_DEASSERT:\n\t\tvatpic_set_pinstate(vatpic, irq, false);\n\t\tbreak;\n\tcase IRQSTATE_PULSE:\n\t\tvatpic_set_pinstate(vatpic, irq, true);\n\t\tvatpic_set_pinstate(vatpic, irq, false);\n\t\tbreak;\n\t}\n\tVATPIC_UNLOCK(vatpic);\n\n\treturn (0);\n}\n\nint\nvatpic_assert_irq(struct vm *vm, int irq)\n{\n\treturn (vatpic_set_irqstate(vm, irq, IRQSTATE_ASSERT));\n}\n\nint\nvatpic_deassert_irq(struct vm *vm, int irq)\n{\n\treturn (vatpic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));\n}\n\nint\nvatpic_pulse_irq(struct vm *vm, int irq)\n{\n\treturn (vatpic_set_irqstate(vm, irq, IRQSTATE_PULSE));\n}\n\nint\nvatpic_set_irq_trigger(struct vm *vm, int irq, enum vm_intr_trigger trigger)\n{\n\tstruct vatpic *vatpic;\n\n\tif (irq < 0 || irq > 15)\n\t\treturn (EINVAL);\n\n\t/*\n\t * See comment in vatpic_elc_handler.  These IRQs must be\n\t * edge triggered.\n\t */\n\tif (trigger == LEVEL_TRIGGER) {\n\t\tswitch (irq) {\n\t\tcase 0:\n\t\tcase 1:\n\t\tcase 2:\n\t\tcase 8:\n\t\tcase 13:\n\t\t\treturn (EINVAL);\n\t\t}\n\t}\n\n\tvatpic = vm_atpic(vm);\n\n\tVATPIC_LOCK(vatpic);\n\n\tif (trigger == LEVEL_TRIGGER)\n\t\tvatpic->elc[irq >> 3] |=  1 << (irq & 0x7);\n\telse\n\t\tvatpic->elc[irq >> 3] &=  ~(1 << (irq & 0x7));\n\n\tVATPIC_UNLOCK(vatpic);\n\n\treturn (0);\n}\n\nvoid\nvatpic_pending_intr(struct vm *vm, int *vecptr)\n{\n\tstruct vatpic *vatpic;\n\tstruct atpic *atpic;\n\tint pin;\n\n\tvatpic = vm_atpic(vm);\n\n\tatpic = &vatpic->atpic[0];\n\n\tVATPIC_LOCK(vatpic);\n\n\tpin = vatpic_get_highest_irrpin(atpic);\n\tif (pin == 2) {\n\t\tatpic = &vatpic->atpic[1];\n\t\tpin = vatpic_get_highest_irrpin(atpic);\n\t}\n\n\t/*\n\t * If there are no pins active at this moment then return the spurious\n\t * interrupt vector instead.\n\t */\n\tif (pin == -1)\n\t\tpin = 7;\n\n\tKASSERT(pin >= 0 && pin <= 7, (\"%s: invalid pin %d\", __func__, pin));\n\t*vecptr = atpic->irq_base + pin;\n\n\tVATPIC_UNLOCK(vatpic);\n}\n\nstatic void\nvatpic_pin_accepted(struct atpic *atpic, int pin)\n{\n\tatpic->intr_raised = false;\n\n\tif (atpic->acnt[pin] == 0)\n\t\tatpic->request &= ~(1 << pin);\n\n\tif (atpic->aeoi == true) {\n\t\tif (atpic->rotate == true)\n\t\t\tatpic->lowprio = pin;\n\t} else {\n\t\tatpic->service |= (1 << pin);\n\t}\n}\n\nvoid\nvatpic_intr_accepted(struct vm *vm, int vector)\n{\n\tstruct vatpic *vatpic;\n\tint pin;\n\n\tvatpic = vm_atpic(vm);\n\n\tVATPIC_LOCK(vatpic);\n\n\tpin = vector & 0x7;\n\n\tif ((vector & ~0x7) == vatpic->atpic[1].irq_base) {\n\t\tvatpic_pin_accepted(&vatpic->atpic[1], pin);\n\t\t/*\n\t\t * If this vector originated from the slave,\n\t\t * accept the cascaded interrupt too.\n\t\t */\n\t\tvatpic_pin_accepted(&vatpic->atpic[0], 2);\n\t} else {\n\t\tvatpic_pin_accepted(&vatpic->atpic[0], pin);\n\t}\n\n\tvatpic_notify_intr(vatpic);\n\n\tVATPIC_UNLOCK(vatpic);\n}\n\nstatic int\nvatpic_read(struct vatpic *vatpic, struct atpic *atpic, UNUSED bool in,\n\tint port, UNUSED int bytes, uint32_t *eax)\n{\n\tint pin;\n\tVATPIC_LOCK(vatpic);\n\n\tif (atpic->poll) {\n\t\tatpic->poll = 0;\n\t\tpin = vatpic_get_highest_irrpin(atpic);\n\t\tif (pin >= 0) {\n\t\t\tvatpic_pin_accepted(atpic, pin);\n\t\t\t*eax = 0x80 | ((uint32_t) pin);\n\t\t} else {\n\t\t\t*eax = 0;\n\t\t}\n\t} else {\n\t\tif (port & ICU_IMR_OFFSET) {\n\t\t\t/* read interrrupt mask register */\n\t\t\t*eax = atpic->mask;\n\t\t} else {\n\t\t\tif (atpic->rd_cmd_reg == OCW3_RIS) {\n\t\t\t\t/* read interrupt service register */\n\t\t\t\t*eax = atpic->service;\n\t\t\t} else {\n\t\t\t\t/* read interrupt request register */\n\t\t\t\t*eax = atpic->request;\n\t\t\t}\n\t\t}\n\t}\n\n\tVATPIC_UNLOCK(vatpic);\n//printf(\"vatpic_read 0x%04x 0x%02x\\n\", port, (uint8_t)*eax);\n\treturn (0);\n\n}\n\nstatic int\nvatpic_write(struct vatpic *vatpic, struct atpic *atpic, UNUSED bool in,\n\tint port, UNUSED int bytes, uint32_t *eax)\n{\n\tint error;\n\tuint8_t val;\n\n\terror = 0;\n\tval = (uint8_t) *eax;\n//printf(\"vatpic_write 0x%04x 0x%02x %d\\n\", port, val, atpic->icw_num);\n\tVATPIC_LOCK(vatpic);\n\n\tif (port & ICU_IMR_OFFSET) {\n\t\tswitch (atpic->icw_num) {\n\t\tcase 2:\n\t\t\terror = vatpic_icw2(vatpic, atpic, val);\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\terror = vatpic_icw3(vatpic, atpic, val);\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\terror = vatpic_icw4(vatpic, atpic, val);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\terror = vatpic_ocw1(vatpic, atpic, val);\n\t\t\tbreak;\n\t\t}\n\t} else {\n\t\tif (val & (1 << 4))\n\t\t\terror = vatpic_icw1(vatpic, atpic, val);\n\n\t\tif (atpic->ready) {\n\t\t\tif (val & (1 << 3))\n\t\t\t\terror = vatpic_ocw3(vatpic, atpic, val);\n\t\t\telse\n\t\t\t\terror = vatpic_ocw2(vatpic, atpic, val);\n\t\t}\n\t}\n\n\tif (atpic->ready)\n\t\tvatpic_notify_intr(vatpic);\n\n\tVATPIC_UNLOCK(vatpic);\n\n\treturn (error);\n}\n\nint\nvatpic_master_handler(struct vm *vm, UNUSED int vcpuid, bool in, int port,\n\tint bytes, uint32_t *eax)\n{\n\tstruct vatpic *vatpic;\n\tstruct atpic *atpic;\n\n\tvatpic = vm_atpic(vm);\n\tatpic = &vatpic->atpic[0];\n\n\tif (bytes != 1)\n\t\treturn (-1);\n \n\tif (in) {\n\t\treturn (vatpic_read(vatpic, atpic, in, port, bytes, eax));\n\t}\n \n\treturn (vatpic_write(vatpic, atpic, in, port, bytes, eax));\n}\n\nint\nvatpic_slave_handler(struct vm *vm, UNUSED int vcpuid, bool in, int port,\n\tint bytes, uint32_t *eax)\n{\n\tstruct vatpic *vatpic;\n\tstruct atpic *atpic;\n\n\tvatpic = vm_atpic(vm);\n\tatpic = &vatpic->atpic[1];\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tif (in) {\n\t\treturn (vatpic_read(vatpic, atpic, in, port, bytes, eax));\n\t}\n\n\treturn (vatpic_write(vatpic, atpic, in, port, bytes, eax));\n}\n\nint\nvatpic_elc_handler(struct vm *vm, UNUSED int vcpuid, bool in, int port,\n\tint bytes, uint32_t *eax)\n{\n\tstruct vatpic *vatpic;\n\tbool is_master;\n\n\tvatpic = vm_atpic(vm);\n\tis_master = (port == IO_ELCR1);\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tVATPIC_LOCK(vatpic);\n\n\tif (in) {\n\t\tif (is_master)\n\t\t\t*eax = vatpic->elc[0];\n\t\telse\n\t\t\t*eax = vatpic->elc[1];\n\t} else {\n\t\t/*\n\t\t * For the master PIC the cascade channel (IRQ2), the\n\t\t * heart beat timer (IRQ0), and the keyboard\n\t\t * controller (IRQ1) cannot be programmed for level\n\t\t * mode.\n\t\t *\n\t\t * For the slave PIC the real time clock (IRQ8) and\n\t\t * the floating point error interrupt (IRQ13) cannot\n\t\t * be programmed for level mode.\n\t\t */\n\t\tif (is_master)\n\t\t\tvatpic->elc[0] = (*eax & 0xf8);\n\t\telse\n\t\t\tvatpic->elc[1] = (*eax & 0xde);\n\t}\n\n\tVATPIC_UNLOCK(vatpic);\n\n\treturn (0);\n}\n\nstruct vatpic *\nvatpic_init(struct vm *vm)\n{\n\tstruct vatpic *vatpic;\n\n\tvatpic = malloc(sizeof(struct vatpic));\n\tassert(vatpic);\n\tbzero(vatpic, sizeof(struct vatpic));\n\tvatpic->vm = vm;\n\n\tVATPIC_LOCK_INIT(vatpic);\n\n\treturn (vatpic);\n}\n\nvoid\nvatpic_cleanup(struct vatpic *vatpic)\n{\n\tfree(vatpic);\n}\n"
  },
  {
    "path": "src/vmm/io/vatpit.c",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <assert.h>\n#include <xhyve/lock.h>\n#include <xhyve/support/timerreg.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vatpit.h>\n#include <xhyve/vmm/io/vioapic.h>\n\n#define VATPIT_LOCK_INIT(v) XHYVE_LOCK_INIT(v, lock)\n#define VATPIT_LOCK(v) XHYVE_LOCK(v, lock)\n#define VATPIT_UNLOCK(v) XHYVE_UNLOCK(v, lock)\n\n#define\tTIMER_SEL_MASK\t\t0xc0\n#define\tTIMER_RW_MASK\t\t0x30\n#define\tTIMER_MODE_MASK\t\t0x0f\n#define\tTIMER_SEL_READBACK\t0xc0\n\n#define\tTIMER_STS_OUT\t\t0x80\n#define\tTIMER_STS_NULLCNT\t0x40\n\n#define\tTIMER_RB_LCTR\t\t0x20\n#define\tTIMER_RB_LSTATUS\t0x10\n#define\tTIMER_RB_CTR_2\t\t0x08\n#define\tTIMER_RB_CTR_1\t\t0x04\n#define\tTIMER_RB_CTR_0\t\t0x02\n\n#define\tTMR2_OUT_STS\t\t0x20\n\n#define\tPIT_8254_FREQ\t\t1193182\n#define\tTIMER_DIV(freq, hz)\t(((freq) + (hz) / 2) / (hz))\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vatpit_callout_arg {\n\tstruct vatpit *vatpit;\n\tint channel_num;\n};\n\nstruct channel {\n\tint mode;\n\tuint16_t initial; /* initial counter value */\n\tsbintime_t now_sbt; /* uptime when counter was loaded */\n\tuint8_t cr[2];\n\tuint8_t ol[2];\n\tbool slatched; /* status latched */\n\tuint8_t status;\n\tint crbyte;\n\tint olbyte;\n\tint frbyte;\n\tstruct callout callout;\n\tsbintime_t callout_sbt; /* target time */\n\tstruct vatpit_callout_arg callout_arg;\n};\n\nstruct vatpit {\n\tstruct vm *vm;\n\txhyve_lock_t lock;\n\tsbintime_t freq_sbt;\n\tstruct channel channel[3];\n};\n#pragma clang diagnostic pop\n\nstatic void pit_timer_start_cntr0(struct vatpit *vatpit);\n\nstatic int\nvatpit_get_out(struct vatpit *vatpit, int channel)\n{\n\tstruct channel *c;\n\tsbintime_t delta_ticks;\n\tint out;\n\n\tc = &vatpit->channel[channel];\n\n\tswitch (c->mode) {\n\tcase TIMER_INTTC:\n\t\tdelta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;\n\t\tout = ((c->initial - delta_ticks) <= 0);\n\t\tbreak;\n\tdefault:\n\t\tout = 0;\n\t\tbreak;\n\t}\n\n\treturn (out);\n}\n\nstatic void\nvatpit_callout_handler(void *a)\n{\n\tstruct vatpit_callout_arg *arg = a;\n\tstruct vatpit *vatpit;\n\tstruct callout *callout;\n\tstruct channel *c;\n\n\tvatpit = arg->vatpit;\n\tc = &vatpit->channel[arg->channel_num];\n\tcallout = &c->callout;\n\n\tVM_CTR1(vatpit->vm, \"atpit t%d fired\", arg->channel_num);\n\n\tVATPIT_LOCK(vatpit);\n\n\tif (callout_pending(callout))\t\t/* callout was reset */\n\t\tgoto done;\n\n\tif (!callout_active(callout))\t\t/* callout was stopped */\n\t\tgoto done;\n\n\tcallout_deactivate(callout);\n\n\tif (c->mode == TIMER_RATEGEN) {\n\t\tpit_timer_start_cntr0(vatpit);\n\t}\n\n\tvatpic_pulse_irq(vatpit->vm, 0);\n\tvioapic_pulse_irq(vatpit->vm, 2);\n\ndone:\n\tVATPIT_UNLOCK(vatpit);\n\treturn;\n}\n\nstatic void\npit_timer_start_cntr0(struct vatpit *vatpit)\n{\n\tstruct channel *c;\n\tsbintime_t now, delta, precision;\n\n\tc = &vatpit->channel[0];\n\tif (c->initial != 0) {\n\t\tdelta = c->initial * vatpit->freq_sbt;\n\t\tprecision = delta >> tc_precexp;\n\t\tc->callout_sbt = c->callout_sbt + delta;\n\n\t\t/*\n\t\t * Reset 'callout_sbt' if the time that the callout\n\t\t * was supposed to fire is more than 'c->initial'\n\t\t * ticks in the past.\n\t\t */\n\t\tnow = sbinuptime();\n\t\tif (c->callout_sbt < now)\n\t\t\tc->callout_sbt = now + delta;\n\n\t\tcallout_reset_sbt(&c->callout, c->callout_sbt,\n\t\t    precision, vatpit_callout_handler, &c->callout_arg,\n\t\t    C_ABSOLUTE);\n\t}\n}\n\nstatic uint16_t\npit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)\n{\n\tuint16_t lval;\n\tsbintime_t delta_ticks;\n\n\t/* cannot latch a new value until the old one has been consumed */\n\tif (latch && c->olbyte != 0)\n\t\treturn (0);\n\n\tif (c->initial == 0) {\n\t\t/*\n\t\t * This is possibly an o/s bug - reading the value of\n\t\t * the timer without having set up the initial value.\n\t\t *\n\t\t * The original user-space version of this code set\n\t\t * the timer to 100hz in this condition; do the same\n\t\t * here.\n\t\t */\n\t\tc->initial = TIMER_DIV(PIT_8254_FREQ, 100);\n\t\tc->now_sbt = sbinuptime();\n\t\tc->status &= ~TIMER_STS_NULLCNT;\n\t}\n\n\tdelta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;\n\n\tlval = c->initial - delta_ticks % c->initial;\n\n\tif (latch) {\n\t\tc->olbyte = 2;\n\t\tc->ol[1] = (uint8_t) lval; /* LSB */\n\t\tc->ol[0] = (uint8_t) (lval >> 8); /* MSB */\n\t}\n\n\treturn (lval);\n}\n\nstatic int\npit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd)\n{\n\tstruct channel *c;\n\n\tc = &vatpit->channel[channel];\n\n\t/*\n\t * Latch the count/status of the timer if not already latched.\n\t * N.B. that the count/status latch-select bits are active-low.\n\t */\n\tif (!(cmd & TIMER_RB_LCTR) && !c->olbyte) {\n\t\t(void) pit_update_counter(vatpit, c, true);\n\t}\n\n\tif (!(cmd & TIMER_RB_LSTATUS) && !c->slatched) {\n\t\tc->slatched = true;\n\t\t/*\n\t\t * For mode 0, see if the elapsed time is greater\n\t\t * than the initial value - this results in the\n\t\t * output pin being set to 1 in the status byte.\n\t\t */\n\t\tif (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel))\n\t\t\tc->status |= TIMER_STS_OUT;\n\t\telse\n\t\t\tc->status &= ~TIMER_STS_OUT;\n\t}\n\n\treturn (0);\n}\n\nstatic int\npit_readback(struct vatpit *vatpit, uint8_t cmd)\n{\n\tint error;\n\n\t/*\n\t * The readback command can apply to all timers.\n\t */\n\terror = 0;\n\tif (cmd & TIMER_RB_CTR_0)\n\t\terror = pit_readback1(vatpit, 0, cmd);\n\tif (!error && cmd & TIMER_RB_CTR_1)\n\t\terror = pit_readback1(vatpit, 1, cmd);\n\tif (!error && cmd & TIMER_RB_CTR_2)\n\t\terror = pit_readback1(vatpit, 2, cmd);\n\n\treturn (error);\n}\n\n\nstatic int\nvatpit_update_mode(struct vatpit *vatpit, uint8_t val)\n{\n\tstruct channel *c;\n\tint sel, rw, mode;\n\n\tsel = val & TIMER_SEL_MASK;\n\trw = val & TIMER_RW_MASK;\n\tmode = val & TIMER_MODE_MASK;\n\n\tif (sel == TIMER_SEL_READBACK)\n\t\treturn (pit_readback(vatpit, val));\n\n\tif (rw != TIMER_LATCH && rw != TIMER_16BIT)\n\t\treturn (-1);\n\n\tif (rw != TIMER_LATCH) {\n\t\t/*\n\t\t * Counter mode is not affected when issuing a\n\t\t * latch command.\n\t\t */\n\t\tif (mode != TIMER_INTTC &&\n\t\t    mode != TIMER_RATEGEN &&\n\t\t    mode != TIMER_SQWAVE &&\n\t\t    mode != TIMER_SWSTROBE)\n\t\t\treturn (-1);\n\t}\n\n\tc = &vatpit->channel[sel >> 6];\n\tif (rw == TIMER_LATCH)\n\t\tpit_update_counter(vatpit, c, true);\n\telse {\n\t\tc->mode = mode;\n\t\tc->olbyte = 0;\t/* reset latch after reprogramming */\n\t\tc->status |= TIMER_STS_NULLCNT;\n\t}\n\n\treturn (0);\n}\n\nint\nvatpit_handler(struct vm *vm, UNUSED int vcpuid, bool in, int port, int bytes,\n    uint32_t *eax)\n{\n\tstruct vatpit *vatpit;\n\tstruct channel *c;\n\tuint8_t val;\n\tint error;\n\n\tvatpit = vm_atpit(vm);\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tval = (uint8_t) *eax;\n\n\tif (port == TIMER_MODE) {\n\t\tif (in) {\n\t\t\tVM_CTR0(vatpit->vm, \"vatpit attempt to read mode\");\n\t\t\treturn (-1);\n\t\t}\n\n\t\tVATPIT_LOCK(vatpit);\n\t\terror = vatpit_update_mode(vatpit, val);\n\t\tVATPIT_UNLOCK(vatpit);\n\n\t\treturn (error);\n\t}\n\n\t/* counter ports */\n\tKASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,\n\t    (\"invalid port 0x%x\\n\", port));\n\tc = &vatpit->channel[port - TIMER_CNTR0];\n\n\tVATPIT_LOCK(vatpit);\n\tif (in && c->slatched) {\n\t\t/*\n\t\t * Return the status byte if latched\n\t\t */\n\t\t*eax = c->status;\n\t\tc->slatched = false;\n\t\tc->status = 0;\n\t} else if (in) {\n\t\t/*\n\t\t * The spec says that once the output latch is completely\n\t\t * read it should revert to \"following\" the counter. Use\n\t\t * the free running counter for this case (i.e. Linux\n\t\t * TSC calibration). Assuming the access mode is 16-bit,\n\t\t * toggle the MSB/LSB bit on each read.\n\t\t */\n\t\tif (c->olbyte == 0) {\n\t\t\tuint16_t tmp;\n\n\t\t\ttmp = pit_update_counter(vatpit, c, false);\n\t\t\tif (c->frbyte)\n\t\t\t\ttmp >>= 8;\n\t\t\ttmp &= 0xff;\n\t\t\t*eax = tmp;\n\t\t\tc->frbyte ^= 1;\n\t\t}  else\n\t\t\t*eax = c->ol[--c->olbyte];\n\t} else {\n\t\tc->cr[c->crbyte++] = (uint8_t) *eax;\n\t\tif (c->crbyte == 2) {\n\t\t\tc->status &= ~TIMER_STS_NULLCNT;\n\t\t\tc->frbyte = 0;\n\t\t\tc->crbyte = 0;\n\t\t\tc->initial = (uint16_t) c->cr[0];\n\t\t\tc->initial |= (((uint16_t) c->cr[1]) << 8);\n\t\t\tc->now_sbt = sbinuptime();\n\t\t\t/* Start an interval timer for channel 0 */\n\t\t\tif (port == TIMER_CNTR0) {\n\t\t\t\tc->callout_sbt = c->now_sbt;\n\t\t\t\tpit_timer_start_cntr0(vatpit);\n\t\t\t}\n\t\t\tif (c->initial == 0)\n\t\t\t\tc->initial = 0xffff;\n\t\t}\n\t}\n\tVATPIT_UNLOCK(vatpit);\n\n\treturn (0);\n}\n\nint\nvatpit_nmisc_handler(struct vm *vm, UNUSED int vcpuid, bool in, UNUSED int port,\n\tUNUSED int bytes, uint32_t *eax)\n{\n\tstruct vatpit *vatpit;\n\n\tvatpit = vm_atpit(vm);\n\n\tif (in) {\n\t\t\tVATPIT_LOCK(vatpit);\n\t\t\tif (vatpit_get_out(vatpit, 2))\n\t\t\t\t*eax = TMR2_OUT_STS;\n\t\t\telse\n\t\t\t\t*eax = 0;\n\n\t\t\tVATPIT_UNLOCK(vatpit);\n\t}\n\n\treturn (0);\n}\n\nstruct vatpit *\nvatpit_init(struct vm *vm)\n{\n\tstruct vatpit *vatpit;\n\tstruct bintime bt;\n\tstruct vatpit_callout_arg *arg;\n\tint i;\n\n\tvatpit = malloc(sizeof(struct vatpit));\n\tassert(vatpit);\n\tbzero(vatpit, sizeof(struct vatpit));\n\tvatpit->vm = vm;\n\n\tVATPIT_LOCK_INIT(vatpit)\n\n\tFREQ2BT(PIT_8254_FREQ, &bt);\n\tvatpit->freq_sbt = bttosbt(bt);\n\n\tfor (i = 0; i < 3; i++) {\n\t\tcallout_init(&vatpit->channel[i].callout, 1);\n\t\targ = &vatpit->channel[i].callout_arg;\n\t\targ->vatpit = vatpit;\n\t\targ->channel_num = i;\n\t}\n\n\treturn (vatpit);\n}\n\nvoid\nvatpit_cleanup(struct vatpit *vatpit)\n{\n\tint i;\n\n\tfor (i = 0; i < 3; i++)\n\t\tcallout_drain(&vatpit->channel[i].callout);\n\n\tfree(vatpit);\n}\n"
  },
  {
    "path": "src/vmm/io/vhpet.c",
    "content": "/*-\n * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <pthread.h>\n#include <assert.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/acpi_hpet.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vhpet.h>\n#include <xhyve/vmm/io/vioapic.h>\n\n#define\tHPET_FREQ\t10000000\t\t/* 10.0 Mhz */\n#define\tFS_PER_S\t1000000000000000ul\n\n/* Timer N Configuration and Capabilities Register */\n#define\tHPET_TCAP_RO_MASK\t(HPET_TCAP_INT_ROUTE \t|\t\t\\\n\t\t\t\t HPET_TCAP_FSB_INT_DEL\t|\t\t\\\n\t\t\t\t HPET_TCAP_SIZE\t\t|\t\t\\\n\t\t\t\t HPET_TCAP_PER_INT)\n/*\n * HPET requires at least 3 timers and up to 32 timers per block.\n */\n#define\tVHPET_NUM_TIMERS\t8\nCTASSERT(VHPET_NUM_TIMERS >= 3 && VHPET_NUM_TIMERS <= 32);\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vhpet_callout_arg {\n\tstruct vhpet *vhpet;\n\tint timer_num;\n};\n\nstruct vhpet {\n\tstruct vm *vm;\n\tpthread_mutex_t mtx;\n\tsbintime_t freq_sbt;\n\tuint64_t config; /* Configuration */\n\tuint64_t isr; /* Interrupt Status */\n\tuint32_t countbase; /* HPET counter base value */\n\tsbintime_t countbase_sbt; /* uptime corresponding to base value */\n\tstruct {\n\t\tuint64_t cap_config; /* Configuration */\n\t\tuint64_t msireg; /* FSB interrupt routing */\n\t\tuint32_t compval; /* Comparator */\n\t\tuint32_t comprate;\n\t\tstruct callout callout;\n\t\tsbintime_t callout_sbt; /* time when counter==compval */\n\t\tstruct vhpet_callout_arg arg;\n\t} timer[VHPET_NUM_TIMERS];\n};\n#pragma clang diagnostic pop\n\n#define\tVHPET_LOCK(vhp) pthread_mutex_lock(&((vhp)->mtx))\n#define\tVHPET_UNLOCK(vhp) pthread_mutex_unlock(&((vhp)->mtx))\n\nstatic void vhpet_start_timer(struct vhpet *vhpet, int n, uint32_t counter,\n    sbintime_t now);\n\nstatic uint64_t\nvhpet_capabilities(void)\n{\n\tuint64_t cap = 0;\n\n\tcap |= ((uint64_t) 0x8086) << 16; /* vendor id */\n\tcap |= ((uint64_t) (VHPET_NUM_TIMERS - 1)) << 8; /* number of timers */\n\tcap |= (uint64_t) 1; /* revision */\n\tcap &= ~((uint64_t) HPET_CAP_COUNT_SIZE); /* 32-bit timer */\n\tcap &= (uint64_t) 0xffffffff;\n\tcap |= ((uint64_t) (FS_PER_S / HPET_FREQ)) << 32; /* tick period in fs */\n\n\treturn (cap);\n}\n\nstatic __inline bool\nvhpet_counter_enabled(struct vhpet *vhpet)\n{\n\n\treturn ((vhpet->config & HPET_CNF_ENABLE) ? true : false);\n}\n\nstatic __inline bool\nvhpet_timer_msi_enabled(struct vhpet *vhpet, int n)\n{\n\tconst uint64_t msi_enable = HPET_TCAP_FSB_INT_DEL | HPET_TCNF_FSB_EN;\n\n\tif ((vhpet->timer[n].cap_config & msi_enable) == msi_enable)\n\t\treturn (true);\n\telse\n\t\treturn (false);\n}\n\nstatic __inline int\nvhpet_timer_ioapic_pin(struct vhpet *vhpet, int n)\n{\n\t/*\n\t * If the timer is configured to use MSI then treat it as if the\n\t * timer is not connected to the ioapic.\n\t */\n\tif (vhpet_timer_msi_enabled(vhpet, n))\n\t\treturn (0);\n\n\treturn ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ROUTE) >> 9);\n}\n\nstatic uint32_t\nvhpet_counter(struct vhpet *vhpet, sbintime_t *nowptr)\n{\n\tuint32_t val;\n\tsbintime_t now, delta;\n\n\tval = vhpet->countbase;\n\tif (vhpet_counter_enabled(vhpet)) {\n\t\tnow = sbinuptime();\n\t\tdelta = now - vhpet->countbase_sbt;\n\t\tKASSERT(delta >= 0, (\"vhpet_counter: uptime went backwards: \"\n\t\t    \"%#llx to %#llx\", vhpet->countbase_sbt, now));\n\t\tval += delta / vhpet->freq_sbt;\n\t\tif (nowptr != NULL)\n\t\t\t*nowptr = now;\n\t} else {\n\t\t/*\n\t\t * The sbinuptime corresponding to the 'countbase' is\n\t\t * meaningless when the counter is disabled. Make sure\n\t\t * that the the caller doesn't want to use it.\n\t\t */\n\t\tKASSERT(nowptr == NULL, (\"vhpet_counter: nowptr must be NULL\"));\n\t}\n\treturn (val);\n}\n\nstatic void\nvhpet_timer_clear_isr(struct vhpet *vhpet, int n)\n{\n\tint pin;\n\n\tif (vhpet->isr & (1 << n)) {\n\t\tpin = vhpet_timer_ioapic_pin(vhpet, n);\n\t\tKASSERT(pin != 0, (\"vhpet timer %d irq incorrectly routed\", n));\n\t\tvioapic_deassert_irq(vhpet->vm, pin);\n\t\tvhpet->isr &= ~(1 << n);\n\t}\n}\n\nstatic __inline bool\nvhpet_periodic_timer(struct vhpet *vhpet, int n)\n{\n\n\treturn ((vhpet->timer[n].cap_config & HPET_TCNF_TYPE) != 0);\n}\n\nstatic __inline bool\nvhpet_timer_interrupt_enabled(struct vhpet *vhpet, int n)\n{\n\n\treturn ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ENB) != 0);\n}\n\nstatic __inline bool\nvhpet_timer_edge_trig(struct vhpet *vhpet, int n)\n{\n\n\tKASSERT(!vhpet_timer_msi_enabled(vhpet, n), (\"vhpet_timer_edge_trig: \"\n\t    \"timer %d is using MSI\", n));\n\n\tif ((vhpet->timer[n].cap_config & HPET_TCNF_INT_TYPE) == 0)\n\t\treturn (true);\n\telse\n\t\treturn (false);\n}\n\nstatic void\nvhpet_timer_interrupt(struct vhpet *vhpet, int n)\n{\n\tint pin;\n\n\t/* If interrupts are not enabled for this timer then just return. */\n\tif (!vhpet_timer_interrupt_enabled(vhpet, n))\n\t\treturn;\n\n\t/*\n\t * If a level triggered interrupt is already asserted then just return.\n\t */\n\tif ((vhpet->isr & (1 << n)) != 0) {\n\t\tVM_CTR1(vhpet->vm, \"hpet t%d intr is already asserted\", n);\n\t\treturn;\n\t}\n\n\tif (vhpet_timer_msi_enabled(vhpet, n)) {\n\t\tlapic_intr_msi(vhpet->vm, vhpet->timer[n].msireg >> 32,\n\t\t    vhpet->timer[n].msireg & 0xffffffff);\n\t\treturn;\n\t}\n\n\tpin = vhpet_timer_ioapic_pin(vhpet, n);\n\tif (pin == 0) {\n\t\tVM_CTR1(vhpet->vm, \"hpet t%d intr is not routed to ioapic\", n);\n\t\treturn;\n\t}\n\n\tif (vhpet_timer_edge_trig(vhpet, n)) {\n\t\tvioapic_pulse_irq(vhpet->vm, pin);\n\t} else {\n\t\tvhpet->isr |= 1 << n;\n\t\tvioapic_assert_irq(vhpet->vm, pin);\n\t}\n}\n\nstatic void\nvhpet_adjust_compval(struct vhpet *vhpet, int n, uint32_t counter)\n{\n\tuint32_t compval, comprate, compnext;\n\n\tKASSERT(vhpet->timer[n].comprate != 0, (\"hpet t%d is not periodic\", n));\n\n\tcompval = vhpet->timer[n].compval;\n\tcomprate = vhpet->timer[n].comprate;\n\n\t/*\n\t * Calculate the comparator value to be used for the next periodic\n\t * interrupt.\n\t *\n\t * This function is commonly called from the callout handler.\n\t * In this scenario the 'counter' is ahead of 'compval'. To find\n\t * the next value to program into the accumulator we divide the\n\t * number space between 'compval' and 'counter' into 'comprate'\n\t * sized units. The 'compval' is rounded up such that is \"ahead\"\n\t * of 'counter'.\n\t */\n\tcompnext = compval + ((counter - compval) / comprate + 1) * comprate;\n\n\tvhpet->timer[n].compval = compnext;\n}\n\nstatic void\nvhpet_handler(void *a)\n{\n\tint n;\n\tuint32_t counter;\n\tsbintime_t now;\n\tstruct vhpet *vhpet;\n\tstruct callout *callout;\n\tstruct vhpet_callout_arg *arg;\n\n\targ = a;\n\tvhpet = arg->vhpet;\n\tn = arg->timer_num;\n\tcallout = &vhpet->timer[n].callout;\n\n\tVM_CTR1(vhpet->vm, \"hpet t%d fired\", n);\n\n\tVHPET_LOCK(vhpet);\n\n\tif (callout_pending(callout))\t\t/* callout was reset */\n\t\tgoto done;\n\n\tif (!callout_active(callout))\t\t/* callout was stopped */\n\t\tgoto done;\n\n\tcallout_deactivate(callout);\n\n\tif (!vhpet_counter_enabled(vhpet))\n\t\txhyve_abort(\"vhpet(%p) callout with counter disabled\\n\", (void*)vhpet);\n\n\tcounter = vhpet_counter(vhpet, &now);\n\tvhpet_start_timer(vhpet, n, counter, now);\n\tvhpet_timer_interrupt(vhpet, n);\ndone:\n\tVHPET_UNLOCK(vhpet);\n\treturn;\n}\n\nstatic void\nvhpet_stop_timer(struct vhpet *vhpet, int n, sbintime_t now)\n{\n\n\tVM_CTR1(vhpet->vm, \"hpet t%d stopped\", n);\n\tcallout_stop(&vhpet->timer[n].callout);\n\n\t/*\n\t * If the callout was scheduled to expire in the past but hasn't\n\t * had a chance to execute yet then trigger the timer interrupt\n\t * here. Failing to do so will result in a missed timer interrupt\n\t * in the guest. This is especially bad in one-shot mode because\n\t * the next interrupt has to wait for the counter to wrap around.\n\t */\n\tif (vhpet->timer[n].callout_sbt < now) {\n\t\tVM_CTR1(vhpet->vm, \"hpet t%d interrupt triggered after \"\n\t\t    \"stopping timer\", n);\n\t\tvhpet_timer_interrupt(vhpet, n);\n\t}\n}\n\nstatic void\nvhpet_start_timer(struct vhpet *vhpet, int n, uint32_t counter, sbintime_t now)\n{\n\tsbintime_t delta, precision;\n\n\tif (vhpet->timer[n].comprate != 0)\n\t\tvhpet_adjust_compval(vhpet, n, counter);\n\telse {\n\t\t/*\n\t\t * In one-shot mode it is the guest's responsibility to make\n\t\t * sure that the comparator value is not in the \"past\". The\n\t\t * hardware doesn't have any belt-and-suspenders to deal with\n\t\t * this so we don't either.\n\t\t */\n\t}\n\n\tdelta = (vhpet->timer[n].compval - counter) * vhpet->freq_sbt;\n\tprecision = delta >> tc_precexp;\n\tvhpet->timer[n].callout_sbt = now + delta;\n\tcallout_reset_sbt(&vhpet->timer[n].callout, vhpet->timer[n].callout_sbt,\n\t    precision, vhpet_handler, &vhpet->timer[n].arg, C_ABSOLUTE);\n}\n\nstatic void\nvhpet_start_counting(struct vhpet *vhpet)\n{\n\tint i;\n\n\tvhpet->countbase_sbt = sbinuptime();\n\tfor (i = 0; i < VHPET_NUM_TIMERS; i++) {\n\t\t/*\n\t\t * Restart the timers based on the value of the main counter\n\t\t * when it stopped counting.\n\t\t */\n\t\tvhpet_start_timer(vhpet, i, vhpet->countbase,\n\t\t    vhpet->countbase_sbt);\n\t}\n}\n\nstatic void\nvhpet_stop_counting(struct vhpet *vhpet, uint32_t counter, sbintime_t now)\n{\n\tint i;\n\n\tvhpet->countbase = counter;\n\tfor (i = 0; i < VHPET_NUM_TIMERS; i++)\n\t\tvhpet_stop_timer(vhpet, i, now);\n}\n\nstatic __inline void\nupdate_register(uint64_t *regptr, uint64_t data, uint64_t mask)\n{\n\n\t*regptr &= ~mask;\n\t*regptr |= (data & mask);\n}\n\nstatic void\nvhpet_timer_update_config(struct vhpet *vhpet, int n, uint64_t data,\n    uint64_t mask)\n{\n\tbool clear_isr;\n\tint old_pin, new_pin;\n\tuint32_t allowed_irqs;\n\tuint64_t oldval, newval;\n\n\tif (vhpet_timer_msi_enabled(vhpet, n) ||\n\t    vhpet_timer_edge_trig(vhpet, n)) {\n\t\tif (vhpet->isr & (1 << n))\n\t\t\txhyve_abort(\"vhpet timer %d isr should not be asserted\\n\", n);\n\t}\n\told_pin = vhpet_timer_ioapic_pin(vhpet, n);\n\toldval = vhpet->timer[n].cap_config;\n\n\tnewval = oldval;\n\tupdate_register(&newval, data, mask);\n\tnewval &= ~(HPET_TCAP_RO_MASK | HPET_TCNF_32MODE);\n\tnewval |= oldval & HPET_TCAP_RO_MASK;\n\n\tif (newval == oldval)\n\t\treturn;\n\n\tvhpet->timer[n].cap_config = newval;\n\tVM_CTR2(vhpet->vm, \"hpet t%d cap_config set to 0x%016llx\", n, newval);\n\n\t/*\n\t * Validate the interrupt routing in the HPET_TCNF_INT_ROUTE field.\n\t * If it does not match the bits set in HPET_TCAP_INT_ROUTE then set\n\t * it to the default value of 0.\n\t */\n\tallowed_irqs = vhpet->timer[n].cap_config >> 32;\n\tnew_pin = vhpet_timer_ioapic_pin(vhpet, n);\n\tif (new_pin != 0 && (allowed_irqs & (1 << new_pin)) == 0) {\n\t\tVM_CTR3(vhpet->vm, \"hpet t%d configured invalid irq %d, \"\n\t\t    \"allowed_irqs 0x%08x\", n, new_pin, allowed_irqs);\n\t\tnew_pin = 0;\n\t\tvhpet->timer[n].cap_config &= ~((uint64_t) HPET_TCNF_INT_ROUTE);\n\t}\n\n\tif (!vhpet_periodic_timer(vhpet, n))\n\t\tvhpet->timer[n].comprate = 0;\n\n\t/*\n\t * If the timer's ISR bit is set then clear it in the following cases:\n\t * - interrupt is disabled\n\t * - interrupt type is changed from level to edge or fsb.\n\t * - interrupt routing is changed\n\t *\n\t * This is to ensure that this timer's level triggered interrupt does\n\t * not remain asserted forever.\n\t */\n\tif (vhpet->isr & (1 << n)) {\n\t\tKASSERT(old_pin != 0, (\"timer %d isr asserted to ioapic pin %d\",\n\t\t    n, old_pin));\n\t\tif (!vhpet_timer_interrupt_enabled(vhpet, n))\n\t\t\tclear_isr = true;\n\t\telse if (vhpet_timer_msi_enabled(vhpet, n))\n\t\t\tclear_isr = true;\n\t\telse if (vhpet_timer_edge_trig(vhpet, n))\n\t\t\tclear_isr = true;\n\t\telse if (vhpet_timer_ioapic_pin(vhpet, n) != old_pin)\n\t\t\tclear_isr = true;\n\t\telse\n\t\t\tclear_isr = false;\n\n\t\tif (clear_isr) {\n\t\t\tVM_CTR1(vhpet->vm, \"hpet t%d isr cleared due to \"\n\t\t\t    \"configuration change\", n);\n\t\t\tvioapic_deassert_irq(vhpet->vm, old_pin);\n\t\t\tvhpet->isr &= ~(1 << n);\n\t\t}\n\t}\n}\n\nint\nvhpet_mmio_write(void *vm, UNUSED int vcpuid, uint64_t gpa, uint64_t val, int size,\n    UNUSED void *arg)\n{\n\tstruct vhpet *vhpet;\n\tuint64_t data, mask, oldval, val64;\n\tuint32_t isr_clear_mask, old_compval, old_comprate, counter;\n\tsbintime_t now, *nowptr;\n\tint i, offset;\n\n\tnow = 0;\n\tvhpet = vm_hpet(vm);\n\toffset = (int) (gpa - VHPET_BASE);\n\n\tVHPET_LOCK(vhpet);\n\n\t/* Accesses to the HPET should be 4 or 8 bytes wide */\n\tswitch (size) {\n\tcase 8:\n\t\tmask = 0xffffffffffffffff;\n\t\tdata = val;\n\t\tbreak;\n\tcase 4:\n\t\tmask = 0xffffffff;\n\t\tdata = val;\n\t\tif ((offset & 0x4) != 0) {\n\t\t\tmask <<= 32;\n\t\t\tdata <<= 32;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tVM_CTR2(vhpet->vm, \"hpet invalid mmio write: \"\n\t\t    \"offset 0x%08x, size %d\", offset, size);\n\t\tgoto done;\n\t}\n\n\t/* Access to the HPET should be naturally aligned to its width */\n\tif (offset & (size - 1)) {\n\t\tVM_CTR2(vhpet->vm, \"hpet invalid mmio write: \"\n\t\t    \"offset 0x%08x, size %d\", offset, size);\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_CONFIG || offset == HPET_CONFIG + 4) {\n\t\t/*\n\t\t * Get the most recent value of the counter before updating\n\t\t * the 'config' register. If the HPET is going to be disabled\n\t\t * then we need to update 'countbase' with the value right\n\t\t * before it is disabled.\n\t\t */\n\t\tnowptr = vhpet_counter_enabled(vhpet) ? &now : NULL;\n\t\tcounter = vhpet_counter(vhpet, nowptr);\n\t\toldval = vhpet->config;\n\t\tupdate_register(&vhpet->config, data, mask);\n\n\t\t/*\n\t\t * LegacyReplacement Routing is not supported so clear the\n\t\t * bit explicitly.\n\t\t */\n\t\tvhpet->config &= ~((uint64_t) HPET_CNF_LEG_RT);\n\n\t\tif ((oldval ^ vhpet->config) & HPET_CNF_ENABLE) {\n\t\t\tif (vhpet_counter_enabled(vhpet)) {\n\t\t\t\tvhpet_start_counting(vhpet);\n\t\t\t\tVM_CTR0(vhpet->vm, \"hpet enabled\");\n\t\t\t} else {\n\t\t\t\tvhpet_stop_counting(vhpet, counter, now);\n\t\t\t\tVM_CTR0(vhpet->vm, \"hpet disabled\");\n\t\t\t}\n\t\t}\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_ISR || offset == HPET_ISR + 4) {\n\t\tisr_clear_mask = (uint32_t) (vhpet->isr & data);\n\t\tfor (i = 0; i < VHPET_NUM_TIMERS; i++) {\n\t\t\tif ((isr_clear_mask & (1 << i)) != 0) {\n\t\t\t\tVM_CTR1(vhpet->vm, \"hpet t%d isr cleared\", i);\n\t\t\t\tvhpet_timer_clear_isr(vhpet, i);\n\t\t\t}\n\t\t}\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_MAIN_COUNTER || offset == HPET_MAIN_COUNTER + 4) {\n\t\t/* Zero-extend the counter to 64-bits before updating it */\n\t\tval64 = vhpet_counter(vhpet, NULL);\n\t\tupdate_register(&val64, data, mask);\n\t\tvhpet->countbase = (uint32_t) val64;\n\t\tif (vhpet_counter_enabled(vhpet))\n\t\t\tvhpet_start_counting(vhpet);\n\t\tgoto done;\n\t}\n\n\tfor (i = 0; i < VHPET_NUM_TIMERS; i++) {\n\t\tif (offset == HPET_TIMER_CAP_CNF(i) ||\n\t\t    offset == HPET_TIMER_CAP_CNF(i) + 4) {\n\t\t\tvhpet_timer_update_config(vhpet, i, data, mask);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (offset == HPET_TIMER_COMPARATOR(i) ||\n\t\t    offset == HPET_TIMER_COMPARATOR(i) + 4) {\n\t\t\told_compval = vhpet->timer[i].compval;\n\t\t\told_comprate = vhpet->timer[i].comprate;\n\t\t\tif (vhpet_periodic_timer(vhpet, i)) {\n\t\t\t\t/*\n\t\t\t\t * In periodic mode writes to the comparator\n\t\t\t\t * change the 'compval' register only if the\n\t\t\t\t * HPET_TCNF_VAL_SET bit is set in the config\n\t\t\t\t * register.\n\t\t\t\t */\n\t\t\t\tval64 = vhpet->timer[i].comprate;\n\t\t\t\tupdate_register(&val64, data, mask);\n\t\t\t\tvhpet->timer[i].comprate = (uint32_t) val64;\n\t\t\t\tif ((vhpet->timer[i].cap_config &\n\t\t\t\t    HPET_TCNF_VAL_SET) != 0) {\n\t\t\t\t\tvhpet->timer[i].compval = (uint32_t) val64;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tKASSERT(vhpet->timer[i].comprate == 0,\n\t\t\t\t    (\"vhpet one-shot timer %d has invalid \"\n\t\t\t\t    \"rate %u\", i, vhpet->timer[i].comprate));\n\t\t\t\tval64 = vhpet->timer[i].compval;\n\t\t\t\tupdate_register(&val64, data, mask);\n\t\t\t\tvhpet->timer[i].compval = (uint32_t) val64;\n\t\t\t}\n\t\t\tvhpet->timer[i].cap_config &= ~((uint64_t) HPET_TCNF_VAL_SET);\n\n\t\t\tif (vhpet->timer[i].compval != old_compval ||\n\t\t\t    vhpet->timer[i].comprate != old_comprate) {\n\t\t\t\tif (vhpet_counter_enabled(vhpet)) {\n\t\t\t\t\tcounter = vhpet_counter(vhpet, &now);\n\t\t\t\t\tvhpet_start_timer(vhpet, i, counter,\n\t\t\t\t\t    now);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tif (offset == HPET_TIMER_FSB_VAL(i) ||\n\t\t    offset == HPET_TIMER_FSB_ADDR(i)) {\n\t\t\tupdate_register(&vhpet->timer[i].msireg, data, mask);\n\t\t\tbreak;\n\t\t}\n\t}\ndone:\n\tVHPET_UNLOCK(vhpet);\n\treturn (0);\n}\n\nint\nvhpet_mmio_read(void *vm, UNUSED int vcpuid, uint64_t gpa, uint64_t *rval, int size,\n    UNUSED void *arg)\n{\n\tint i, offset;\n\tstruct vhpet *vhpet;\n\tuint64_t data;\n\n\tdata = 0;\n\tvhpet = vm_hpet(vm);\n\toffset = (int) (gpa - VHPET_BASE);\n\n\tVHPET_LOCK(vhpet);\n\n\t/* Accesses to the HPET should be 4 or 8 bytes wide */\n\tif (size != 4 && size != 8) {\n\t\tVM_CTR2(vhpet->vm, \"hpet invalid mmio read: \"\n\t\t    \"offset 0x%08x, size %d\", offset, size);\n\t\tdata = 0;\n\t\tgoto done;\n\t}\n\n\t/* Access to the HPET should be naturally aligned to its width */\n\tif (offset & (size - 1)) {\n\t\tVM_CTR2(vhpet->vm, \"hpet invalid mmio read: \"\n\t\t    \"offset 0x%08x, size %d\", offset, size);\n\t\tdata = 0;\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_CAPABILITIES || offset == HPET_CAPABILITIES + 4) {\n\t\tdata = vhpet_capabilities();\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_CONFIG || offset == HPET_CONFIG + 4) {\n\t\tdata = vhpet->config;\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_ISR || offset == HPET_ISR + 4) {\n\t\tdata = vhpet->isr;\n\t\tgoto done;\n\t}\n\n\tif (offset == HPET_MAIN_COUNTER || offset == HPET_MAIN_COUNTER + 4) {\n\t\tdata = vhpet_counter(vhpet, NULL);\n\t\tgoto done;\n\t}\n\n\tfor (i = 0; i < VHPET_NUM_TIMERS; i++) {\n\t\tif (offset == HPET_TIMER_CAP_CNF(i) ||\n\t\t    offset == HPET_TIMER_CAP_CNF(i) + 4) {\n\t\t\tdata = vhpet->timer[i].cap_config;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (offset == HPET_TIMER_COMPARATOR(i) ||\n\t\t    offset == HPET_TIMER_COMPARATOR(i) + 4) {\n\t\t\tdata = vhpet->timer[i].compval;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (offset == HPET_TIMER_FSB_VAL(i) ||\n\t\t    offset == HPET_TIMER_FSB_ADDR(i)) {\n\t\t\tdata = vhpet->timer[i].msireg;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (i >= VHPET_NUM_TIMERS)\n\t\tdata = 0;\ndone:\n\tVHPET_UNLOCK(vhpet);\n\n\tif (size == 4) {\n\t\tif (offset & 0x4)\n\t\t\tdata >>= 32;\n\t}\n\t*rval = data;\n\treturn (0);\n}\n\nstruct vhpet *\nvhpet_init(struct vm *vm)\n{\n\tint i, pincount;\n\tstruct vhpet *vhpet;\n\tuint64_t allowed_irqs;\n\tstruct vhpet_callout_arg *arg;\n\tstruct bintime bt;\n\n\tvhpet = malloc(sizeof(struct vhpet));\n\tassert(vhpet);\n\tbzero(vhpet, sizeof(struct vhpet));\n\tvhpet->vm = vm;\n\n\tpthread_mutex_init(&vhpet->mtx, NULL);\n\n\tFREQ2BT(HPET_FREQ, &bt);\n\tvhpet->freq_sbt = bttosbt(bt);\n\n\tpincount = vioapic_pincount(vm);\n\tif (pincount >= 24)\n\t\tallowed_irqs = 0x00f00000;\t/* irqs 20, 21, 22 and 23 */\n\telse\n\t\tallowed_irqs = 0;\n\n\t/*\n\t * Initialize HPET timer hardware state.\n\t */\n\tfor (i = 0; i < VHPET_NUM_TIMERS; i++) {\n\t\tvhpet->timer[i].cap_config = allowed_irqs << 32;\n\t\tvhpet->timer[i].cap_config |= HPET_TCAP_PER_INT;\n\t\tvhpet->timer[i].cap_config |= HPET_TCAP_FSB_INT_DEL;\n\n\t\tvhpet->timer[i].compval = 0xffffffff;\n\t\tcallout_init(&vhpet->timer[i].callout, 1);\n\n\t\targ = &vhpet->timer[i].arg;\n\t\targ->vhpet = vhpet;\n\t\targ->timer_num = i;\n\t}\n\n\treturn (vhpet);\n}\n\nvoid\nvhpet_cleanup(struct vhpet *vhpet)\n{\n\tint i;\n\n\tfor (i = 0; i < VHPET_NUM_TIMERS; i++)\n\t\tcallout_drain(&vhpet->timer[i].callout);\n\n\tfree(vhpet);\n}\n\nint\nvhpet_getcap(uint32_t *cap)\n{\n\t*cap = (uint32_t) vhpet_capabilities();\n\treturn (0);\n}\n"
  },
  {
    "path": "src/vmm/io/vioapic.c",
    "content": "/*-\n * Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2013 Neel Natu <neel@freebsd.org>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <errno.h>\n#include <assert.h>\n#include <xhyve/lock.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/apicreg.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vioapic.h>\n#include <xhyve/vmm/io/vlapic.h>\n\n#define\tIOREGSEL\t0x00\n#define\tIOWIN\t\t0x10\n\n#define\tREDIR_ENTRIES\t24\n#define\tRTBL_RO_BITS\t((uint64_t)(IOART_REM_IRR | IOART_DELIVS))\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vioapic {\n\tstruct vm *vm;\n\txhyve_lock_t lock;\n\tuint32_t id;\n\tuint32_t ioregsel;\n\tstruct {\n\t\tuint64_t reg;\n\t\tint acnt; /* sum of pin asserts (+1) and deasserts (-1) */\n\t} rtbl[REDIR_ENTRIES];\n};\n#pragma clang diagnostic pop\n\n#define VIOAPIC_LOCK_INIT(v) XHYVE_LOCK_INIT(v, lock)\n#define VIOAPIC_LOCK(v) XHYVE_LOCK(v, lock)\n#define VIOAPIC_UNLOCK(v) XHYVE_UNLOCK(v, lock)\n\n#define\tVIOAPIC_CTR1(vioapic, fmt, a1) \\\n\tVM_CTR1((vioapic)->vm, fmt, a1)\n\n#define\tVIOAPIC_CTR2(vioapic, fmt, a1, a2) \\\n\tVM_CTR2((vioapic)->vm, fmt, a1, a2)\n\n#ifdef XHYVE_CONFIG_TRACE\n#define\tVIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \\\n\tVM_CTR3((vioapic)->vm, fmt, a1, a2, a3)\n#endif\n\n#ifdef XHYVE_CONFIG_TRACE\nstatic const char *\npinstate_str(bool asserted)\n{\n\n\tif (asserted)\n\t\treturn (\"asserted\");\n\telse\n\t\treturn (\"deasserted\");\n}\n#endif\n\nstatic void\nvioapic_send_intr(struct vioapic *vioapic, int pin)\n{\n\tint vector, delmode;\n\tuint32_t low, high, dest;\n\tbool level, phys;\n\n\tKASSERT(pin >= 0 && pin < REDIR_ENTRIES,\n\t    (\"vioapic_set_pinstate: invalid pin number %d\", pin));\n\n\tlow = (uint32_t) vioapic->rtbl[pin].reg;\n\thigh = (uint32_t) (vioapic->rtbl[pin].reg >> 32);\n\n\tif ((low & IOART_INTMASK) == IOART_INTMSET) {\n\t\tVIOAPIC_CTR1(vioapic, \"ioapic pin%d: masked\", pin);\n\t\treturn;\n\t}\n\n\tphys = ((low & IOART_DESTMOD) == IOART_DESTPHY);\n\tdelmode = low & IOART_DELMOD;\n\tlevel = low & IOART_TRGRLVL ? true : false;\n\tif (level)\n\t\tvioapic->rtbl[pin].reg |= IOART_REM_IRR;\n\n\tvector = low & IOART_INTVEC;\n\tdest = high >> APIC_ID_SHIFT;\n\tvlapic_deliver_intr(vioapic->vm, level, dest, phys, delmode, vector);\n}\n\nstatic void\nvioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)\n{\n\tint oldcnt, newcnt;\n\tbool needintr;\n\n\tKASSERT(pin >= 0 && pin < REDIR_ENTRIES,\n\t    (\"vioapic_set_pinstate: invalid pin number %d\", pin));\n\n\toldcnt = vioapic->rtbl[pin].acnt;\n\tif (newstate)\n\t\tvioapic->rtbl[pin].acnt++;\n\telse\n\t\tvioapic->rtbl[pin].acnt--;\n\tnewcnt = vioapic->rtbl[pin].acnt;\n\n\tif (newcnt < 0) {\n\t\tVIOAPIC_CTR2(vioapic, \"ioapic pin%d: bad acnt %d\",\n\t\t    pin, newcnt);\n\t}\n\n\tneedintr = false;\n\tif (oldcnt == 0 && newcnt == 1) {\n\t\tneedintr = true;\n\t\tVIOAPIC_CTR1(vioapic, \"ioapic pin%d: asserted\", pin);\n\t} else if (oldcnt == 1 && newcnt == 0) {\n\t\tVIOAPIC_CTR1(vioapic, \"ioapic pin%d: deasserted\", pin);\n\t} else {\n#ifdef XHYVE_CONFIG_TRACE\n\t\tVIOAPIC_CTR3(vioapic, \"ioapic pin%d: %s, ignored, acnt %d\",\n\t\t    pin, pinstate_str(newstate), newcnt);\n#endif\n\t}\n\tif (needintr)\n\t\tvioapic_send_intr(vioapic, pin);\n}\n\nenum irqstate {\n\tIRQSTATE_ASSERT,\n\tIRQSTATE_DEASSERT,\n\tIRQSTATE_PULSE\n};\n\nstatic int\nvioapic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)\n{\n\tstruct vioapic *vioapic;\n\n\tif (irq < 0 || irq >= REDIR_ENTRIES)\n\t\treturn (EINVAL);\n\n\tvioapic = vm_ioapic(vm);\n\n\tVIOAPIC_LOCK(vioapic);\n\tswitch (irqstate) {\n\tcase IRQSTATE_ASSERT:\n\t\tvioapic_set_pinstate(vioapic, irq, true);\n\t\tbreak;\n\tcase IRQSTATE_DEASSERT:\n\t\tvioapic_set_pinstate(vioapic, irq, false);\n\t\tbreak;\n\tcase IRQSTATE_PULSE:\n\t\tvioapic_set_pinstate(vioapic, irq, true);\n\t\tvioapic_set_pinstate(vioapic, irq, false);\n\t\tbreak;\n\t}\n\tVIOAPIC_UNLOCK(vioapic);\n\n\treturn (0);\n}\n\nint\nvioapic_assert_irq(struct vm *vm, int irq)\n{\n\n\treturn (vioapic_set_irqstate(vm, irq, IRQSTATE_ASSERT));\n}\n\nint\nvioapic_deassert_irq(struct vm *vm, int irq)\n{\n\n\treturn (vioapic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));\n}\n\nint\nvioapic_pulse_irq(struct vm *vm, int irq)\n{\n\n\treturn (vioapic_set_irqstate(vm, irq, IRQSTATE_PULSE));\n}\n\n/*\n * Reset the vlapic's trigger-mode register to reflect the ioapic pin\n * configuration.\n */\nstatic void\nvioapic_update_tmr(struct vm *vm, int vcpuid, UNUSED void *arg)\n{\n\tstruct vioapic *vioapic;\n\tstruct vlapic *vlapic;\n\tuint32_t low, high, dest;\n\tint delmode, pin, vector;\n\tbool level, phys;\n\n\tvlapic = vm_lapic(vm, vcpuid);\n\tvioapic = vm_ioapic(vm);\n\n\tVIOAPIC_LOCK(vioapic);\n\t/*\n\t * Reset all vectors to be edge-triggered.\n\t */\n\tvlapic_reset_tmr(vlapic);\n\tfor (pin = 0; pin < REDIR_ENTRIES; pin++) {\n\t\tlow = (uint32_t) vioapic->rtbl[pin].reg;\n\t\thigh = (uint32_t) (vioapic->rtbl[pin].reg >> 32);\n\n\t\tlevel = low & IOART_TRGRLVL ? true : false;\n\t\tif (!level)\n\t\t\tcontinue;\n\n\t\t/*\n\t\t * For a level-triggered 'pin' let the vlapic figure out if\n\t\t * an assertion on this 'pin' would result in an interrupt\n\t\t * being delivered to it. If yes, then it will modify the\n\t\t * TMR bit associated with this vector to level-triggered.\n\t\t */\n\t\tphys = ((low & IOART_DESTMOD) == IOART_DESTPHY);\n\t\tdelmode = low & IOART_DELMOD;\n\t\tvector = low & IOART_INTVEC;\n\t\tdest = high >> APIC_ID_SHIFT;\n\t\tvlapic_set_tmr_level(vlapic, dest, phys, delmode, vector);\n\t}\n\tVIOAPIC_UNLOCK(vioapic);\n}\n\nstatic uint32_t\nvioapic_read(struct vioapic *vioapic, UNUSED int vcpuid, uint32_t addr)\n{\n\tint regnum, pin, rshift;\n\n\tregnum = addr & 0xff;\n\tswitch (regnum) {\n\tcase IOAPIC_ID:\n\t\treturn (vioapic->id);\n\tcase IOAPIC_VER:\n\t\treturn (((REDIR_ENTRIES - 1) << MAXREDIRSHIFT) | 0x11);\n\tcase IOAPIC_ARB:\n\t\treturn (vioapic->id);\n\tdefault:\n\t\tbreak;\n\t}\n\n\t/* redirection table entries */\n\tif (regnum >= IOAPIC_REDTBL &&\n\t    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {\n\t\tpin = (regnum - IOAPIC_REDTBL) / 2;\n\t\tif ((regnum - IOAPIC_REDTBL) % 2)\n\t\t\trshift = 32;\n\t\telse\n\t\t\trshift = 0;\n\n\t\treturn ((uint32_t) (vioapic->rtbl[pin].reg >> rshift));\n\t}\n\n\treturn (0);\n}\n\nstatic void\nvioapic_write(struct vioapic *vioapic, int vcpuid, uint32_t addr, uint32_t data)\n{\n\tuint64_t data64, mask64;\n\tuint64_t last, changed;\n\tint regnum, pin, lshift;\n\tcpuset_t allvcpus;\n\n\tregnum = addr & 0xff;\n\tswitch (regnum) {\n\tcase IOAPIC_ID:\n\t\tvioapic->id = data & APIC_ID_MASK;\n\t\tbreak;\n\tcase IOAPIC_VER:\n\tcase IOAPIC_ARB:\n\t\t/* readonly */\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\t/* redirection table entries */\n\tif (regnum >= IOAPIC_REDTBL &&\n\t    regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {\n\t\tpin = (regnum - IOAPIC_REDTBL) / 2;\n\t\tif ((regnum - IOAPIC_REDTBL) % 2)\n\t\t\tlshift = 32;\n\t\telse\n\t\t\tlshift = 0;\n\n\t\tlast = vioapic->rtbl[pin].reg;\n\n\t\tdata64 = (uint64_t)data << lshift;\n\t\tmask64 = (uint64_t)0xffffffff << lshift;\n\t\tvioapic->rtbl[pin].reg &= ~mask64 | RTBL_RO_BITS;\n\t\tvioapic->rtbl[pin].reg |= data64 & ~RTBL_RO_BITS;\n\n\t\tVIOAPIC_CTR2(vioapic, \"ioapic pin%d: redir table entry %#llx\",\n\t\t    pin, vioapic->rtbl[pin].reg);\n\n\t\t/*\n\t\t * If any fields in the redirection table entry (except mask\n\t\t * or polarity) have changed then rendezvous all the vcpus\n\t\t * to update their vlapic trigger-mode registers.\n\t\t */\n\t\tchanged = last ^ vioapic->rtbl[pin].reg;\n\t\tif (changed & ~((uint64_t) (IOART_INTMASK | IOART_INTPOL))) {\n\t\t\tVIOAPIC_CTR1(vioapic, \"ioapic pin%d: recalculate \"\n\t\t\t    \"vlapic trigger-mode register\", pin);\n\t\t\tVIOAPIC_UNLOCK(vioapic);\n\t\t\tallvcpus = vm_active_cpus(vioapic->vm);\n\t\t\tvm_smp_rendezvous(vioapic->vm, vcpuid, allvcpus,\n\t\t\t    vioapic_update_tmr, NULL);\n\t\t\tVIOAPIC_LOCK(vioapic);\n\t\t}\n\n\t\t/*\n\t\t * Generate an interrupt if the following conditions are met:\n\t\t * - pin is not masked\n\t\t * - previous interrupt has been EOIed\n\t\t * - pin level is asserted\n\t\t */\n\t\tif ((vioapic->rtbl[pin].reg & IOART_INTMASK) == IOART_INTMCLR &&\n\t\t    (vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0 &&\n\t\t    (vioapic->rtbl[pin].acnt > 0)) {\n\t\t\tVIOAPIC_CTR2(vioapic, \"ioapic pin%d: asserted at rtbl \"\n\t\t\t    \"write, acnt %d\", pin, vioapic->rtbl[pin].acnt);\n\t\t\tvioapic_send_intr(vioapic, pin);\n\t\t}\n\t}\n}\n\nstatic int\nvioapic_mmio_rw(struct vioapic *vioapic, int vcpuid, uint64_t gpa,\n    uint64_t *data, int size, bool doread)\n{\n\tuint64_t offset;\n\n\toffset = gpa - VIOAPIC_BASE;\n\n\t/*\n\t * The IOAPIC specification allows 32-bit wide accesses to the\n\t * IOREGSEL (offset 0) and IOWIN (offset 16) registers.\n\t */\n\tif (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {\n\t\tif (doread)\n\t\t\t*data = 0;\n\t\treturn (0);\n\t}\n\n\tVIOAPIC_LOCK(vioapic);\n\tif (offset == IOREGSEL) {\n\t\tif (doread)\n\t\t\t*data = vioapic->ioregsel;\n\t\telse\n\t\t\tvioapic->ioregsel = (uint32_t) *data;\n\t} else {\n\t\tif (doread) {\n\t\t\t*data = vioapic_read(vioapic, vcpuid,\n\t\t\t    vioapic->ioregsel);\n\t\t} else {\n\t\t\tvioapic_write(vioapic, vcpuid, vioapic->ioregsel,\n\t\t\t\t((uint32_t) *data));\n\t\t}\n\t}\n\tVIOAPIC_UNLOCK(vioapic);\n\n\treturn (0);\n}\n\nint\nvioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,\n    int size, UNUSED void *arg)\n{\n\tint error;\n\tstruct vioapic *vioapic;\n\n\tvioapic = vm_ioapic(vm);\n\terror = vioapic_mmio_rw(vioapic, vcpuid, gpa, rval, size, true);\n\n\treturn (error);\n}\n\nint\nvioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,\n    int size, UNUSED void *arg)\n{\n\tint error;\n\tstruct vioapic *vioapic;\n\n\tvioapic = vm_ioapic(vm);\n\terror = vioapic_mmio_rw(vioapic, vcpuid, gpa, &wval, size, false);\n\treturn (error);\n}\n\nvoid\nvioapic_process_eoi(struct vm *vm, UNUSED int vcpuid, int vector)\n{\n\tstruct vioapic *vioapic;\n\tint pin;\n\n\tKASSERT(vector >= 0 && vector < 256,\n\t    (\"vioapic_process_eoi: invalid vector %d\", vector));\n\n\tvioapic = vm_ioapic(vm);\n\tVIOAPIC_CTR1(vioapic, \"ioapic processing eoi for vector %d\", vector);\n\n\t/*\n\t * XXX keep track of the pins associated with this vector instead\n\t * of iterating on every single pin each time.\n\t */\n\tVIOAPIC_LOCK(vioapic);\n\tfor (pin = 0; pin < REDIR_ENTRIES; pin++) {\n\t\tif ((vioapic->rtbl[pin].reg & IOART_REM_IRR) == 0)\n\t\t\tcontinue;\n\t\tif ((vioapic->rtbl[pin].reg & IOART_INTVEC) != vector)\n\t\t\tcontinue;\n\t\tvioapic->rtbl[pin].reg &= ~((uint64_t) IOART_REM_IRR);\n\t\tif (vioapic->rtbl[pin].acnt > 0) {\n\t\t\tVIOAPIC_CTR2(vioapic, \"ioapic pin%d: asserted at eoi, \"\n\t\t\t    \"acnt %d\", pin, vioapic->rtbl[pin].acnt);\n\t\t\tvioapic_send_intr(vioapic, pin);\n\t\t}\n\t}\n\tVIOAPIC_UNLOCK(vioapic);\n}\n\nstruct vioapic *\nvioapic_init(struct vm *vm)\n{\n\tint i;\n\tstruct vioapic *vioapic;\n\n\tvioapic = malloc(sizeof(struct vioapic));\n\tassert(vioapic);\n\tbzero(vioapic, sizeof(struct vioapic));\n\tvioapic->vm = vm;\n\n\tVIOAPIC_LOCK_INIT(vioapic);\n\n\t/* Initialize all redirection entries to mask all interrupts */\n\tfor (i = 0; i < REDIR_ENTRIES; i++)\n\t\tvioapic->rtbl[i].reg = 0x0001000000010000UL;\n\n\treturn (vioapic);\n}\n\nvoid\nvioapic_cleanup(struct vioapic *vioapic)\n{\n\tfree(vioapic);\n}\n\nint\nvioapic_pincount(UNUSED struct vm *vm)\n{\n\treturn (REDIR_ENTRIES);\n}\n"
  },
  {
    "path": "src/vmm/io/vlapic.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <strings.h>\n#include <errno.h>\n#include <xhyve/lock.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/support/apicreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/vmm_stat.h>\n#include <xhyve/vmm/io/vlapic.h>\n#include <xhyve/vmm/io/vlapic_priv.h>\n#include <xhyve/vmm/io/vioapic.h>\n\n#define\tPRIO(x)\t\t\t((x) >> 4)\n\n#define VLAPIC_VERSION\t\t(16)\n\n#define\tx2apic(vlapic)\t(((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0)\n\n/*\n * The 'vlapic->timer_lock' is used to provide mutual exclusion between the\n * vlapic_callout_handler() and vcpu accesses to:\n * - timer_freq_bt, timer_period_bt, timer_fire_bt\n * - timer LVT register\n */\n#define VLAPIC_TIMER_LOCK_INIT(v) XHYVE_LOCK_INIT(v, timer_lock)\n#define VLAPIC_TIMER_LOCK(v) XHYVE_LOCK(v, timer_lock)\n#define VLAPIC_TIMER_UNLOCK(v) XHYVE_UNLOCK(v, timer_lock)\n\n/*\n * APIC timer frequency:\n * - arbitrary but chosen to be in the ballpark of contemporary hardware.\n * - power-of-two to avoid loss of precision when converted to a bintime.\n */\n#define VLAPIC_BUS_FREQ\t\t(128 * 1024 * 1024)\n\nstatic __inline uint32_t\nvlapic_get_id(struct vlapic *vlapic)\n{\n\n\tif (x2apic(vlapic))\n\t\treturn ((uint32_t) vlapic->vcpuid);\n\telse\n\t\treturn ((uint32_t) (vlapic->vcpuid << 24));\n}\n\nstatic uint32_t\nx2apic_ldr(struct vlapic *vlapic)\n{\n\tint apicid;\n\tuint32_t ldr;\n\n\tapicid = (int) vlapic_get_id(vlapic);\n\tldr = 1 << (apicid & 0xf);\n\tldr |= (uint32_t) ((apicid & 0xffff0) << 12);\n\treturn (ldr);\n}\n\nvoid\nvlapic_dfr_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\n\tlapic = vlapic->apic_page;\n\tif (x2apic(vlapic)) {\n\t\tVM_CTR1(vlapic->vm, \"ignoring write to DFR in x2apic mode: %#x\",\n\t\t    lapic->dfr);\n\t\tlapic->dfr = 0;\n\t\treturn;\n\t}\n\n\tlapic->dfr &= APIC_DFR_MODEL_MASK;\n\tlapic->dfr |= APIC_DFR_RESERVED;\n\n\tif ((lapic->dfr & APIC_DFR_MODEL_MASK) == APIC_DFR_MODEL_FLAT) {\n\t\tVLAPIC_CTR0(vlapic, \"vlapic DFR in Flat Model\");\n\t} else if ((lapic->dfr & APIC_DFR_MODEL_MASK) == APIC_DFR_MODEL_CLUSTER) {\n\t\tVLAPIC_CTR0(vlapic, \"vlapic DFR in Cluster Model\");\n\t} else {\n\t\tVLAPIC_CTR1(vlapic, \"DFR in Unknown Model %#x\", lapic->dfr);\n\t}\n}\n\nvoid\nvlapic_ldr_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\n\tlapic = vlapic->apic_page;\n\n\t/* LDR is read-only in x2apic mode */\n\tif (x2apic(vlapic)) {\n\t\tVLAPIC_CTR1(vlapic, \"ignoring write to LDR in x2apic mode: %#x\",\n\t\t    lapic->ldr);\n\t\tlapic->ldr = x2apic_ldr(vlapic);\n\t} else {\n\t\tlapic->ldr &= ~((unsigned) APIC_LDR_RESERVED);\n\t\tVLAPIC_CTR1(vlapic, \"vlapic LDR set to %#x\", lapic->ldr);\n\t}\n}\n\nvoid\nvlapic_id_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\t\n\t/*\n\t * We don't allow the ID register to be modified so reset it back to\n\t * its default value.\n\t */\n\tlapic = vlapic->apic_page;\n\tlapic->id = vlapic_get_id(vlapic);\n}\n\nstatic int\nvlapic_timer_divisor(uint32_t dcr)\n{\n\tswitch (dcr & 0xB) {\n\tcase APIC_TDCR_1:\n\t\treturn (1);\n\tcase APIC_TDCR_2:\n\t\treturn (2);\n\tcase APIC_TDCR_4:\n\t\treturn (4);\n\tcase APIC_TDCR_8:\n\t\treturn (8);\n\tcase APIC_TDCR_16:\n\t\treturn (16);\n\tcase APIC_TDCR_32:\n\t\treturn (32);\n\tcase APIC_TDCR_64:\n\t\treturn (64);\n\tcase APIC_TDCR_128:\n\t\treturn (128);\n\tdefault:\n\t\txhyve_abort(\"vlapic_timer_divisor: invalid dcr 0x%08x\\n\", dcr);\n\t}\n}\n\n#if 0\nstatic inline void\nvlapic_dump_lvt(uint32_t offset, uint32_t *lvt)\n{\n\tprintf(\"Offset %x: lvt %08x (V:%02x DS:%x M:%x)\\n\", offset,\n\t    *lvt, *lvt & APIC_LVTT_VECTOR, *lvt & APIC_LVTT_DS,\n\t    *lvt & APIC_LVTT_M);\n}\n#endif\n\nstatic uint32_t\nvlapic_get_ccr(struct vlapic *vlapic)\n{\n\tstruct bintime bt_now, bt_rem;\n\tstruct LAPIC *lapic;\n\tuint32_t ccr;\n\t\n\tccr = 0;\n\tlapic = vlapic->apic_page;\n\n\tVLAPIC_TIMER_LOCK(vlapic);\n\tif (callout_active(&vlapic->callout)) {\n\t\t/*\n\t\t * If the timer is scheduled to expire in the future then\n\t\t * compute the value of 'ccr' based on the remaining time.\n\t\t */\n\t\tbinuptime(&bt_now);\n\t\tif (bintime_cmp(&vlapic->timer_fire_bt, &bt_now, >)) {\n\t\t\tbt_rem = vlapic->timer_fire_bt;\n\t\t\tbintime_sub(&bt_rem, &bt_now);\n\t\t\tccr += bt_rem.sec * BT2FREQ(&vlapic->timer_freq_bt);\n\t\t\tccr += bt_rem.frac / vlapic->timer_freq_bt.frac;\n\t\t}\n\t}\n\tKASSERT(ccr <= lapic->icr_timer, (\"vlapic_get_ccr: invalid ccr %#x, \"\n\t    \"icr_timer is %#x\", ccr, lapic->icr_timer));\n\tVLAPIC_CTR2(vlapic, \"vlapic ccr_timer = %#x, icr_timer = %#x\",\n\t    ccr, lapic->icr_timer);\n\tVLAPIC_TIMER_UNLOCK(vlapic);\n\treturn (ccr);\n}\n\nvoid\nvlapic_dcr_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\tint divisor;\n\t\n\tlapic = vlapic->apic_page;\n\tVLAPIC_TIMER_LOCK(vlapic);\n\n\tdivisor = vlapic_timer_divisor(lapic->dcr_timer);\n\tVLAPIC_CTR2(vlapic, \"vlapic dcr_timer=%#x, divisor=%d\",\n\t    lapic->dcr_timer, divisor);\n\n\t/*\n\t * Update the timer frequency and the timer period.\n\t *\n\t * XXX changes to the frequency divider will not take effect until\n\t * the timer is reloaded.\n\t */\n\tFREQ2BT(((unsigned) (VLAPIC_BUS_FREQ / divisor)), &vlapic->timer_freq_bt);\n\tvlapic->timer_period_bt = vlapic->timer_freq_bt;\n\tbintime_mul(&vlapic->timer_period_bt, lapic->icr_timer);\n\n\tVLAPIC_TIMER_UNLOCK(vlapic);\n}\n\nvoid\nvlapic_esr_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\t\n\tlapic = vlapic->apic_page;\n\tlapic->esr = vlapic->esr_pending;\n\tvlapic->esr_pending = 0;\n}\n\nint\nvlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level)\n{\n\tstruct LAPIC *lapic;\n\tuint32_t *irrptr, *tmrptr, mask;\n\tint idx;\n\n\tKASSERT(vector >= 0 && vector < 256, (\"invalid vector %d\", vector));\n\n\tlapic = vlapic->apic_page;\n\tif (!(lapic->svr & APIC_SVR_ENABLE)) {\n\t\tVLAPIC_CTR1(vlapic, \"vlapic is software disabled, ignoring \"\n\t\t    \"interrupt %d\", vector);\n\t\treturn (0);\n\t}\n\n\tif (vector < 16) {\n\t\tvlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR);\n\t\tVLAPIC_CTR1(vlapic, \"vlapic ignoring interrupt to vector %d\",\n\t\t    vector);\n\t\treturn (1);\n\t}\n\n\tif (vlapic->ops.set_intr_ready)\n\t\treturn ((*vlapic->ops.set_intr_ready)(vlapic, vector, level));\n\n\tidx = (vector / 32) * 4;\n\tmask = 1 << (vector % 32);\n\n\tirrptr = &lapic->irr0;\n\tatomic_set_int(&irrptr[idx], mask);\n\n\t/*\n\t * Verify that the trigger-mode of the interrupt matches with\n\t * the vlapic TMR registers.\n\t */\n\ttmrptr = &lapic->tmr0;\n\tif ((tmrptr[idx] & mask) != (level ? mask : 0)) {\n\t\tVLAPIC_CTR3(vlapic, \"vlapic TMR[%d] is 0x%08x but \"\n\t\t    \"interrupt is %s-triggered\", idx / 4, tmrptr[idx],\n\t\t    level ? \"level\" : \"edge\");\n\t}\n\n\tVLAPIC_CTR_IRR(vlapic, \"vlapic_set_intr_ready\");\n\treturn (1);\n}\n\nstatic __inline uint32_t *\nvlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset)\n{\n\tstruct LAPIC\t*lapic = vlapic->apic_page;\n\tint \t\t i;\n\n\tswitch (offset) {\n\tcase APIC_OFFSET_CMCI_LVT:\n\t\treturn (&lapic->lvt_cmci);\n\tcase APIC_OFFSET_TIMER_LVT:\n\tcase APIC_OFFSET_THERM_LVT:\n\tcase APIC_OFFSET_PERF_LVT:\n\tcase APIC_OFFSET_LINT0_LVT:\n\tcase APIC_OFFSET_LINT1_LVT:\n\tcase APIC_OFFSET_ERROR_LVT:\n\t\ti = (offset - APIC_OFFSET_TIMER_LVT) >> 2;\n\t\treturn ((&lapic->lvt_timer) + i);;\n\tdefault:\n\t\txhyve_abort(\"vlapic_get_lvt: invalid LVT\\n\");\n\t}\n}\n\nstatic __inline int\nlvt_off_to_idx(uint32_t offset)\n{\n\tint index;\n\n\tswitch (offset) {\n\tcase APIC_OFFSET_CMCI_LVT:\n\t\tindex = APIC_LVT_CMCI;\n\t\tbreak;\n\tcase APIC_OFFSET_TIMER_LVT:\n\t\tindex = APIC_LVT_TIMER;\n\t\tbreak;\n\tcase APIC_OFFSET_THERM_LVT:\n\t\tindex = APIC_LVT_THERMAL;\n\t\tbreak;\n\tcase APIC_OFFSET_PERF_LVT:\n\t\tindex = APIC_LVT_PMC;\n\t\tbreak;\n\tcase APIC_OFFSET_LINT0_LVT:\n\t\tindex = APIC_LVT_LINT0;\n\t\tbreak;\n\tcase APIC_OFFSET_LINT1_LVT:\n\t\tindex = APIC_LVT_LINT1;\n\t\tbreak;\n\tcase APIC_OFFSET_ERROR_LVT:\n\t\tindex = APIC_LVT_ERROR;\n\t\tbreak;\n\tdefault:\n\t\tindex = -1;\n\t\tbreak;\n\t}\n\tKASSERT(index >= 0 && index <= VLAPIC_MAXLVT_INDEX, (\"lvt_off_to_idx: \"\n\t    \"invalid lvt index %d for offset %#x\", index, offset));\n\n\treturn (index);\n}\n\nstatic __inline uint32_t\nvlapic_get_lvt(struct vlapic *vlapic, uint32_t offset)\n{\n\tint idx;\n\tuint32_t val;\n\n\tidx = lvt_off_to_idx(offset);\n\tval = atomic_load_acq_32(&vlapic->lvt_last[idx]);\n\treturn (val);\n}\n\nvoid\nvlapic_lvt_write_handler(struct vlapic *vlapic, uint32_t offset)\n{\n\tuint32_t *lvtptr, mask, val;\n\tstruct LAPIC *lapic;\n\tint idx;\n\t\n\tlapic = vlapic->apic_page;\n\tlvtptr = vlapic_get_lvtptr(vlapic, offset);\t\n\tval = *lvtptr;\n\tidx = lvt_off_to_idx(offset);\n\n\tif (!(lapic->svr & APIC_SVR_ENABLE))\n\t\tval |= APIC_LVT_M;\n\tmask = APIC_LVT_M | APIC_LVT_DS | APIC_LVT_VECTOR;\n\tswitch (offset) {\n\tcase APIC_OFFSET_TIMER_LVT:\n\t\tmask |= APIC_LVTT_TM;\n\t\tbreak;\n\tcase APIC_OFFSET_ERROR_LVT:\n\t\tbreak;\n\tcase APIC_OFFSET_LINT0_LVT:\n\tcase APIC_OFFSET_LINT1_LVT:\n\t\tmask |= APIC_LVT_TM | APIC_LVT_RIRR | APIC_LVT_IIPP;\n\t\t/* FALLTHROUGH */\n\tdefault:\n\t\tmask |= APIC_LVT_DM;\n\t\tbreak;\n\t}\n\tval &= mask;\n\t*lvtptr = val;\n\tatomic_store_rel_32(&vlapic->lvt_last[idx], val);\n}\n\nstatic void\nvlapic_mask_lvts(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic = vlapic->apic_page;\n\n\tlapic->lvt_cmci |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_CMCI_LVT);\n\n\tlapic->lvt_timer |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_TIMER_LVT);\n\n\tlapic->lvt_thermal |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_THERM_LVT);\n\n\tlapic->lvt_pcint |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_PERF_LVT);\n\n\tlapic->lvt_lint0 |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_LINT0_LVT);\n\n\tlapic->lvt_lint1 |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_LINT1_LVT);\n\n\tlapic->lvt_error |= APIC_LVT_M;\n\tvlapic_lvt_write_handler(vlapic, APIC_OFFSET_ERROR_LVT);\n}\n\nstatic int\nvlapic_fire_lvt(struct vlapic *vlapic, uint32_t lvt)\n{\n\tuint32_t vec, mode;\n\n\tif (lvt & APIC_LVT_M)\n\t\treturn (0);\n\n\tvec = lvt & APIC_LVT_VECTOR;\n\tmode = lvt & APIC_LVT_DM;\n\n\tswitch (mode) {\n\tcase APIC_LVT_DM_FIXED:\n\t\tif (vec < 16) {\n\t\t\tvlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);\n\t\t\treturn (0);\n\t\t}\n\t\tif (vlapic_set_intr_ready(vlapic, ((int) vec), false))\n\t\t\tvcpu_notify_event(vlapic->vm, vlapic->vcpuid, true);\n\t\tbreak;\n\tcase APIC_LVT_DM_NMI:\n\t\tvm_inject_nmi(vlapic->vm, vlapic->vcpuid);\n\t\tbreak;\n\tcase APIC_LVT_DM_EXTINT:\n\t\tvm_inject_extint(vlapic->vm, vlapic->vcpuid);\n\t\tbreak;\n\tdefault:\n\t\t// Other modes ignored\n\t\treturn (0);\n\t}\n\treturn (1);\n}\n\n#if 1\nstatic void\ndump_isrvec_stk(struct vlapic *vlapic)\n{\n\tint i;\n\tuint32_t *isrptr;\n\n\tisrptr = &vlapic->apic_page->isr0;\n\tfor (i = 0; i < 8; i++)\n\t\tprintf(\"ISR%d 0x%08x\\n\", i, isrptr[i * 4]);\n\n\tfor (i = 0; i <= vlapic->isrvec_stk_top; i++)\n\t\tprintf(\"isrvec_stk[%d] = %d\\n\", i, vlapic->isrvec_stk[i]);\n}\n#endif\n\n/*\n * Algorithm adopted from section \"Interrupt, Task and Processor Priority\"\n * in Intel Architecture Manual Vol 3a.\n */\nstatic void\nvlapic_update_ppr(struct vlapic *vlapic)\n{\n\tint isrvec, tpr, ppr;\n\n\t/*\n\t * Note that the value on the stack at index 0 is always 0.\n\t *\n\t * This is a placeholder for the value of ISRV when none of the\n\t * bits is set in the ISRx registers.\n\t */\n\tisrvec = vlapic->isrvec_stk[vlapic->isrvec_stk_top];\n\ttpr = (int) vlapic->apic_page->tpr;\n\n#if 1\n\t{\n\t\tint i, lastprio, curprio, vector, idx;\n\t\tuint32_t *isrptr;\n\n\t\tif (vlapic->isrvec_stk_top == 0 && isrvec != 0)\n\t\t\txhyve_abort(\"isrvec_stk is corrupted: %d\\n\", isrvec);\n\n\t\t/*\n\t\t * Make sure that the priority of the nested interrupts is\n\t\t * always increasing.\n\t\t */\n\t\tlastprio = -1;\n\t\tfor (i = 1; i <= vlapic->isrvec_stk_top; i++) {\n\t\t\tcurprio = PRIO(vlapic->isrvec_stk[i]);\n\t\t\tif (curprio <= lastprio) {\n\t\t\t\tdump_isrvec_stk(vlapic);\n\t\t\t\txhyve_abort(\"isrvec_stk does not satisfy invariant\\n\");\n\t\t\t}\n\t\t\tlastprio = curprio;\n\t\t}\n\n\t\t/*\n\t\t * Make sure that each bit set in the ISRx registers has a\n\t\t * corresponding entry on the isrvec stack.\n\t\t */\n\t\ti = 1;\n\t\tisrptr = &vlapic->apic_page->isr0;\n\t\tfor (vector = 0; vector < 256; vector++) {\n\t\t\tidx = (vector / 32) * 4;\n\t\t\tif (isrptr[idx] & (1 << (vector % 32))) {\n\t\t\t\tif (i > vlapic->isrvec_stk_top ||\n\t\t\t\t    vlapic->isrvec_stk[i] != vector) {\n\t\t\t\t\tdump_isrvec_stk(vlapic);\n\t\t\t\t\txhyve_abort(\"ISR and isrvec_stk out of sync\\n\");\n\t\t\t\t}\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t}\n#endif\n\n\tif (PRIO(tpr) >= PRIO(isrvec))\n\t\tppr = tpr;\n\telse\n\t\tppr = isrvec & 0xf0;\n\n\tvlapic->apic_page->ppr = (uint32_t) ppr;\n\tVLAPIC_CTR1(vlapic, \"vlapic_update_ppr 0x%02x\", ppr);\n}\n\nstatic VMM_STAT(VLAPIC_GRATUITOUS_EOI, \"EOI without any in-service interrupt\");\n\nstatic void\nvlapic_process_eoi(struct vlapic *vlapic)\n{\n\tstruct LAPIC\t*lapic = vlapic->apic_page;\n\tuint32_t\t*isrptr, *tmrptr;\n\tint\t\ti, idx, bitpos, vector;\n\n\tisrptr = &lapic->isr0;\n\ttmrptr = &lapic->tmr0;\n\n\tfor (i = 7; i >= 0; i--) {\n\t\tidx = i * 4;\n\t\tbitpos = fls((int) isrptr[idx]);\n\t\tif (bitpos-- != 0) {\n\t\t\tif (vlapic->isrvec_stk_top <= 0) {\n\t\t\t\txhyve_abort(\"invalid vlapic isrvec_stk_top %d\\n\",\n\t\t\t\t      vlapic->isrvec_stk_top);\n\t\t\t}\n\t\t\tisrptr[idx] &= ~(1 << bitpos);\n\t\t\tvector = i * 32 + bitpos;\n\t\t\tVCPU_CTR1(vlapic->vm, vlapic->vcpuid, \"EOI vector %d\",\n\t\t\t    vector);\n\t\t\tVLAPIC_CTR_ISR(vlapic, \"vlapic_process_eoi\");\n\t\t\tvlapic->isrvec_stk_top--;\n\t\t\tvlapic_update_ppr(vlapic);\n\t\t\tif ((tmrptr[idx] & (1 << bitpos)) != 0) {\n\t\t\t\tvioapic_process_eoi(vlapic->vm, vlapic->vcpuid,\n\t\t\t\t    vector);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\tVCPU_CTR0(vlapic->vm, vlapic->vcpuid, \"Gratuitous EOI\");\n\tvmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_GRATUITOUS_EOI, 1);\n}\n\nstatic __inline int\nvlapic_get_lvt_field(uint32_t lvt, uint32_t mask)\n{\n\n\treturn ((int) (lvt & mask));\n}\n\nstatic __inline int\nvlapic_periodic_timer(struct vlapic *vlapic)\n{\n\tuint32_t lvt;\n\t\n\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);\n\n\treturn (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC));\n}\n\nstatic VMM_STAT(VLAPIC_INTR_ERROR, \"error interrupts generated by vlapic\");\n\nvoid\nvlapic_set_error(struct vlapic *vlapic, uint32_t mask)\n{\n\tuint32_t lvt;\n\n\tvlapic->esr_pending |= mask;\n\tif (vlapic->esr_firing)\n\t\treturn;\n\tvlapic->esr_firing = 1;\n\n\t// The error LVT always uses the fixed delivery mode.\n\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);\n\tif (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {\n\t\tvmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_ERROR, 1);\n\t}\n\tvlapic->esr_firing = 0;\n}\n\nstatic VMM_STAT(VLAPIC_INTR_TIMER, \"timer interrupts generated by vlapic\");\n\nstatic void\nvlapic_fire_timer(struct vlapic *vlapic)\n{\n\tuint32_t lvt;\n\t\n\t// The timer LVT always uses the fixed delivery mode.\n\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);\n\tif (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {\n\t\tVLAPIC_CTR0(vlapic, \"vlapic timer fired\");\n\t\tvmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1);\n\t}\n}\n\nstatic VMM_STAT(VLAPIC_INTR_CMC,\n    \"corrected machine check interrupts generated by vlapic\");\n\nvoid\nvlapic_fire_cmci(struct vlapic *vlapic)\n{\n\tuint32_t lvt;\n\n\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);\n\tif (vlapic_fire_lvt(vlapic, lvt)) {\n\t\tvmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_CMC, 1);\n\t}\n}\n\nstatic VMM_STAT_ARRAY(LVTS_TRIGGERRED, VLAPIC_MAXLVT_INDEX + 1,\n    \"lvts triggered\");\n\nint\nvlapic_trigger_lvt(struct vlapic *vlapic, int vector)\n{\n\tuint32_t lvt;\n\n\tif (vlapic_enabled(vlapic) == false) {\n\t\t/*\n\t\t * When the local APIC is global/hardware disabled,\n\t\t * LINT[1:0] pins are configured as INTR and NMI pins,\n\t\t * respectively.\n\t\t*/\n\t\tswitch (vector) {\n\t\t\tcase APIC_LVT_LINT0:\n\t\t\t\tvm_inject_extint(vlapic->vm, vlapic->vcpuid);\n\t\t\t\tbreak;\n\t\t\tcase APIC_LVT_LINT1:\n\t\t\t\tvm_inject_nmi(vlapic->vm, vlapic->vcpuid);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\treturn (0);\n\t}\n\n\tswitch (vector) {\n\tcase APIC_LVT_LINT0:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT0_LVT);\n\t\tbreak;\n\tcase APIC_LVT_LINT1:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT1_LVT);\n\t\tbreak;\n\tcase APIC_LVT_TIMER:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);\n\t\tlvt |= APIC_LVT_DM_FIXED;\n\t\tbreak;\n\tcase APIC_LVT_ERROR:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);\n\t\tlvt |= APIC_LVT_DM_FIXED;\n\t\tbreak;\n\tcase APIC_LVT_PMC:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_PERF_LVT);\n\t\tbreak;\n\tcase APIC_LVT_THERMAL:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_THERM_LVT);\n\t\tbreak;\n\tcase APIC_LVT_CMCI:\n\t\tlvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);\n\t\tbreak;\n\tdefault:\n\t\treturn (EINVAL);\n\t}\n\tif (vlapic_fire_lvt(vlapic, lvt)) {\n\t\tvmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,\n\t\t    LVTS_TRIGGERRED, vector, 1);\n\t}\n\treturn (0);\n}\n\nstatic void\nvlapic_callout_handler(void *arg)\n{\n\tstruct vlapic *vlapic;\n\tstruct bintime bt, btnow;\n\tsbintime_t rem_sbt;\n\n\tvlapic = arg;\n\n\tVLAPIC_TIMER_LOCK(vlapic);\n\tif (callout_pending(&vlapic->callout))\t/* callout was reset */\n\t\tgoto done;\n\n\tif (!callout_active(&vlapic->callout))\t/* callout was stopped */\n\t\tgoto done;\n\n\tcallout_deactivate(&vlapic->callout);\n\n\tvlapic_fire_timer(vlapic);\n\n\tif (vlapic_periodic_timer(vlapic)) {\n\t\tbinuptime(&btnow);\n\t\t/* FIXME */\n\t\tKWARN(bintime_cmp(&btnow, &vlapic->timer_fire_bt, >=),\n\t\t    (\"XHYVE: vlapic callout at %#llx.%#llx, expected at \"\n\t\t    \"%#llx.#%llx\\r\\n\",\n\t\t    btnow.sec, btnow.frac, vlapic->timer_fire_bt.sec,\n\t\t    vlapic->timer_fire_bt.frac));\n\n\t\t/*\n\t\t * Compute the delta between when the timer was supposed to\n\t\t * fire and the present time.\n\t\t */\n\t\tbt = btnow;\n\t\tbintime_sub(&bt, &vlapic->timer_fire_bt);\n\n\t\trem_sbt = bttosbt(vlapic->timer_period_bt);\n\t\tif (bintime_cmp(&bt, &vlapic->timer_period_bt, <)) {\n\t\t\t/*\n\t\t\t * Adjust the time until the next countdown downward\n\t\t\t * to account for the lost time.\n\t\t\t */\n\t\t\trem_sbt -= bttosbt(bt);\n\t\t} else {\n\t\t\t/*\n\t\t\t * If the delta is greater than the timer period then\n\t\t\t * just reset our time base instead of trying to catch\n\t\t\t * up.\n\t\t\t */\n\t\t\tvlapic->timer_fire_bt = btnow;\n\t\t\tVLAPIC_CTR2(vlapic, \"vlapic timer lagging by %llu \"\n\t\t\t    \"usecs, period is %llu usecs - resetting time base\",\n\t\t\t    bttosbt(bt) / SBT_1US,\n\t\t\t    bttosbt(vlapic->timer_period_bt) / SBT_1US);\n\t\t}\n\n\t\tbintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);\n\t\tcallout_reset_sbt(&vlapic->callout, rem_sbt, 0,\n\t\t    vlapic_callout_handler, vlapic, 0);\n\t}\ndone:\n\tVLAPIC_TIMER_UNLOCK(vlapic);\n}\n\nvoid\nvlapic_icrtmr_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\tsbintime_t sbt;\n\tuint32_t icr_timer;\n\n\tVLAPIC_TIMER_LOCK(vlapic);\n\n\tlapic = vlapic->apic_page;\n\ticr_timer = lapic->icr_timer;\n\n\tvlapic->timer_period_bt = vlapic->timer_freq_bt;\n\tbintime_mul(&vlapic->timer_period_bt, icr_timer);\n\n\tif (icr_timer != 0) {\n\t\tbinuptime(&vlapic->timer_fire_bt);\n\t\tbintime_add(&vlapic->timer_fire_bt, &vlapic->timer_period_bt);\n\n\t\tsbt = bttosbt(vlapic->timer_period_bt);\n\t\tcallout_reset_sbt(&vlapic->callout, sbt, 0,\n\t\t    vlapic_callout_handler, vlapic, 0);\n\t} else\n\t\tcallout_stop(&vlapic->callout);\n\n\tVLAPIC_TIMER_UNLOCK(vlapic);\n}\n\n/*\n * This function populates 'dmask' with the set of vcpus that match the\n * addressing specified by the (dest, phys, lowprio) tuple.\n * \n * 'x2apic_dest' specifies whether 'dest' is interpreted as x2APIC (32-bit)\n * or xAPIC (8-bit) destination field.\n */\nstatic void\nvlapic_calcdest(struct vm *vm, cpuset_t *dmask, uint32_t dest, bool phys,\n    bool lowprio, bool x2apic_dest)\n{\n\tstruct vlapic *vlapic;\n\tuint32_t dfr, ldr, ldest, cluster;\n\tuint32_t mda_flat_ldest, mda_cluster_ldest, mda_ldest, mda_cluster_id;\n\tcpuset_t amask;\n\tint vcpuid;\n\n\tif ((x2apic_dest && dest == 0xffffffff) ||\n\t    (!x2apic_dest && dest == 0xff)) {\n\t\t/*\n\t\t * Broadcast in both logical and physical modes.\n\t\t */\n\t\t*dmask = vm_active_cpus(vm);\n\t\treturn;\n\t}\n\n\tif (phys) {\n\t\t/*\n\t\t * Physical mode: destination is APIC ID.\n\t\t */\n\t\tCPU_ZERO(dmask);\n\t\tvcpuid = vm_apicid2vcpuid(vm, ((int) dest));\n\t\tif (vcpuid < VM_MAXCPU)\n\t\t\tCPU_SET(((unsigned) vcpuid), dmask);\n\t} else {\n\t\t/*\n\t\t * In the \"Flat Model\" the MDA is interpreted as an 8-bit wide\n\t\t * bitmask. This model is only avilable in the xAPIC mode.\n\t\t */\n\t\tmda_flat_ldest = dest & 0xff;\n\n\t\t/*\n\t\t * In the \"Cluster Model\" the MDA is used to identify a\n\t\t * specific cluster and a set of APICs in that cluster.\n\t\t */\n\t\tif (x2apic_dest) {\n\t\t\tmda_cluster_id = dest >> 16;\n\t\t\tmda_cluster_ldest = dest & 0xffff;\n\t\t} else {\n\t\t\tmda_cluster_id = (dest >> 4) & 0xf;\n\t\t\tmda_cluster_ldest = dest & 0xf;\n\t\t}\n\n\t\t/*\n\t\t * Logical mode: match each APIC that has a bit set\n\t\t * in it's LDR that matches a bit in the ldest.\n\t\t */\n\t\tCPU_ZERO(dmask);\n\t\tamask = vm_active_cpus(vm);\n\t\twhile ((vcpuid = CPU_FFS(&amask)) != 0) {\n\t\t\tvcpuid--;\n\t\t\tCPU_CLR(((unsigned) vcpuid), &amask);\n\n\t\t\tvlapic = vm_lapic(vm, vcpuid);\n\t\t\tdfr = vlapic->apic_page->dfr;\n\t\t\tldr = vlapic->apic_page->ldr;\n\n\t\t\tif ((dfr & APIC_DFR_MODEL_MASK) ==\n\t\t\t    APIC_DFR_MODEL_FLAT) {\n\t\t\t\tldest = ldr >> 24;\n\t\t\t\tmda_ldest = mda_flat_ldest;\n\t\t\t} else if ((dfr & APIC_DFR_MODEL_MASK) ==\n\t\t\t    APIC_DFR_MODEL_CLUSTER) {\n\t\t\t\tif (x2apic(vlapic)) {\n\t\t\t\t\tcluster = ldr >> 16;\n\t\t\t\t\tldest = ldr & 0xffff;\n\t\t\t\t} else {\n\t\t\t\t\tcluster = ldr >> 28;\n\t\t\t\t\tldest = (ldr >> 24) & 0xf;\n\t\t\t\t}\n\t\t\t\tif (cluster != mda_cluster_id)\n\t\t\t\t\tcontinue;\n\t\t\t\tmda_ldest = mda_cluster_ldest;\n\t\t\t} else {\n\t\t\t\t/*\n\t\t\t\t * Guest has configured a bad logical\n\t\t\t\t * model for this vcpu - skip it.\n\t\t\t\t */\n\t\t\t\tVLAPIC_CTR1(vlapic, \"vlapic has bad logical \"\n\t\t\t\t    \"model %x - cannot deliver interrupt\", dfr);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ((mda_ldest & ldest) != 0) {\n\t\t\t\tCPU_SET(((unsigned) vcpuid), dmask);\n\t\t\t\tif (lowprio)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, \"ipis sent to vcpu\");\n\nstatic void\nvlapic_set_tpr(struct vlapic *vlapic, uint8_t val)\n{\n\tstruct LAPIC *lapic = vlapic->apic_page;\n\n\tif (lapic->tpr != val) {\n\t\tVCPU_CTR2(vlapic->vm, vlapic->vcpuid, \"vlapic TPR changed \"\n\t\t    \"from %#x to %#x\", lapic->tpr, val);\n\t\tlapic->tpr = val;\n\t\tvlapic_update_ppr(vlapic);\n\t}\n}\n\nstatic uint8_t\nvlapic_get_tpr(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic = vlapic->apic_page;\n\n\treturn ((uint8_t) lapic->tpr);\n}\n\nvoid\nvlapic_set_cr8(struct vlapic *vlapic, uint64_t val)\n{\n\tuint8_t tpr;\n\n\tif (val & ~((uint64_t) 0xf)) {\n\t\tvm_inject_gp(vlapic->vm, vlapic->vcpuid);\n\t\treturn;\n\t}\n\n\ttpr = (uint8_t) (val << 4);\n\tvlapic_set_tpr(vlapic, tpr);\n}\n\nuint64_t\nvlapic_get_cr8(struct vlapic *vlapic)\n{\n\tuint8_t tpr;\n\n\ttpr = vlapic_get_tpr(vlapic);\n\treturn (tpr >> 4);\n}\n\nint\nvlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)\n{\n\tint i;\n\tbool phys;\n\tcpuset_t dmask;\n\tuint64_t icrval;\n\tuint32_t dest, vec, mode;\n\tstruct vlapic *vlapic2;\n\tstruct vm_exit *vmexit;\n\tstruct LAPIC *lapic;\n\n\tlapic = vlapic->apic_page;\n\tlapic->icr_lo &= ~((unsigned) APIC_DELSTAT_PEND);\n\ticrval = ((uint64_t)lapic->icr_hi << 32) | lapic->icr_lo;\n\n\tif (x2apic(vlapic))\n\t\tdest = icrval >> 32;\n\telse\n\t\tdest = icrval >> (32 + 24);\n\tvec = icrval & APIC_VECTOR_MASK;\n\tmode = icrval & APIC_DELMODE_MASK;\n\n\tif (mode == APIC_DELMODE_FIXED && vec < 16) {\n\t\tvlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);\n\t\tVLAPIC_CTR1(vlapic, \"Ignoring invalid IPI %d\", vec);\n\t\treturn (0);\n\t}\n\n\tVLAPIC_CTR2(vlapic, \"icrlo 0x%016llx triggered ipi %d\", icrval, vec);\n\n\tif (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) {\n\t\tswitch (icrval & APIC_DEST_MASK) {\n\t\tcase APIC_DEST_DESTFLD:\n\t\t\tphys = ((icrval & APIC_DESTMODE_LOG) == 0);\n\t\t\tvlapic_calcdest(vlapic->vm, &dmask, dest, phys, false,\n\t\t\t    x2apic(vlapic));\n\t\t\tbreak;\n\t\tcase APIC_DEST_SELF:\n\t\t\tCPU_SETOF(((unsigned) vlapic->vcpuid), &dmask);\n\t\t\tbreak;\n\t\tcase APIC_DEST_ALLISELF:\n\t\t\tdmask = vm_active_cpus(vlapic->vm);\n\t\t\tbreak;\n\t\tcase APIC_DEST_ALLESELF:\n\t\t\tdmask = vm_active_cpus(vlapic->vm);\n\t\t\tCPU_CLR(((unsigned) vlapic->vcpuid), &dmask);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tCPU_ZERO(&dmask);\t/* satisfy gcc */\n\t\t\tbreak;\n\t\t}\n\n\t\twhile ((i = CPU_FFS(&dmask)) != 0) {\n\t\t\ti--;\n\t\t\tCPU_CLR(((unsigned) i), &dmask);\n\t\t\tif (mode == APIC_DELMODE_FIXED) {\n\t\t\t\tlapic_intr_edge(vlapic->vm, i, ((int) vec));\n\t\t\t\tvmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,\n\t\t\t\t\t\t    IPIS_SENT, i, 1);\n\t\t\t\tVLAPIC_CTR2(vlapic, \"vlapic sending ipi %d \"\n\t\t\t\t    \"to vcpuid %d\", vec, i);\n\t\t\t} else {\n\t\t\t\tvm_inject_nmi(vlapic->vm, i);\n\t\t\t\tVLAPIC_CTR1(vlapic, \"vlapic sending ipi nmi \"\n\t\t\t\t    \"to vcpuid %d\", i);\n\t\t\t}\n\t\t}\n\n\t\treturn (0);\t/* handled completely in the kernel */\n\t}\n\n\tif (mode == APIC_DELMODE_INIT) {\n\t\tif ((icrval & APIC_LEVEL_MASK) == APIC_LEVEL_DEASSERT)\n\t\t\treturn (0);\n\n\t\tif (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) {\n\t\t\tvlapic2 = vm_lapic(vlapic->vm, ((int) dest));\n\n\t\t\t/* move from INIT to waiting-for-SIPI state */\n\t\t\tif (vlapic2->boot_state == BS_INIT) {\n\t\t\t\tvlapic2->boot_state = BS_SIPI;\n\t\t\t}\n\n\t\t\treturn (0);\n\t\t}\n\t}\n\n\tif (mode == APIC_DELMODE_STARTUP) {\n\t\tif (vlapic->vcpuid == 0 && dest != 0 && dest < VM_MAXCPU) {\n\t\t\tvlapic2 = vm_lapic(vlapic->vm, ((int) dest));\n\n\t\t\t/*\n\t\t\t * Ignore SIPIs in any state other than wait-for-SIPI\n\t\t\t */\n\t\t\tif (vlapic2->boot_state != BS_SIPI)\n\t\t\t\treturn (0);\n\n\t\t\tvlapic2->boot_state = BS_RUNNING;\n\n\t\t\t*retu = true;\n\t\t\tvmexit = vm_exitinfo(vlapic->vm, vlapic->vcpuid);\n\t\t\tvmexit->exitcode = VM_EXITCODE_SPINUP_AP;\n\t\t\tvmexit->u.spinup_ap.vcpu = (int) dest;\n\t\t\tvmexit->u.spinup_ap.rip = vec << XHYVE_PAGE_SHIFT;\n\n\t\t\treturn (0);\n\t\t}\n\t}\n\n\t/*\n\t * This will cause a return to userland.\n\t */\n\treturn (1);\n}\n\nvoid\nvlapic_self_ipi_handler(struct vlapic *vlapic, uint64_t val)\n{\n\tint vec;\n\n\tKASSERT(x2apic(vlapic), (\"SELF_IPI does not exist in xAPIC mode\"));\n\n\tvec = val & 0xff;\n\tlapic_intr_edge(vlapic->vm, vlapic->vcpuid, vec);\n\tvmm_stat_array_incr(vlapic->vm, vlapic->vcpuid, IPIS_SENT,\n\t    vlapic->vcpuid, 1);\n\tVLAPIC_CTR1(vlapic, \"vlapic self-ipi %d\", vec);\n}\n\nint\nvlapic_pending_intr(struct vlapic *vlapic, int *vecptr)\n{\n\tstruct LAPIC\t*lapic = vlapic->apic_page;\n\tint\t  \t idx, i, bitpos, vector;\n\tuint32_t\t*irrptr, val;\n\n\tif (vlapic->ops.pending_intr)\n\t\treturn ((*vlapic->ops.pending_intr)(vlapic, vecptr));\n\n\tirrptr = &lapic->irr0;\n\n\tfor (i = 7; i >= 0; i--) {\n\t\tidx = i * 4;\n\t\tval = atomic_load_acq_int(&irrptr[idx]);\n\t\tbitpos = fls((int) val);\n\t\tif (bitpos != 0) {\n\t\t\tvector = i * 32 + (bitpos - 1);\n\t\t\tif (((unsigned) PRIO(vector)) > PRIO(lapic->ppr)) {\n\t\t\t\tVLAPIC_CTR1(vlapic, \"pending intr %d\", vector);\n\t\t\t\tif (vecptr != NULL)\n\t\t\t\t\t*vecptr = vector;\n\t\t\t\treturn (1);\n\t\t\t} else \n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn (0);\n}\n\nvoid\nvlapic_intr_accepted(struct vlapic *vlapic, int vector)\n{\n\tstruct LAPIC\t*lapic = vlapic->apic_page;\n\tuint32_t\t*irrptr, *isrptr;\n\tint\t\tidx, stk_top;\n\n\tif (vlapic->ops.intr_accepted) {\n\t\t(*vlapic->ops.intr_accepted)(vlapic, vector);\n\t\treturn;\n\t}\n\n\t/*\n\t * clear the ready bit for vector being accepted in irr \n\t * and set the vector as in service in isr.\n\t */\n\tidx = (vector / 32) * 4;\n\n\tirrptr = &lapic->irr0;\n\tatomic_clear_int(&irrptr[idx], 1 << (vector % 32));\n\tVLAPIC_CTR_IRR(vlapic, \"vlapic_intr_accepted\");\n\n\tisrptr = &lapic->isr0;\n\tisrptr[idx] |= 1 << (vector % 32);\n\tVLAPIC_CTR_ISR(vlapic, \"vlapic_intr_accepted\");\n\n\t/*\n\t * Update the PPR\n\t */\n\tvlapic->isrvec_stk_top++;\n\n\tstk_top = vlapic->isrvec_stk_top;\n\tif (stk_top >= ISRVEC_STK_SIZE)\n\t\txhyve_abort(\"isrvec_stk_top overflow %d\\n\", stk_top);\n\n\tvlapic->isrvec_stk[stk_top] = (uint8_t) vector;\n\tvlapic_update_ppr(vlapic);\n}\n\nvoid\nvlapic_svr_write_handler(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\tuint32_t old, new, changed;\n\n\tlapic = vlapic->apic_page;\n\n\tnew = lapic->svr;\n\told = vlapic->svr_last;\n\tvlapic->svr_last = new;\n\n\tchanged = old ^ new;\n\tif ((changed & APIC_SVR_ENABLE) != 0) {\n\t\tif ((new & APIC_SVR_ENABLE) == 0) {\n\t\t\t/*\n\t\t\t * The apic is now disabled so stop the apic timer\n\t\t\t * and mask all the LVT entries.\n\t\t\t */\n\t\t\tVLAPIC_CTR0(vlapic, \"vlapic is software-disabled\");\n\t\t\tVLAPIC_TIMER_LOCK(vlapic);\n\t\t\tcallout_stop(&vlapic->callout);\n\t\t\tVLAPIC_TIMER_UNLOCK(vlapic);\n\t\t\tvlapic_mask_lvts(vlapic);\n\t\t} else {\n\t\t\t/*\n\t\t\t * The apic is now enabled so restart the apic timer\n\t\t\t * if it is configured in periodic mode.\n\t\t\t */\n\t\t\tVLAPIC_CTR0(vlapic, \"vlapic is software-enabled\");\n\t\t\tif (vlapic_periodic_timer(vlapic))\n\t\t\t\tvlapic_icrtmr_write_handler(vlapic);\n\t\t}\n\t}\n}\n\nint\nvlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset,\n    uint64_t *data, UNUSED bool *retu)\n{\n\tstruct LAPIC\t*lapic = vlapic->apic_page;\n\tuint32_t\t*reg;\n\tint\t\t i;\n\n\t/* Ignore MMIO accesses in x2APIC mode */\n\tif (x2apic(vlapic) && mmio_access) {\n\t\tVLAPIC_CTR1(vlapic, \"MMIO read from offset %#llx in x2APIC mode\",\n\t\t    offset);\n\t\t*data = 0;\n\t\tgoto done;\n\t}\n\n\tif (!x2apic(vlapic) && !mmio_access) {\n\t\t/*\n\t\t * XXX Generate GP fault for MSR accesses in xAPIC mode\n\t\t */\n\t\tVLAPIC_CTR1(vlapic, \"x2APIC MSR read from offset %#llx in \"\n\t\t    \"xAPIC mode\", offset);\n\t\t*data = 0;\n\t\tgoto done;\n\t}\n\n\tif (offset > sizeof(*lapic)) {\n\t\t*data = 0;\n\t\tgoto done;\n\t}\n\t\n\toffset &= ~((uint64_t) 3);\n\tswitch(offset)\n\t{\n\t\tcase APIC_OFFSET_ID:\n\t\t\t*data = lapic->id;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_VER:\n\t\t\t*data = lapic->version;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TPR:\n\t\t\t*data = vlapic_get_tpr(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_APR:\n\t\t\t*data = lapic->apr;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_PPR:\n\t\t\t*data = lapic->ppr;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_EOI:\n\t\t\t*data = lapic->eoi;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_LDR:\n\t\t\t*data = lapic->ldr;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_DFR:\n\t\t\t*data = lapic->dfr;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_SVR:\n\t\t\t*data = lapic->svr;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_ISR0:\n\t\tcase APIC_OFFSET_ISR1:\n\t\tcase APIC_OFFSET_ISR2:\n\t\tcase APIC_OFFSET_ISR3:\n\t\tcase APIC_OFFSET_ISR4:\n\t\tcase APIC_OFFSET_ISR5:\n\t\tcase APIC_OFFSET_ISR6:\n\t\tcase APIC_OFFSET_ISR7:\n\t\t\ti = (int) ((offset - APIC_OFFSET_ISR0) >> 2);\n\t\t\treg = &lapic->isr0;\n\t\t\t*data = *(reg + i);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TMR0:\n\t\tcase APIC_OFFSET_TMR1:\n\t\tcase APIC_OFFSET_TMR2:\n\t\tcase APIC_OFFSET_TMR3:\n\t\tcase APIC_OFFSET_TMR4:\n\t\tcase APIC_OFFSET_TMR5:\n\t\tcase APIC_OFFSET_TMR6:\n\t\tcase APIC_OFFSET_TMR7:\n\t\t\ti = (int) ((offset - APIC_OFFSET_TMR0) >> 2);\n\t\t\treg = &lapic->tmr0;\n\t\t\t*data = *(reg + i);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_IRR0:\n\t\tcase APIC_OFFSET_IRR1:\n\t\tcase APIC_OFFSET_IRR2:\n\t\tcase APIC_OFFSET_IRR3:\n\t\tcase APIC_OFFSET_IRR4:\n\t\tcase APIC_OFFSET_IRR5:\n\t\tcase APIC_OFFSET_IRR6:\n\t\tcase APIC_OFFSET_IRR7:\n\t\t\ti = (int) ((offset - APIC_OFFSET_IRR0) >> 2);\n\t\t\treg = &lapic->irr0;\n\t\t\t*data = atomic_load_acq_int(reg + i);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_ESR:\n\t\t\t*data = lapic->esr;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_ICR_LOW: \n\t\t\t*data = lapic->icr_lo;\n\t\t\tif (x2apic(vlapic))\n\t\t\t\t*data |= (uint64_t)lapic->icr_hi << 32;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_ICR_HI: \n\t\t\t*data = lapic->icr_hi;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_CMCI_LVT:\n\t\tcase APIC_OFFSET_TIMER_LVT:\n\t\tcase APIC_OFFSET_THERM_LVT:\n\t\tcase APIC_OFFSET_PERF_LVT:\n\t\tcase APIC_OFFSET_LINT0_LVT:\n\t\tcase APIC_OFFSET_LINT1_LVT:\n\t\tcase APIC_OFFSET_ERROR_LVT:\n\t\t\t*data = vlapic_get_lvt(vlapic, ((uint32_t) offset));\t\n#ifdef INVARIANTS\n\t\t\treg = vlapic_get_lvtptr(vlapic, offset);\n\t\t\tKASSERT(*data == *reg, (\"inconsistent lvt value at \"\n\t\t\t    \"offset %#lx: %#lx/%#x\", offset, *data, *reg));\n#endif\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TIMER_ICR:\n\t\t\t*data = lapic->icr_timer;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TIMER_CCR:\n\t\t\t*data = vlapic_get_ccr(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TIMER_DCR:\n\t\t\t*data = lapic->dcr_timer;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_SELF_IPI:\n\t\t\t/*\n\t\t\t * XXX generate a GP fault if vlapic is in x2apic mode\n\t\t\t */\n\t\t\t*data = 0;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_RRR:\n\t\tdefault:\n\t\t\t*data = 0;\n\t\t\tbreak;\n\t}\ndone:\n\tVLAPIC_CTR2(vlapic, \"vlapic read offset %#llx, data %#llx\", offset, *data);\n\treturn 0;\n}\n\nint\nvlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset,\n    uint64_t data, bool *retu)\n{\n\tstruct LAPIC\t*lapic = vlapic->apic_page;\n\tuint32_t\t*regptr;\n\tint\t\tretval;\n\n\tKASSERT((offset & 0xf) == 0 && offset < XHYVE_PAGE_SIZE,\n\t    (\"vlapic_write: invalid offset %#llx\", offset));\n\n\tVLAPIC_CTR2(vlapic, \"vlapic write offset %#llx, data %#llx\",\n\t    offset, data);\n\n\tif (offset > sizeof(*lapic))\n\t\treturn (0);\n\n\t/* Ignore MMIO accesses in x2APIC mode */\n\tif (x2apic(vlapic) && mmio_access) {\n\t\tVLAPIC_CTR2(vlapic, \"MMIO write of %#llx to offset %#llx \"\n\t\t    \"in x2APIC mode\", data, offset);\n\t\treturn (0);\n\t}\n\n\t/*\n\t * XXX Generate GP fault for MSR accesses in xAPIC mode\n\t */\n\tif (!x2apic(vlapic) && !mmio_access) {\n\t\tVLAPIC_CTR2(vlapic, \"x2APIC MSR write of %#llx to offset %#llx \"\n\t\t    \"in xAPIC mode\", data, offset);\n\t\treturn (0);\n\t}\n\n\tretval = 0;\n\tswitch(offset)\n\t{\n\t\tcase APIC_OFFSET_ID:\n\t\t\tlapic->id = (uint32_t) data;\n\t\t\tvlapic_id_write_handler(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TPR:\n\t\t\tvlapic_set_tpr(vlapic, data & 0xff);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_EOI:\n\t\t\tvlapic_process_eoi(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_LDR:\n\t\t\tlapic->ldr = (uint32_t) data;\n\t\t\tvlapic_ldr_write_handler(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_DFR:\n\t\t\tlapic->dfr = (uint32_t) data;\n\t\t\tvlapic_dfr_write_handler(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_SVR:\n\t\t\tlapic->svr = (uint32_t) data;\n\t\t\tvlapic_svr_write_handler(vlapic);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_ICR_LOW: \n\t\t\tlapic->icr_lo = (uint32_t) data;\n\t\t\tif (x2apic(vlapic))\n\t\t\t\tlapic->icr_hi = data >> 32;\n\t\t\tretval = vlapic_icrlo_write_handler(vlapic, retu);\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_ICR_HI:\n\t\t\tlapic->icr_hi = (uint32_t) data;\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_CMCI_LVT:\n\t\tcase APIC_OFFSET_TIMER_LVT:\n\t\tcase APIC_OFFSET_THERM_LVT:\n\t\tcase APIC_OFFSET_PERF_LVT:\n\t\tcase APIC_OFFSET_LINT0_LVT:\n\t\tcase APIC_OFFSET_LINT1_LVT:\n\t\tcase APIC_OFFSET_ERROR_LVT:\n\t\t\tregptr = vlapic_get_lvtptr(vlapic, ((uint32_t) offset));\n\t\t\t*regptr = (uint32_t) data;\n\t\t\tvlapic_lvt_write_handler(vlapic, ((uint32_t) offset));\n\t\t\tbreak;\n\t\tcase APIC_OFFSET_TIMER_ICR:\n\t\t\tlapic->icr_timer = (uint32_t) data;\n\t\t\tvlapic_icrtmr_write_handler(vlapic);\n\t\t\tbreak;\n\n\t\tcase APIC_OFFSET_TIMER_DCR:\n\t\t\tlapic->dcr_timer = (uint32_t) data;\n\t\t\tvlapic_dcr_write_handler(vlapic);\n\t\t\tbreak;\n\n\t\tcase APIC_OFFSET_ESR:\n\t\t\tvlapic_esr_write_handler(vlapic);\n\t\t\tbreak;\n\n\t\tcase APIC_OFFSET_SELF_IPI:\n\t\t\tif (x2apic(vlapic))\n\t\t\t\tvlapic_self_ipi_handler(vlapic, data);\n\t\t\tbreak;\n\n\t\tcase APIC_OFFSET_VER:\n\t\tcase APIC_OFFSET_APR:\n\t\tcase APIC_OFFSET_PPR:\n\t\tcase APIC_OFFSET_RRR:\n\t\tcase APIC_OFFSET_ISR0:\n\t\tcase APIC_OFFSET_ISR1:\n\t\tcase APIC_OFFSET_ISR2:\n\t\tcase APIC_OFFSET_ISR3:\n\t\tcase APIC_OFFSET_ISR4:\n\t\tcase APIC_OFFSET_ISR5:\n\t\tcase APIC_OFFSET_ISR6:\n\t\tcase APIC_OFFSET_ISR7:\n\t\tcase APIC_OFFSET_TMR0:\n\t\tcase APIC_OFFSET_TMR1:\n\t\tcase APIC_OFFSET_TMR2:\n\t\tcase APIC_OFFSET_TMR3:\n\t\tcase APIC_OFFSET_TMR4:\n\t\tcase APIC_OFFSET_TMR5:\n\t\tcase APIC_OFFSET_TMR6:\n\t\tcase APIC_OFFSET_TMR7:\n\t\tcase APIC_OFFSET_IRR0:\n\t\tcase APIC_OFFSET_IRR1:\n\t\tcase APIC_OFFSET_IRR2:\n\t\tcase APIC_OFFSET_IRR3:\n\t\tcase APIC_OFFSET_IRR4:\n\t\tcase APIC_OFFSET_IRR5:\n\t\tcase APIC_OFFSET_IRR6:\n\t\tcase APIC_OFFSET_IRR7:\n\t\tcase APIC_OFFSET_TIMER_CCR:\n\t\tdefault:\n\t\t\t// Read only.\n\t\t\tbreak;\n\t}\n\n\treturn (retval);\n}\n\nstatic void\nvlapic_reset(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic;\n\t\n\tlapic = vlapic->apic_page;\n\tbzero(lapic, sizeof(struct LAPIC));\n\n\tlapic->id = vlapic_get_id(vlapic);\n\tlapic->version = VLAPIC_VERSION;\n\tlapic->version |= (VLAPIC_MAXLVT_INDEX << MAXLVTSHIFT);\n\tlapic->dfr = 0xffffffff;\n\tlapic->svr = APIC_SVR_VECTOR;\n\tvlapic_mask_lvts(vlapic);\n\tvlapic_reset_tmr(vlapic);\n\n\tlapic->dcr_timer = 0;\n\tvlapic_dcr_write_handler(vlapic);\n\n\tif (vlapic->vcpuid == 0)\n\t\tvlapic->boot_state = BS_RUNNING;\t/* BSP */\n\telse\n\t\tvlapic->boot_state = BS_INIT;\t\t/* AP */\n\n\tvlapic->svr_last = lapic->svr;\n}\n\nvoid\nvlapic_init(struct vlapic *vlapic)\n{\n\tKASSERT(vlapic->vm != NULL, (\"vlapic_init: vm is not initialized\"));\n\tKASSERT(vlapic->vcpuid >= 0 && vlapic->vcpuid < VM_MAXCPU,\n\t    (\"vlapic_init: vcpuid is not initialized\"));\n\tKASSERT(vlapic->apic_page != NULL, (\"vlapic_init: apic_page is not \"\n\t    \"initialized\"));\n\n\t/*\n\t * If the vlapic is configured in x2apic mode then it will be\n\t * accessed in the critical section via the MSR emulation code.\n\t *\n\t * Therefore the timer mutex must be a spinlock because blockable\n\t * mutexes cannot be acquired in a critical section.\n\t */\n\tVLAPIC_TIMER_LOCK_INIT(vlapic);\n\tcallout_init(&vlapic->callout, 1);\n\n\tvlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED;\n\n\tif (vlapic->vcpuid == 0)\n\t\tvlapic->msr_apicbase |= APICBASE_BSP;\n\n\tvlapic_reset(vlapic);\n}\n\nvoid\nvlapic_cleanup(struct vlapic *vlapic)\n{\n\n\tcallout_drain(&vlapic->callout);\n}\n\nuint64_t\nvlapic_get_apicbase(struct vlapic *vlapic)\n{\n\n\treturn (vlapic->msr_apicbase);\n}\n\nint\nvlapic_set_apicbase(struct vlapic *vlapic, uint64_t new)\n{\n\n\tif (vlapic->msr_apicbase != new) {\n\t\tVLAPIC_CTR2(vlapic, \"Changing APIC_BASE MSR from %#llx to %#llx \"\n\t\t    \"not supported\", vlapic->msr_apicbase, new);\n\t\treturn (-1);\n\t}\n\n\treturn (0);\n}\n\nvoid\nvlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state)\n{\n\tstruct vlapic *vlapic;\n\tstruct LAPIC *lapic;\n\n\tvlapic = vm_lapic(vm, vcpuid);\n\n\tif (state == X2APIC_DISABLED)\n\t\tvlapic->msr_apicbase &= ~((uint64_t) APICBASE_X2APIC);\n\telse\n\t\tvlapic->msr_apicbase |= APICBASE_X2APIC;\n\n\t/*\n\t * Reset the local APIC registers whose values are mode-dependent.\n\t *\n\t * XXX this works because the APIC mode can be changed only at vcpu\n\t * initialization time.\n\t */\n\tlapic = vlapic->apic_page;\n\tlapic->id = vlapic_get_id(vlapic);\n\tif (x2apic(vlapic)) {\n\t\tlapic->ldr = x2apic_ldr(vlapic);\n\t\tlapic->dfr = 0;\n\t} else {\n\t\tlapic->ldr = 0;\n\t\tlapic->dfr = 0xffffffff;\n\t}\n\n\tif (state == X2APIC_ENABLED) {\n\t\tif (vlapic->ops.enable_x2apic_mode)\n\t\t\t(*vlapic->ops.enable_x2apic_mode)(vlapic);\n\t}\n}\n\nvoid\nvlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys,\n    int delmode, int vec)\n{\n\tbool lowprio;\n\tint vcpuid;\n\tcpuset_t dmask;\n\n\tif (delmode != IOART_DELFIXED &&\n\t    delmode != IOART_DELLOPRI &&\n\t    delmode != IOART_DELEXINT) {\n\t\tVM_CTR1(vm, \"vlapic intr invalid delmode %#x\", delmode);\n\t\treturn;\n\t}\n\tlowprio = (delmode == IOART_DELLOPRI);\n\n\t/*\n\t * We don't provide any virtual interrupt redirection hardware so\n\t * all interrupts originating from the ioapic or MSI specify the\n\t * 'dest' in the legacy xAPIC format.\n\t */\n\tvlapic_calcdest(vm, &dmask, dest, phys, lowprio, false);\n\n\twhile ((vcpuid = CPU_FFS(&dmask)) != 0) {\n\t\tvcpuid--;\n\t\tCPU_CLR(((unsigned) vcpuid), &dmask);\n\t\tif (delmode == IOART_DELEXINT) {\n\t\t\tvm_inject_extint(vm, vcpuid);\n\t\t} else {\n\t\t\tlapic_set_intr(vm, vcpuid, vec, level);\n\t\t}\n\t}\n}\n\nvoid\nvlapic_post_intr(struct vlapic *vlapic, int hostcpu, UNUSED int ipinum)\n{\n\t/*\n\t * Post an interrupt to the vcpu currently running on 'hostcpu'.\n\t *\n\t * This is done by leveraging features like Posted Interrupts (Intel)\n\t * Doorbell MSR (AMD AVIC) that avoid a VM exit.\n\t *\n\t * If neither of these features are available then fallback to\n\t * sending an IPI to 'hostcpu'.\n\t */\n\tif (vlapic->ops.post_intr)\n\t\t(*vlapic->ops.post_intr)(vlapic, hostcpu);\n\telse\n\t\txhyve_abort(\"hv_vcpu_interrupt\\n\"); /* FIXME */\n\t\t//ipi_cpu(hostcpu, ipinum);\n}\n\nbool\nvlapic_enabled(struct vlapic *vlapic)\n{\n\tstruct LAPIC *lapic = vlapic->apic_page;\n\n\tif ((vlapic->msr_apicbase & APICBASE_ENABLED) != 0 &&\n\t    (lapic->svr & APIC_SVR_ENABLE) != 0)\n\t\treturn (true);\n\telse\n\t\treturn (false);\n}\n\nstatic void\nvlapic_set_tmr(struct vlapic *vlapic, int vector, bool level)\n{\n\tstruct LAPIC *lapic;\n\tuint32_t *tmrptr, mask;\n\tint idx;\n\n\tlapic = vlapic->apic_page;\n\ttmrptr = &lapic->tmr0;\n\tidx = (vector / 32) * 4;\n\tmask = 1 << (vector % 32);\n\tif (level)\n\t\ttmrptr[idx] |= mask;\n\telse\n\t\ttmrptr[idx] &= ~mask;\n\n\tif (vlapic->ops.set_tmr != NULL)\n\t\t(*vlapic->ops.set_tmr)(vlapic, vector, level);\n}\n\nvoid\nvlapic_reset_tmr(struct vlapic *vlapic)\n{\n\tint vector;\n\n\tVLAPIC_CTR0(vlapic, \"vlapic resetting all vectors to edge-triggered\");\n\n\tfor (vector = 0; vector <= 255; vector++)\n\t\tvlapic_set_tmr(vlapic, vector, false);\n}\n\nvoid\nvlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys,\n    int delmode, int vector)\n{\n\tcpuset_t dmask;\n\tbool lowprio;\n\n\tKASSERT(vector >= 0 && vector <= 255, (\"invalid vector %d\", vector));\n\n\t/*\n\t * A level trigger is valid only for fixed and lowprio delivery modes.\n\t */\n\tif (delmode != APIC_DELMODE_FIXED && delmode != APIC_DELMODE_LOWPRIO) {\n\t\tVLAPIC_CTR1(vlapic, \"Ignoring level trigger-mode for \"\n\t\t    \"delivery-mode %d\", delmode);\n\t\treturn;\n\t}\n\n\tlowprio = (delmode == APIC_DELMODE_LOWPRIO);\n\tvlapic_calcdest(vlapic->vm, &dmask, dest, phys, lowprio, false);\n\n\tif (!CPU_ISSET(((unsigned) vlapic->vcpuid), &dmask))\n\t\treturn;\n\n\tVLAPIC_CTR1(vlapic, \"vector %d set to level-triggered\", vector);\n\tvlapic_set_tmr(vlapic, vector, true);\n}\n"
  },
  {
    "path": "src/vmm/io/vpmtmr.c",
    "content": "/*-\n * Copyright (c) 2014, Neel Natu (neel@freebsd.org)\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <assert.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/io/vpmtmr.h>\n\n/*\n * The ACPI Power Management timer is a free-running 24- or 32-bit\n * timer with a frequency of 3.579545MHz\n *\n * This implementation will be 32-bits\n */\n\n#define PMTMR_FREQ\t3579545  /* 3.579545MHz */\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vpmtmr {\n\tsbintime_t\tfreq_sbt;\n\tsbintime_t\tbaseuptime;\n\tuint32_t\tbaseval;\n};\n#pragma clang diagnostic pop\n\nstruct vpmtmr *\nvpmtmr_init(UNUSED struct vm *vm)\n{\n\tstruct vpmtmr *vpmtmr;\n\tstruct bintime bt;\n\n\tvpmtmr = malloc(sizeof(struct vpmtmr));\n\tassert(vpmtmr);\n\tbzero(vpmtmr, sizeof(struct vpmtmr));\n\tvpmtmr->baseuptime = sbinuptime();\n\tvpmtmr->baseval = 0;\n\n\tFREQ2BT(PMTMR_FREQ, &bt);\n\tvpmtmr->freq_sbt = bttosbt(bt);\n\n\treturn (vpmtmr);\n}\n\nvoid\nvpmtmr_cleanup(struct vpmtmr *vpmtmr)\n{\n\n\tfree(vpmtmr);\n}\n\nint\nvpmtmr_handler(struct vm *vm, UNUSED int vcpuid, bool in, UNUSED int port,\n\tint bytes, uint32_t *val)\n{\n\tstruct vpmtmr *vpmtmr;\n\tsbintime_t now, delta;\n\n\tif (!in || bytes != 4)\n\t\treturn (-1);\n\n\tvpmtmr = vm_pmtmr(vm);\n\n\t/*\n\t * No locking needed because 'baseuptime' and 'baseval' are\n\t * written only during initialization.\n\t */\n\tnow = sbinuptime();\n\tdelta = now - vpmtmr->baseuptime;\n\tKASSERT(delta >= 0, (\"vpmtmr_handler: uptime went backwards: \"\n\t    \"%#llx to %#llx\", vpmtmr->baseuptime, now));\n\t*val = (uint32_t) (vpmtmr->baseval + (delta / vpmtmr->freq_sbt));\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/vmm/io/vrtc.c",
    "content": "/*-\n * Copyright (c) 2014, Neel Natu (neel@freebsd.org)\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice unmodified, this list of conditions, and the following\n *    disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <strings.h>\n#include <pthread.h>\n#include <errno.h>\n#include <assert.h>\n#include <mach/mach.h>\n#include <mach/clock.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/rtc.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vioapic.h>\n#include <xhyve/vmm/io/vrtc.h>\n\nstatic const u_char bin2bcd_data[] = {\n\t0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,\n\t0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,\n\t0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,\n\t0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,\n\t0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,\n\t0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,\n\t0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,\n\t0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,\n\t0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,\n\t0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99\n};\n\n/* Register layout of the RTC */\nstruct rtcdev {\n\tuint8_t sec;\n\tuint8_t alarm_sec;\n\tuint8_t min;\n\tuint8_t alarm_min;\n\tuint8_t hour;\n\tuint8_t alarm_hour;\n\tuint8_t day_of_week;\n\tuint8_t day_of_month;\n\tuint8_t month;\n\tuint8_t year;\n\tuint8_t reg_a;\n\tuint8_t reg_b;\n\tuint8_t reg_c;\n\tuint8_t reg_d;\n\tuint8_t nvram[36];\n\tuint8_t century;\n\tuint8_t nvram2[128 - 51];\n};\nCTASSERT(sizeof(struct rtcdev) == 128);\nCTASSERT(offsetof(struct rtcdev, century) == RTC_CENTURY);\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstruct vrtc {\n\tstruct vm *vm;\n\tpthread_mutex_t mtx;\n\tstruct callout callout;\n\tu_int addr; /* RTC register to read or write */\n\tsbintime_t base_uptime;\n\ttime_t base_rtctime;\n\tstruct rtcdev rtcdev;\n};\n\nstruct clocktime {\n\tint\tyear; /* year (4 digit year) */\n\tint\tmon; /* month (1 - 12) */\n\tint\tday; /* day (1 - 31) */\n\tint\thour; /* hour (0 - 23) */\n\tint\tmin; /* minute (0 - 59) */\n\tint\tsec; /* second (0 - 59) */\n\tint\tdow; /* day of week (0 - 6; 0 = Sunday) */\n\tlong nsec; /* nano seconds */\n};\n#pragma clang diagnostic pop\n\n#define\tVRTC_LOCK(vrtc) pthread_mutex_lock(&((vrtc)->mtx))\n#define\tVRTC_UNLOCK(vrtc) pthread_mutex_unlock(&((vrtc)->mtx))\n/*\n * RTC time is considered \"broken\" if:\n * - RTC updates are halted by the guest\n * - RTC date/time fields have invalid values\n */\n#define\tVRTC_BROKEN_TIME\t((time_t)-1)\n\n#define\tRTC_IRQ\t\t\t8\n#define\tRTCSB_BIN\t\t0x04\n#define\tRTCSB_ALL_INTRS\t\t(RTCSB_UINTR | RTCSB_AINTR | RTCSB_PINTR)\n#define\trtc_halted(vrtc)\t((vrtc->rtcdev.reg_b & RTCSB_HALT) != 0)\n#define\taintr_enabled(vrtc)\t(((vrtc)->rtcdev.reg_b & RTCSB_AINTR) != 0)\n#define\tpintr_enabled(vrtc)\t(((vrtc)->rtcdev.reg_b & RTCSB_PINTR) != 0)\n#define\tuintr_enabled(vrtc)\t(((vrtc)->rtcdev.reg_b & RTCSB_UINTR) != 0)\n\nstatic void vrtc_callout_handler(void *arg);\nstatic void vrtc_set_reg_c(struct vrtc *vrtc, uint8_t newval);\n\nstatic int rtc_flag_broken_time = 1;\nstatic clock_serv_t mach_clock;\n\n#define\tPOSIX_BASE_YEAR\t1970\n#define\tFEBRUARY 2\n#define SECDAY (24 * 60 * 60)\n#define\tdays_in_year(y) (leapyear(y) ? 366 : 365)\n#define\tdays_in_month(y, m) \\\n\t(month_days[(m) - 1] + (m == FEBRUARY ? leapyear(y) : 0))\n#define\tday_of_week(days) (((days) + 4) % 7)\n\nstatic const int month_days[12] = {\n\t31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31\n};\n\nstatic __inline int\nleapyear(int year)\n{\n\tint rv = 0;\n\n\tif ((year & 3) == 0) {\n\t\trv = 1;\n\t\tif ((year % 100) == 0) {\n\t\t\trv = 0;\n\t\t\tif ((year % 400) == 0)\n\t\t\t\trv = 1;\n\t\t}\n\t}\n\treturn (rv);\n}\n\nstatic int\nclock_ct_to_ts(struct clocktime *ct, struct timespec *ts)\n{\n\tint i, year, days;\n\n\tyear = ct->year;\n\n\t/* Sanity checks. */\n\tif (ct->mon < 1 || ct->mon > 12 || ct->day < 1 ||\n\t    ct->day > days_in_month(year, ct->mon) ||\n\t    ct->hour > 23 ||  ct->min > 59 || ct->sec > 59 ||\n\t    (year > 2037 && sizeof(time_t) == 4)) {\t/* time_t overflow */\n\t\treturn (EINVAL);\n\t}\n\n\t/*\n\t * Compute days since start of time\n\t * First from years, then from months.\n\t */\n\tdays = 0;\n\tfor (i = POSIX_BASE_YEAR; i < year; i++)\n\t\tdays += days_in_year(i);\n\n\t/* Months */\n\tfor (i = 1; i < ct->mon; i++)\n\t  \tdays += days_in_month(year, i);\n\tdays += (ct->day - 1);\n\n\tts->tv_sec = (((time_t)days * 24 + ct->hour) * 60 + ct->min) * 60 +\n\t    ct->sec;\n\tts->tv_nsec = ct->nsec;\n\n\treturn (0);\n}\n\nstatic void\nclock_ts_to_ct(struct timespec *ts, struct clocktime *ct)\n{\n\tint i, year, days;\n\ttime_t rsec;\t/* remainder seconds */\n\ttime_t secs;\n\n\tsecs = ts->tv_sec;\n\tdays = (int) (secs / SECDAY);\n\trsec = secs % SECDAY;\n\n\tct->dow = day_of_week(days);\n\n\t/* Subtract out whole years, counting them in i. */\n\tfor (year = POSIX_BASE_YEAR; days >= days_in_year(year); year++)\n\t\tdays -= days_in_year(year);\n\tct->year = year;\n\n\t/* Subtract out whole months, counting them in i. */\n\tfor (i = 1; days >= days_in_month(year, i); i++)\n\t\tdays -= days_in_month(year, i);\n\tct->mon = i;\n\n\t/* Days are what is left over (+1) from all that. */\n\tct->day = days + 1;\n\n\t/* Hours, minutes, seconds are easy */\n\tct->hour = (int) (rsec / 3600);\n\trsec = rsec % 3600;\n\tct->min  = (int) (rsec / 60);\n\trsec = rsec % 60;\n\tct->sec  = (int) rsec;\n\tct->nsec = ts->tv_nsec;\n}\n\nstatic __inline bool\ndivider_enabled(int reg_a)\n{\n\t/*\n\t * The RTC is counting only when dividers are not held in reset.\n\t */\n\treturn ((reg_a & 0x70) == 0x20);\n}\n\nstatic __inline bool\nupdate_enabled(struct vrtc *vrtc)\n{\n\t/*\n\t * RTC date/time can be updated only if:\n\t * - divider is not held in reset\n\t * - guest has not disabled updates\n\t * - the date/time fields have valid contents\n\t */\n\tif (!divider_enabled(vrtc->rtcdev.reg_a))\n\t\treturn (false);\n\n\tif (rtc_halted(vrtc))\n\t\treturn (false);\n\n\tif (vrtc->base_rtctime == VRTC_BROKEN_TIME)\n\t\treturn (false);\n\n\treturn (true);\n}\n\nstatic time_t\nvrtc_curtime(struct vrtc *vrtc, sbintime_t *basetime)\n{\n\tsbintime_t now, delta;\n\ttime_t t, secs;\n\n\tt = vrtc->base_rtctime;\n\t*basetime = vrtc->base_uptime;\n\tif (update_enabled(vrtc)) {\n\t\tnow = sbinuptime();\n\t\tdelta = now - vrtc->base_uptime;\n\t\tKASSERT(delta >= 0, (\"vrtc_curtime: uptime went backwards: \"\n\t\t    \"%#llx to %#llx\", vrtc->base_uptime, now));\n\t\tsecs = delta / SBT_1S;\n\t\tt += secs;\n\t\t*basetime += secs * SBT_1S;\n\t}\n\treturn (t);\n}\n\nstatic __inline uint8_t\nrtcset(struct rtcdev *rtc, int val)\n{\n\n\tKASSERT(val >= 0 && val < 100, (\"%s: invalid bin2bcd index %d\",\n\t    __func__, val));\n\n\treturn ((uint8_t) ((rtc->reg_b & RTCSB_BIN) ? val : bin2bcd_data[val]));\n}\n\nstatic void\nsecs_to_rtc(time_t rtctime, struct vrtc *vrtc, int force_update)\n{\n\tmach_timespec_t mts;\n\tstruct clocktime ct;\n\tstruct timespec ts;\n\tstruct rtcdev *rtc;\n\tint hour;\n\n\tif (rtctime < 0) {\n\t\tKASSERT(rtctime == VRTC_BROKEN_TIME,\n\t\t    (\"%s: invalid vrtc time %#lx\", __func__, rtctime));\n\t\treturn;\n\t}\n\n\t/*\n\t * If the RTC is halted then the guest has \"ownership\" of the\n\t * date/time fields. Don't update the RTC date/time fields in\n\t * this case (unless forced).\n\t */\n\tif (rtc_halted(vrtc) && !force_update)\n\t\treturn;\n\n\tclock_get_time(mach_clock, &mts);\n\tts.tv_sec = mts.tv_sec;\n\tts.tv_nsec = mts.tv_nsec;\n\n\tclock_ts_to_ct(&ts, &ct);\n\n\tKASSERT(ct.sec >= 0 && ct.sec <= 59, (\"invalid clocktime sec %d\",\n\t    ct.sec));\n\tKASSERT(ct.min >= 0 && ct.min <= 59, (\"invalid clocktime min %d\",\n\t    ct.min));\n\tKASSERT(ct.hour >= 0 && ct.hour <= 23, (\"invalid clocktime hour %d\",\n\t    ct.hour));\n\tKASSERT(ct.dow >= 0 && ct.dow <= 6, (\"invalid clocktime wday %d\",\n\t    ct.dow));\n\tKASSERT(ct.day >= 1 && ct.day <= 31, (\"invalid clocktime mday %d\",\n\t    ct.day));\n\tKASSERT(ct.mon >= 1 && ct.mon <= 12, (\"invalid clocktime month %d\",\n\t    ct.mon));\n\tKASSERT(ct.year >= 1900, (\"invalid clocktime year %d\", ct.year));\n\n\trtc = &vrtc->rtcdev;\n\trtc->sec = rtcset(rtc, ct.sec);\n\trtc->min = rtcset(rtc, ct.min);\n\n\tif (rtc->reg_b & RTCSB_24HR) {\n\t\thour = ct.hour;\n\t} else {\n\t\t/*\n\t\t * Convert to the 12-hour format.\n\t\t */\n\t\tswitch (ct.hour) {\n\t\tcase 0:\t\t\t/* 12 AM */\n\t\tcase 12:\t\t/* 12 PM */\n\t\t\thour = 12;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t/*\n\t\t\t * The remaining 'ct.hour' values are interpreted as:\n\t\t\t * [1  - 11] ->  1 - 11 AM\n\t\t\t * [13 - 23] ->  1 - 11 PM\n\t\t\t */\n\t\t\thour = ct.hour % 12;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\trtc->hour = rtcset(rtc, hour);\n\n\tif ((rtc->reg_b & RTCSB_24HR) == 0 && ct.hour >= 12)\n\t\trtc->hour |= 0x80;\t    /* set MSB to indicate PM */\n\n\trtc->day_of_week = rtcset(rtc, ct.dow + 1);\n\trtc->day_of_month = rtcset(rtc, ct.day);\n\trtc->month = rtcset(rtc, ct.mon);\n\trtc->year = rtcset(rtc, ct.year % 100);\n\trtc->century = rtcset(rtc, ct.year / 100);\n}\n\nstatic int\nrtcget(struct rtcdev *rtc, int val, int *retval)\n{\n\tuint8_t upper, lower;\n\n\tif (rtc->reg_b & RTCSB_BIN) {\n\t\t*retval = val;\n\t\treturn (0);\n\t}\n\n\tlower = val & 0xf;\n\tupper = (val >> 4) & 0xf;\n\n\tif (lower > 9 || upper > 9)\n\t\treturn (-1);\n\n\t*retval = upper * 10 + lower;\n\treturn (0);\n}\n\nstatic time_t\nrtc_to_secs(struct vrtc *vrtc)\n{\n\tstruct clocktime ct;\n\tstruct timespec ts;\n\tstruct rtcdev *rtc;\n\tstruct vm *vm;\n\tint century, error, hour, pm, year;\n\n\tvm = vrtc->vm;\n\trtc = &vrtc->rtcdev;\n\n\tbzero(&ct, sizeof(struct clocktime));\n\n\terror = rtcget(rtc, rtc->sec, &ct.sec);\n\tif (error || ct.sec < 0 || ct.sec > 59) {\n\t\tVM_CTR2(vm, \"Invalid RTC sec %#x/%d\", rtc->sec, ct.sec);\n\t\tgoto fail;\n\t}\n\n\terror = rtcget(rtc, rtc->min, &ct.min);\n\tif (error || ct.min < 0 || ct.min > 59) {\n\t\tVM_CTR2(vm, \"Invalid RTC min %#x/%d\", rtc->min, ct.min);\n\t\tgoto fail;\n\t}\n\n\tpm = 0;\n\thour = rtc->hour;\n\tif ((rtc->reg_b & RTCSB_24HR) == 0) {\n\t\tif (hour & 0x80) {\n\t\t\thour &= ~0x80;\n\t\t\tpm = 1;\n\t\t}\n\t}\n\terror = rtcget(rtc, hour, &ct.hour);\n\tif ((rtc->reg_b & RTCSB_24HR) == 0) {\n\t\tif (ct.hour >= 1 && ct.hour <= 12) {\n\t\t\t/*\n\t\t\t * Convert from 12-hour format to internal 24-hour\n\t\t\t * representation as follows:\n\t\t\t *\n\t\t\t *    12-hour format\t\tct.hour\n\t\t\t *\t12\tAM\t\t0\n\t\t\t *\t1 - 11\tAM\t\t1 - 11\n\t\t\t *\t12\tPM\t\t12\n\t\t\t *\t1 - 11\tPM\t\t13 - 23\n\t\t\t */\n\t\t\tif (ct.hour == 12)\n\t\t\t\tct.hour = 0;\n\t\t\tif (pm)\n\t\t\t\tct.hour += 12;\n\t\t} else {\n\t\t\tVM_CTR2(vm, \"Invalid RTC 12-hour format %#x/%d\",\n\t\t\t    rtc->hour, ct.hour);\n\t\t\tgoto fail;\n\t\t}\n\t}\n\n\tif (error || ct.hour < 0 || ct.hour > 23) {\n\t\tVM_CTR2(vm, \"Invalid RTC hour %#x/%d\", rtc->hour, ct.hour);\n\t\tgoto fail;\n\t}\n\n\t/*\n\t * Ignore 'rtc->dow' because some guests like Linux don't bother\n\t * setting it at all while others like OpenBSD/i386 set it incorrectly. \n\t *\n\t * clock_ct_to_ts() does not depend on 'ct.dow' anyways so ignore it.\n\t */\n\tct.dow = -1;\n\n\terror = rtcget(rtc, rtc->day_of_month, &ct.day);\n\tif (error || ct.day < 1 || ct.day > 31) {\n\t\tVM_CTR2(vm, \"Invalid RTC mday %#x/%d\", rtc->day_of_month,\n\t\t    ct.day);\n\t\tgoto fail;\n\t}\n\n\terror = rtcget(rtc, rtc->month, &ct.mon);\n\tif (error || ct.mon < 1 || ct.mon > 12) {\n\t\tVM_CTR2(vm, \"Invalid RTC month %#x/%d\", rtc->month, ct.mon);\n\t\tgoto fail;\n\t}\n\n\terror = rtcget(rtc, rtc->year, &year);\n\tif (error || year < 0 || year > 99) {\n\t\tVM_CTR2(vm, \"Invalid RTC year %#x/%d\", rtc->year, year);\n\t\tgoto fail;\n\t}\n\n\terror = rtcget(rtc, rtc->century, &century);\n\tct.year = century * 100 + year;\n\tif (error || ct.year < 1900) {\n\t\tVM_CTR2(vm, \"Invalid RTC century %#x/%d\", rtc->century,\n\t\t    ct.year);\n\t\tgoto fail;\n\t}\n\n\terror = clock_ct_to_ts(&ct, &ts);\n\tif (error || ts.tv_sec < 0) {\n\t\tVM_CTR3(vm, \"Invalid RTC clocktime.date %04d-%02d-%02d\",\n\t\t    ct.year, ct.mon, ct.day);\n\t\tVM_CTR3(vm, \"Invalid RTC clocktime.time %02d:%02d:%02d\",\n\t\t    ct.hour, ct.min, ct.sec);\n\t\tgoto fail;\n\t}\n\treturn (ts.tv_sec);\t\t/* success */\nfail:\n\t/*\n\t * Stop updating the RTC if the date/time fields programmed by\n\t * the guest are invalid.\n\t */\n\tVM_CTR0(vrtc->vm, \"Invalid RTC date/time programming detected\");\n\treturn (VRTC_BROKEN_TIME);\n}\n\nstatic int\nvrtc_time_update(struct vrtc *vrtc, time_t newtime, sbintime_t newbase)\n{\n\tstruct rtcdev *rtc;\n\tsbintime_t oldbase;\n\ttime_t oldtime;\n\tuint8_t alarm_sec, alarm_min, alarm_hour;\n\n\trtc = &vrtc->rtcdev;\n\talarm_sec = rtc->alarm_sec;\n\talarm_min = rtc->alarm_min;\n\talarm_hour = rtc->alarm_hour;\n\n\toldtime = vrtc->base_rtctime;\n\tVM_CTR2(vrtc->vm, \"Updating RTC secs from %#lx to %#lx\",\n\t    oldtime, newtime);\n\n\toldbase = vrtc->base_uptime;\n\tVM_CTR2(vrtc->vm, \"Updating RTC base uptime from %#llx to %#llx\",\n\t    oldbase, newbase);\n\tvrtc->base_uptime = newbase;\n\n\tif (newtime == oldtime)\n\t\treturn (0);\n\n\t/*\n\t * If 'newtime' indicates that RTC updates are disabled then just\n\t * record that and return. There is no need to do alarm interrupt\n\t * processing in this case.\n\t */\n\tif (newtime == VRTC_BROKEN_TIME) {\n\t\tvrtc->base_rtctime = VRTC_BROKEN_TIME;\n\t\treturn (0);\n\t}\n\n\t/*\n\t * Return an error if RTC updates are halted by the guest.\n\t */\n\tif (rtc_halted(vrtc)) {\n\t\tVM_CTR0(vrtc->vm, \"RTC update halted by guest\");\n\t\treturn (EBUSY);\n\t}\n\n\tdo {\n\t\t/*\n\t\t * If the alarm interrupt is enabled and 'oldtime' is valid\n\t\t * then visit all the seconds between 'oldtime' and 'newtime'\n\t\t * to check for the alarm condition.\n\t\t *\n\t\t * Otherwise move the RTC time forward directly to 'newtime'.\n\t\t */\n\t\tif (aintr_enabled(vrtc) && oldtime != VRTC_BROKEN_TIME)\n\t\t\tvrtc->base_rtctime++;\n\t\telse\n\t\t\tvrtc->base_rtctime = newtime;\n\n\t\tif (aintr_enabled(vrtc)) {\n\t\t\t/*\n\t\t\t * Update the RTC date/time fields before checking\n\t\t\t * if the alarm conditions are satisfied.\n\t\t\t */\n\t\t\tsecs_to_rtc(vrtc->base_rtctime, vrtc, 0);\n\n\t\t\tif ((alarm_sec >= 0xC0 || alarm_sec == rtc->sec) &&\n\t\t\t    (alarm_min >= 0xC0 || alarm_min == rtc->min) &&\n\t\t\t    (alarm_hour >= 0xC0 || alarm_hour == rtc->hour)) {\n\t\t\t\tvrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_ALARM);\n\t\t\t}\n\t\t}\n\t} while (vrtc->base_rtctime != newtime);\n\n\tif (uintr_enabled(vrtc))\n\t\tvrtc_set_reg_c(vrtc, rtc->reg_c | RTCIR_UPDATE);\n\n\treturn (0);\n}\n\nstatic sbintime_t\nvrtc_freq(struct vrtc *vrtc)\n{\n\tint ratesel;\n\n\tstatic sbintime_t pf[16] = {\n\t\t0,\n\t\tSBT_1S / 256,\n\t\tSBT_1S / 128,\n\t\tSBT_1S / 8192,\n\t\tSBT_1S / 4096,\n\t\tSBT_1S / 2048,\n\t\tSBT_1S / 1024,\n\t\tSBT_1S / 512,\n\t\tSBT_1S / 256,\n\t\tSBT_1S / 128,\n\t\tSBT_1S / 64,\n\t\tSBT_1S / 32,\n\t\tSBT_1S / 16,\n\t\tSBT_1S / 8,\n\t\tSBT_1S / 4,\n\t\tSBT_1S / 2,\n\t};\n\n\t/*\n\t * If both periodic and alarm interrupts are enabled then use the\n\t * periodic frequency to drive the callout. The minimum periodic\n\t * frequency (2 Hz) is higher than the alarm frequency (1 Hz) so\n\t * piggyback the alarm on top of it. The same argument applies to\n\t * the update interrupt.\n\t */\n\tif (pintr_enabled(vrtc) && divider_enabled(vrtc->rtcdev.reg_a)) {\n\t\tratesel = vrtc->rtcdev.reg_a & 0xf;\n\t\treturn (pf[ratesel]);\n\t} else if (aintr_enabled(vrtc) && update_enabled(vrtc)) {\n\t\treturn (SBT_1S);\n\t} else if (uintr_enabled(vrtc) && update_enabled(vrtc)) {\n\t\treturn (SBT_1S);\n\t} else {\n\t\treturn (0);\n\t}\n}\n\nstatic void\nvrtc_callout_reset(struct vrtc *vrtc, sbintime_t freqsbt)\n{\n\tif (freqsbt == 0) {\n\t\tif (callout_active(&vrtc->callout)) {\n\t\t\tVM_CTR0(vrtc->vm, \"RTC callout stopped\");\n\t\t\tcallout_stop(&vrtc->callout);\n\t\t}\n\t\treturn;\n\t}\n\tVM_CTR1(vrtc->vm, \"RTC callout frequency %lld hz\", SBT_1S / freqsbt);\n\tcallout_reset_sbt(&vrtc->callout, freqsbt, 0, vrtc_callout_handler,\n\t    vrtc, 0);\n}\n\nstatic void\nvrtc_callout_handler(void *arg)\n{\n\tstruct vrtc *vrtc = arg;\n\tsbintime_t freqsbt, basetime;\n\ttime_t rtctime;\n\tint error;\n\n\tVM_CTR0(vrtc->vm, \"vrtc callout fired\");\n\n\tVRTC_LOCK(vrtc);\n\tif (callout_pending(&vrtc->callout))\t/* callout was reset */\n\t\tgoto done;\n\n\tif (!callout_active(&vrtc->callout))\t/* callout was stopped */\n\t\tgoto done;\n\n\tcallout_deactivate(&vrtc->callout);\n\n\tKASSERT((vrtc->rtcdev.reg_b & RTCSB_ALL_INTRS) != 0,\n\t    (\"gratuitous vrtc callout\"));\n\n\tif (pintr_enabled(vrtc))\n\t\tvrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c | RTCIR_PERIOD);\n\n\tif (aintr_enabled(vrtc) || uintr_enabled(vrtc)) {\n\t\trtctime = vrtc_curtime(vrtc, &basetime);\n\t\terror = vrtc_time_update(vrtc, rtctime, basetime);\n\t\tKASSERT(error == 0, (\"%s: vrtc_time_update error %d\",\n\t\t    __func__, error));\n\t}\n\n\tfreqsbt = vrtc_freq(vrtc);\n\tKASSERT(freqsbt != 0, (\"%s: vrtc frequency cannot be zero\", __func__));\n\tvrtc_callout_reset(vrtc, freqsbt);\ndone:\n\tVRTC_UNLOCK(vrtc);\n}\n\nstatic __inline void\nvrtc_callout_check(struct vrtc *vrtc, sbintime_t freq)\n{\n\tint active;\n\n\tactive = callout_active(&vrtc->callout) ? 1 : 0;\n\tKASSERT((freq == 0 && !active) || (freq != 0 && active),\n\t    (\"vrtc callout %s with frequency %#llx\",\n\t    active ? \"active\" : \"inactive\", freq));\n}\n\nstatic void\nvrtc_set_reg_c(struct vrtc *vrtc, uint8_t newval)\n{\n\tstruct rtcdev *rtc;\n\tint oldirqf, newirqf;\n\tuint8_t oldval, changed;\n\n\trtc = &vrtc->rtcdev;\n\tnewval &= RTCIR_ALARM | RTCIR_PERIOD | RTCIR_UPDATE;\n\n\toldirqf = rtc->reg_c & RTCIR_INT;\n\tif ((aintr_enabled(vrtc) && (newval & RTCIR_ALARM) != 0) ||\n\t    (pintr_enabled(vrtc) && (newval & RTCIR_PERIOD) != 0) ||\n\t    (uintr_enabled(vrtc) && (newval & RTCIR_UPDATE) != 0)) {\n\t\tnewirqf = RTCIR_INT;\n\t} else {\n\t\tnewirqf = 0;\n\t}\n\n\toldval = rtc->reg_c;\n\trtc->reg_c = (uint8_t) (newirqf | newval);\n\tchanged = oldval ^ rtc->reg_c;\n\tif (changed) {\n\t\tVM_CTR2(vrtc->vm, \"RTC reg_c changed from %#x to %#x\",\n\t\t    oldval, rtc->reg_c);\n\t}\n\n\tif (!oldirqf && newirqf) {\n\t\tVM_CTR1(vrtc->vm, \"RTC irq %d asserted\", RTC_IRQ);\n\t\tvatpic_pulse_irq(vrtc->vm, RTC_IRQ);\n\t\tvioapic_pulse_irq(vrtc->vm, RTC_IRQ);\n\t} else if (oldirqf && !newirqf) {\n\t\tVM_CTR1(vrtc->vm, \"RTC irq %d deasserted\", RTC_IRQ);\n\t}\n}\n\nstatic int\nvrtc_set_reg_b(struct vrtc *vrtc, uint8_t newval)\n{\n\tstruct rtcdev *rtc;\n\tsbintime_t oldfreq, newfreq, basetime;\n\ttime_t curtime, rtctime;\n\tint error;\n\tuint8_t oldval, changed;\n\n\trtc = &vrtc->rtcdev;\n\toldval = rtc->reg_b;\n\toldfreq = vrtc_freq(vrtc);\n\n\trtc->reg_b = newval;\n\tchanged = oldval ^ newval;\n\tif (changed) {\n\t\tVM_CTR2(vrtc->vm, \"RTC reg_b changed from %#x to %#x\",\n\t\t    oldval, newval);\n\t}\n\n\tif (changed & RTCSB_HALT) {\n\t\tif ((newval & RTCSB_HALT) == 0) {\n\t\t\trtctime = rtc_to_secs(vrtc);\n\t\t\tbasetime = sbinuptime();\n\t\t\tif (rtctime == VRTC_BROKEN_TIME) {\n\t\t\t\tif (rtc_flag_broken_time)\n\t\t\t\t\treturn (-1);\n\t\t\t}\n\t\t} else {\n\t\t\tcurtime = vrtc_curtime(vrtc, &basetime);\n\t\t\tKASSERT(curtime == vrtc->base_rtctime, (\"%s: mismatch \"\n\t\t\t    \"between vrtc basetime (%#lx) and curtime (%#lx)\",\n\t\t\t    __func__, vrtc->base_rtctime, curtime));\n\n\t\t\t/*\n\t\t\t * Force a refresh of the RTC date/time fields so\n\t\t\t * they reflect the time right before the guest set\n\t\t\t * the HALT bit.\n\t\t\t */\n\t\t\tsecs_to_rtc(curtime, vrtc, 1);\n\n\t\t\t/*\n\t\t\t * Updates are halted so mark 'base_rtctime' to denote\n\t\t\t * that the RTC date/time is in flux.\n\t\t\t */\n\t\t\trtctime = VRTC_BROKEN_TIME;\n\t\t\trtc->reg_b &= ~RTCSB_UINTR;\n\t\t}\n\t\terror = vrtc_time_update(vrtc, rtctime, basetime);\n\t\tKASSERT(error == 0, (\"vrtc_time_update error %d\", error));\n\t}\n\n\t/*\n\t * Side effect of changes to the interrupt enable bits.\n\t */\n\tif (changed & RTCSB_ALL_INTRS)\n\t\tvrtc_set_reg_c(vrtc, vrtc->rtcdev.reg_c);\n\n\t/*\n\t * Change the callout frequency if it has changed.\n\t */\n\tnewfreq = vrtc_freq(vrtc);\n\tif (newfreq != oldfreq)\n\t\tvrtc_callout_reset(vrtc, newfreq);\n\telse\n\t\tvrtc_callout_check(vrtc, newfreq);\n\n\t/*\n\t * The side effect of bits that control the RTC date/time format\n\t * is handled lazily when those fields are actually read.\n\t */\n\treturn (0);\n}\n\nstatic void\nvrtc_set_reg_a(struct vrtc *vrtc, uint8_t newval)\n{\n\tsbintime_t oldfreq, newfreq;\n\tuint8_t oldval, changed;\n\n\tnewval &= ~RTCSA_TUP;\n\toldval = vrtc->rtcdev.reg_a;\n\toldfreq = vrtc_freq(vrtc);\n\n\tif (divider_enabled(oldval) && !divider_enabled(newval)) {\n\t\tVM_CTR2(vrtc->vm, \"RTC divider held in reset at %#lx/%#llx\",\n\t\t    vrtc->base_rtctime, vrtc->base_uptime);\n\t} else if (!divider_enabled(oldval) && divider_enabled(newval)) {\n\t\t/*\n\t\t * If the dividers are coming out of reset then update\n\t\t * 'base_uptime' before this happens. This is done to\n\t\t * maintain the illusion that the RTC date/time was frozen\n\t\t * while the dividers were disabled.\n\t\t */\n\t\tvrtc->base_uptime = sbinuptime();\n\t\tVM_CTR2(vrtc->vm, \"RTC divider out of reset at %#lx/%#llx\",\n\t\t    vrtc->base_rtctime, vrtc->base_uptime);\n\t} else {\n\t\t/* NOTHING */\n\t}\n\n\tvrtc->rtcdev.reg_a = newval;\n\tchanged = oldval ^ newval;\n\tif (changed) {\n\t\tVM_CTR2(vrtc->vm, \"RTC reg_a changed from %#x to %#x\",\n\t\t    oldval, newval);\n\t}\n\n\t/*\n\t * Side effect of changes to rate select and divider enable bits.\n\t */\n\tnewfreq = vrtc_freq(vrtc);\n\tif (newfreq != oldfreq)\n\t\tvrtc_callout_reset(vrtc, newfreq);\n\telse\n\t\tvrtc_callout_check(vrtc, newfreq);\n}\n\nint\nvrtc_set_time(struct vm *vm, time_t secs)\n{\n\tstruct vrtc *vrtc;\n\tint error;\n\n\tvrtc = vm_rtc(vm);\n\tVRTC_LOCK(vrtc);\n\terror = vrtc_time_update(vrtc, secs, sbinuptime());\n\tVRTC_UNLOCK(vrtc);\n\n\tif (error) {\n\t\tVM_CTR2(vrtc->vm, \"Error %d setting RTC time to %#lx\", error,\n\t\t    secs);\n\t} else {\n\t\tVM_CTR1(vrtc->vm, \"RTC time set to %#lx\", secs);\n\t}\n\n\treturn (error);\n}\n\ntime_t\nvrtc_get_time(struct vm *vm)\n{\n\tstruct vrtc *vrtc;\n\tsbintime_t basetime;\n\ttime_t t;\n\n\tvrtc = vm_rtc(vm);\n\tVRTC_LOCK(vrtc);\n\tt = vrtc_curtime(vrtc, &basetime);\n\tVRTC_UNLOCK(vrtc);\n\n\treturn (t);\n}\n\nint\nvrtc_nvram_write(struct vm *vm, int offset, uint8_t value)\n{\n\tstruct vrtc *vrtc;\n\tuint8_t *ptr;\n\n\tvrtc = vm_rtc(vm);\n\n\t/*\n\t * Don't allow writes to RTC control registers or the date/time fields.\n\t */\n\tif (((unsigned long) offset) < offsetof(struct rtcdev, nvram) ||\n\t    offset == RTC_CENTURY ||\n\t    ((unsigned long) offset) >= sizeof(struct rtcdev))\n\t{\n\t\tVM_CTR1(vrtc->vm, \"RTC nvram write to invalid offset %d\",\n\t\t    offset);\n\t\treturn (EINVAL);\n\t}\n\n\tVRTC_LOCK(vrtc);\n\tptr = (uint8_t *)(&vrtc->rtcdev);\n\tptr[offset] = value;\n\tVM_CTR2(vrtc->vm, \"RTC nvram write %#x to offset %#x\", value, offset);\n\tVRTC_UNLOCK(vrtc);\n\n\treturn (0);\n}\n\nint\nvrtc_nvram_read(struct vm *vm, int offset, uint8_t *retval)\n{\n\tstruct vrtc *vrtc;\n\tsbintime_t basetime;\n\ttime_t curtime;\n\tuint8_t *ptr;\n\n\t/*\n\t * Allow all offsets in the RTC to be read.\n\t */\n\tif (offset < 0 || ((unsigned long) offset) >= sizeof(struct rtcdev))\n\t\treturn (EINVAL);\n\n\tvrtc = vm_rtc(vm);\n\tVRTC_LOCK(vrtc);\n\n\t/*\n\t * Update RTC date/time fields if necessary.\n\t */\n\tif (offset < 10 || offset == RTC_CENTURY) {\n\t\tcurtime = vrtc_curtime(vrtc, &basetime);\n\t\tsecs_to_rtc(curtime, vrtc, 0);\n\t}\n\n\tptr = (uint8_t *)(&vrtc->rtcdev);\n\t*retval = ptr[offset];\n\n\tVRTC_UNLOCK(vrtc);\n\treturn (0);\n}\n\nint\nvrtc_addr_handler(struct vm *vm, UNUSED int vcpuid, bool in, UNUSED int port,\n\tint bytes, uint32_t *val)\n{\n\tstruct vrtc *vrtc;\n\n\tvrtc = vm_rtc(vm);\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tif (in) {\n\t\t*val = 0xff;\n\t\treturn (0);\n\t}\n\n\tVRTC_LOCK(vrtc);\n\tvrtc->addr = *val & 0x7f;\n\tVRTC_UNLOCK(vrtc);\n\n\treturn (0);\n}\n\nint\nvrtc_data_handler(struct vm *vm, int vcpuid, bool in, UNUSED int port,\n\tint bytes, uint32_t *val)\n{\n\tstruct vrtc *vrtc;\n\tstruct rtcdev *rtc;\n\tsbintime_t basetime;\n\ttime_t curtime;\n\tint error, offset;\n\n\tvrtc = vm_rtc(vm);\n\trtc = &vrtc->rtcdev;\n\n\tif (bytes != 1)\n\t\treturn (-1);\n\n\tVRTC_LOCK(vrtc);\n\toffset = (int) vrtc->addr;\n\tif (((unsigned long) offset) >= sizeof(struct rtcdev)) {\n\t\tVRTC_UNLOCK(vrtc);\n\t\treturn (-1);\n\t}\n\n\terror = 0;\n\tcurtime = vrtc_curtime(vrtc, &basetime);\n\tvrtc_time_update(vrtc, curtime, basetime);\n\n\t/*\n\t * Update RTC date/time fields if necessary.\n\t *\n\t * This is not just for reads of the RTC. The side-effect of writing\n\t * the century byte requires other RTC date/time fields (e.g. sec)\n\t * to be updated here.\n\t */\n\tif (offset < 10 || offset == RTC_CENTURY)\n\t\tsecs_to_rtc(curtime, vrtc, 0);\n\n\tif (in) {\n\t\tif (offset == 12) {\n\t\t\t/*\n\t\t\t * XXX\n\t\t\t * reg_c interrupt flags are updated only if the\n\t\t\t * corresponding interrupt enable bit in reg_b is set.\n\t\t\t */\n\t\t\t*val = vrtc->rtcdev.reg_c;\n\t\t\tvrtc_set_reg_c(vrtc, 0);\n\t\t} else {\n\t\t\t*val = *((uint8_t *)rtc + offset);\n\t\t}\n\t\tVCPU_CTR2(vm, vcpuid, \"Read value %#x from RTC offset %#x\",\n\t\t    *val, offset);\n\t} else {\n\t\tswitch (offset) {\n\t\tcase 10:\n\t\t\tVCPU_CTR1(vm, vcpuid, \"RTC reg_a set to %#x\", *val);\n\t\t\tvrtc_set_reg_a(vrtc, ((uint8_t) *val));\n\t\t\tbreak;\n\t\tcase 11:\n\t\t\tVCPU_CTR1(vm, vcpuid, \"RTC reg_b set to %#x\", *val);\n\t\t\terror = vrtc_set_reg_b(vrtc, ((uint8_t) *val));\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\tVCPU_CTR1(vm, vcpuid, \"RTC reg_c set to %#x (ignored)\",\n\t\t\t    *val);\n\t\t\tbreak;\n\t\tcase 13:\n\t\t\tVCPU_CTR1(vm, vcpuid, \"RTC reg_d set to %#x (ignored)\",\n\t\t\t    *val);\n\t\t\tbreak;\n\t\tcase 0:\n\t\t\t/*\n\t\t\t * High order bit of 'seconds' is readonly.\n\t\t\t */\n\t\t\t*val &= 0x7f;\n\t\t\t/* FALLTHRU */\n\t\tdefault:\n\t\t\tVCPU_CTR2(vm, vcpuid, \"RTC offset %#x set to %#x\",\n\t\t\t    offset, *val);\n\t\t\t*((uint8_t *)rtc + offset) = ((uint8_t) *val);\n\t\t\tbreak;\n\t\t}\n\n\t\t/*\n\t\t * XXX some guests (e.g. OpenBSD) write the century byte\n\t\t * outside of RTCSB_HALT so re-calculate the RTC date/time.\n\t\t */\n\t\tif (offset == RTC_CENTURY && !rtc_halted(vrtc)) {\n\t\t\tcurtime = rtc_to_secs(vrtc);\n\t\t\terror = vrtc_time_update(vrtc, curtime, sbinuptime());\n\t\t\tKASSERT(!error, (\"vrtc_time_update error %d\", error));\n\t\t\tif (curtime == VRTC_BROKEN_TIME && rtc_flag_broken_time)\n\t\t\t\terror = -1;\n\t\t}\n\t}\n\tVRTC_UNLOCK(vrtc);\n\treturn (error);\n}\n\nvoid\nvrtc_reset(struct vrtc *vrtc)\n{\n\tstruct rtcdev *rtc;\n\n\tVRTC_LOCK(vrtc);\n\n\trtc = &vrtc->rtcdev;\n\tvrtc_set_reg_b(vrtc, rtc->reg_b & ~(RTCSB_ALL_INTRS | RTCSB_SQWE));\n\tvrtc_set_reg_c(vrtc, 0);\n\tKASSERT(!callout_active(&vrtc->callout), (\"rtc callout still active\"));\n\n\tVRTC_UNLOCK(vrtc);\n}\n\nstruct vrtc *\nvrtc_init(struct vm *vm)\n{\n\tstruct vrtc *vrtc;\n\tstruct rtcdev *rtc;\n\ttime_t curtime;\n\n\tvrtc = malloc(sizeof(struct vrtc));\n\tassert(vrtc);\n\tbzero(vrtc, sizeof(struct vrtc));\n\tvrtc->vm = vm;\n\t\n\tpthread_mutex_init(&vrtc->mtx, NULL);\n\n\thost_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &mach_clock);\n\n\tcallout_init(&vrtc->callout, 1);\n\n\t/* Allow dividers to keep time but disable everything else */\n\trtc = &vrtc->rtcdev;\n\trtc->reg_a = 0x20;\n\trtc->reg_b = RTCSB_24HR;\n\trtc->reg_c = 0;\n\trtc->reg_d = RTCSD_PWR;\n\n\t/* Reset the index register to a safe value. */\n\tvrtc->addr = RTC_STATUSD;\n\n\t/*\n\t * Initialize RTC time to 00:00:00 Jan 1, 1970.\n\t */\n\tcurtime = 0;\n\n\tVRTC_LOCK(vrtc);\n\tvrtc->base_rtctime = VRTC_BROKEN_TIME;\n\tvrtc_time_update(vrtc, curtime, sbinuptime());\n\tsecs_to_rtc(curtime, vrtc, 0);\n\tVRTC_UNLOCK(vrtc);\n\n\treturn (vrtc);\n}\n\nvoid\nvrtc_cleanup(struct vrtc *vrtc)\n{\n\tcallout_drain(&vrtc->callout);\n\tmach_port_deallocate(mach_task_self(), mach_clock);\n\tfree(vrtc);\n}\n"
  },
  {
    "path": "src/vmm/vmm.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n#include <errno.h>\n#include <pthread.h>\n#include <assert.h>\n#include <xhyve/lock.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/cpuset.h>\n#include <xhyve/support/psl.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/support/apicreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/vmm_mem.h>\n#include <xhyve/vmm/vmm_ioport.h>\n#include <xhyve/vmm/vmm_instruction_emul.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/vmm_host.h>\n#include <xhyve/vmm/vmm_stat.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vatpit.h>\n#include <xhyve/vmm/io/vioapic.h>\n#include <xhyve/vmm/io/vlapic.h>\n#include <xhyve/vmm/io/vhpet.h>\n#include <xhyve/vmm/io/vpmtmr.h>\n#include <xhyve/vmm/io/vrtc.h>\n\nstruct vlapic;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\n/*\n * Initialization:\n * (a) allocated when vcpu is created\n * (i) initialized when vcpu is created and when it is reinitialized\n * (o) initialized the first time the vcpu is created\n * (x) initialized before use\n */\nstruct vcpu {\n\txhyve_lock_t lock; /* (o) protects 'state' */\n\tpthread_mutex_t state_sleep_mtx;\n\tpthread_cond_t state_sleep_cnd;\n\tpthread_mutex_t vcpu_sleep_mtx;\n\tpthread_cond_t vcpu_sleep_cnd;\n\tenum vcpu_state state; /* (o) vcpu state */\n\tstruct vlapic *vlapic; /* (i) APIC device model */\n\tenum x2apic_state x2apic_state; /* (i) APIC mode */\n\tuint64_t exitintinfo; /* (i) events pending at VM exit */\n\tint nmi_pending; /* (i) NMI pending */\n\tint extint_pending; /* (i) INTR pending */\n\tint exception_pending; /* (i) exception pending */\n\tint exc_vector; /* (x) exception collateral */\n\tint exc_errcode_valid;\n\tuint32_t exc_errcode;\n\tuint64_t guest_xcr0; /* (i) guest %xcr0 register */\n\tvoid *stats; /* (a,i) statistics */\n\tstruct vm_exit exitinfo; /* (x) exit reason and collateral */\n\tuint64_t nextrip; /* (x) next instruction to execute */\n};\n\n#define vcpu_lock_init(v) XHYVE_LOCK_INIT(v, lock)\n#define vcpu_lock(v) XHYVE_LOCK(v, lock)\n#define vcpu_unlock(v) XHYVE_UNLOCK(v, lock)\n\nstruct mem_seg {\n\tuint64_t gpa;\n\tsize_t len;\n\tvoid *object;\n};\n\n#define\tVM_MAX_MEMORY_SEGMENTS\t4\n\n/*\n * Initialization:\n * (o) initialized the first time the VM is created\n * (i) initialized when VM is created and when it is reinitialized\n * (x) initialized before use\n */\nstruct vm {\n\tvoid *cookie; /* (i) cpu-specific data */\n\tstruct vhpet *vhpet; /* (i) virtual HPET */\n\tstruct vioapic *vioapic; /* (i) virtual ioapic */\n\tstruct vatpic *vatpic; /* (i) virtual atpic */\n\tstruct vatpit *vatpit; /* (i) virtual atpit */\n\tstruct vpmtmr *vpmtmr; /* (i) virtual ACPI PM timer */\n\tstruct vrtc *vrtc; /* (o) virtual RTC */\n\tvolatile cpuset_t active_cpus; /* (i) active vcpus */\n\tint suspend; /* (i) stop VM execution */\n\tvolatile cpuset_t suspended_cpus; /* (i) suspended vcpus */\n\tvolatile cpuset_t halted_cpus; /* (x) cpus in a hard halt */\n\tcpuset_t rendezvous_req_cpus; /* (x) rendezvous requested */\n\tcpuset_t rendezvous_done_cpus; /* (x) rendezvous finished */\n\tvoid *rendezvous_arg; /* (x) rendezvous func/arg */\n\tvm_rendezvous_func_t rendezvous_func;\n\tpthread_mutex_t rendezvous_mtx; /* (o) rendezvous lock */\n\tpthread_cond_t rendezvous_sleep_cnd;\n\tint num_mem_segs; /* (o) guest memory segments */\n\tstruct mem_seg mem_segs[VM_MAX_MEMORY_SEGMENTS];\n\tstruct vcpu vcpu[VM_MAXCPU]; /* (i) guest vcpus */\n};\n#pragma clang diagnostic pop\n\nstatic int vmm_initialized;\n\nstatic struct vmm_ops *ops;\n\n#define\tVMM_INIT() \\\n\t(*ops->init)()\n#define\tVMM_CLEANUP() \\\n\t(*ops->cleanup)()\n#define\tVM_INIT(vmi) \\\n\t(*ops->vm_init)(vmi)\n#define\tVCPU_INIT(vmi, vcpu) \\\n\t(*ops->vcpu_init)(vmi, vcpu)\n#define\tVMRUN(vmi, vcpu, rip, rptr, sptr) \\\n\t(*ops->vmrun)(vmi, vcpu, rip, rptr, sptr)\n#define\tVM_CLEANUP(vmi) \\\n\t(*ops->vm_cleanup)(vmi)\n#define\tVCPU_CLEANUP(vmi, vcpu) \\\n\t(*ops->vcpu_cleanup)(vmi, vcpu)\n#define\tVMGETREG(vmi, vcpu, num, retval) \\\n\t(*ops->vmgetreg)(vmi, vcpu, num, retval)\n#define\tVMSETREG(vmi, vcpu, num, val) \\\n\t(*ops->vmsetreg)(vmi, vcpu, num, val)\n#define\tVMGETDESC(vmi, vcpu, num, desc) \\\n\t(*ops->vmgetdesc)(vmi, vcpu, num, desc)\n#define\tVMSETDESC(vmi, vcpu, num, desc) \\\n\t(*ops->vmsetdesc)(vmi, vcpu, num, desc)\n#define\tVMGETCAP(vmi, vcpu, num, retval) \\\n\t(*ops->vmgetcap)(vmi, vcpu, num, retval)\n#define\tVMSETCAP(vmi, vcpu, num, val) \\\n\t(*ops->vmsetcap)(vmi, vcpu, num, val)\n#define\tVLAPIC_INIT(vmi, vcpu) \\\n\t(*ops->vlapic_init)(vmi, vcpu)\n#define\tVLAPIC_CLEANUP(vmi, vlapic) \\\n\t(*ops->vlapic_cleanup)(vmi, vlapic)\n#define\tVCPU_INTERRUPT(vcpu) \\\n\t(*ops->vcpu_interrupt)(vcpu)\n\n/* statistics */\n//static VMM_STAT(VCPU_TOTAL_RUNTIME, \"vcpu total runtime\");\n\n/*\n * Halt the guest if all vcpus are executing a HLT instruction with\n * interrupts disabled.\n */\nstatic int halt_detection_enabled = 1;\nstatic int trace_guest_exceptions = 0;\n\nstatic void\nvcpu_cleanup(struct vm *vm, int i, bool destroy)\n{\n\tstruct vcpu *vcpu = &vm->vcpu[i];\n\n\tVLAPIC_CLEANUP(vm->cookie, vcpu->vlapic);\n\tif (destroy) {\n\t\tvmm_stat_free(vcpu->stats);\t\n\t}\n}\n\nstatic void\nvcpu_init(struct vm *vm, int vcpu_id, bool create)\n{\n\tstruct vcpu *vcpu;\n\n\tKASSERT(vcpu_id >= 0 && vcpu_id < VM_MAXCPU,\n\t    (\"vcpu_init: invalid vcpu %d\", vcpu_id));\n\t  \n\tvcpu = &vm->vcpu[vcpu_id];\n\n\tif (create) {\n\t\tvcpu_lock_init(vcpu);\n\t\tpthread_mutex_init(&vcpu->state_sleep_mtx, NULL);\n\t\tpthread_cond_init(&vcpu->state_sleep_cnd, NULL);\n\t\tpthread_mutex_init(&vcpu->vcpu_sleep_mtx, NULL);\n\t\tpthread_cond_init(&vcpu->vcpu_sleep_cnd, NULL);\n\t\tvcpu->state = VCPU_IDLE;\n\t\tvcpu->stats = vmm_stat_alloc();\n\t}\n\n\tvcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id);\n\tvm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED);\n\tvcpu->exitintinfo = 0;\n\tvcpu->nmi_pending = 0;\n\tvcpu->extint_pending = 0;\n\tvcpu->exception_pending = 0;\n\tvcpu->guest_xcr0 = XFEATURE_ENABLED_X87;\n\tvmm_stat_init(vcpu->stats);\n}\n\nint vcpu_create(struct vm *vm, int vcpu) {\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\txhyve_abort(\"vcpu_create: invalid cpuid %d\\n\", vcpu);\n\n\treturn VCPU_INIT(vm->cookie, vcpu);\n}\n\nvoid vcpu_destroy(struct vm *vm, int vcpu) {\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\txhyve_abort(\"vcpu_destroy: invalid cpuid %d\\n\", vcpu);\n\n\tVCPU_CLEANUP(vm, vcpu);\n}\n\nint\nvcpu_trace_exceptions(void)\n{\n\treturn (trace_guest_exceptions);\n}\n\nstruct vm_exit *\nvm_exitinfo(struct vm *vm, int cpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (cpuid < 0 || cpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_exitinfo: invalid cpuid %d\\n\", cpuid);\n\n\tvcpu = &vm->vcpu[cpuid];\n\n\treturn (&vcpu->exitinfo);\n}\n\nint\nvmm_init(void)\n{\n\tint error;\n\n\tvmm_host_state_init();\n\n\terror = vmm_mem_init();\n\tif (error)\n\t\treturn (error);\n\t\n\tops = &vmm_ops_intel;\n\n\terror = VMM_INIT();\n\n\tif (error == 0)\n\t\tvmm_initialized = 1;\n\n\treturn (error);\n}\n\n\nint\nvmm_cleanup(void) {\n\tint error;\n\n\terror = VMM_CLEANUP();\n\n\tif (error == 0)\n\t\tvmm_initialized = 0;\n\n\treturn error;\n}\n\nstatic void\nvm_init(struct vm *vm, bool create)\n{\n\tint vcpu;\n\n\tif (create) {\n\t\tcallout_system_init();\n\t}\n\n\tvm->cookie = VM_INIT(vm);\n\tvm->vioapic = vioapic_init(vm);\n\tvm->vhpet = vhpet_init(vm);\n\tvm->vatpic = vatpic_init(vm);\n\tvm->vatpit = vatpit_init(vm);\n\tvm->vpmtmr = vpmtmr_init(vm);\n\n\tif (create) {\n\t\tvm->vrtc = vrtc_init(vm);\n\t}\n\n\tCPU_ZERO(&vm->active_cpus);\n\n\tvm->suspend = 0;\n\tCPU_ZERO(&vm->suspended_cpus);\n\n\tfor (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) {\n\t\tvcpu_init(vm, vcpu, create);\n\t}\n}\n\nint\nvm_create(struct vm **retvm)\n{\n\tstruct vm *vm;\n\n\tif (!vmm_initialized)\n\t\treturn (ENXIO);\n\n\tvm = malloc(sizeof(struct vm));\n\tassert(vm);\n\tbzero(vm, sizeof(struct vm));\n\tvm->num_mem_segs = 0;\n\tpthread_mutex_init(&vm->rendezvous_mtx, NULL);\n\tpthread_cond_init(&vm->rendezvous_sleep_cnd, NULL);\n\n\tvm_init(vm, true);\n\n\t*retvm = vm;\n\treturn (0);\n}\n\nstatic void\nvm_free_mem_seg(struct mem_seg *seg)\n{\n\tif (seg->object != NULL) {\n\t\tvmm_mem_free(seg->gpa, seg->len, seg->object);\n\t}\n\n\tbzero(seg, sizeof(*seg));\n}\n\nstatic void\nvm_cleanup(struct vm *vm, bool destroy)\n{\n\tint i, vcpu;\n\n\tfor (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) {\n\t\tvcpu_cleanup(vm, vcpu, destroy);\n\t}\n\n\tif (destroy) {\n\t\tvrtc_cleanup(vm->vrtc);\n\t} else {\n\t\tvrtc_reset(vm->vrtc);\n\t}\n\tvpmtmr_cleanup(vm->vpmtmr);\n\tvatpit_cleanup(vm->vatpit);\n\tvhpet_cleanup(vm->vhpet);\n\tvatpic_cleanup(vm->vatpic);\n\tvioapic_cleanup(vm->vioapic);\n\n\tVM_CLEANUP(vm->cookie);\n\n\tif (destroy) {\n\t\tfor (i = 0; i < vm->num_mem_segs; i++) {\n\t\t\tvm_free_mem_seg(&vm->mem_segs[i]);\n\t\t}\n\n\t\tvm->num_mem_segs = 0;\n\t}\n}\n\nvoid\nvm_destroy(struct vm *vm)\n{\n\tvm_cleanup(vm, true);\n\tfree(vm);\n}\n\nint\nvm_reinit(struct vm *vm)\n{\n\tint error;\n\n\t/*\n\t * A virtual machine can be reset only if all vcpus are suspended.\n\t */\n\tif (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) {\n\t\tvm_cleanup(vm, false);\n\t\tvm_init(vm, false);\n\t\terror = 0;\n\t} else {\n\t\terror = EBUSY;\n\t}\n\n\treturn (error);\n}\n\nconst char *\nvm_name(UNUSED struct vm *vm)\n{\n\treturn \"VM\";\n}\n\nbool\nvm_mem_allocated(struct vm *vm, uint64_t gpa)\n{\n\tint i;\n\tuint64_t gpabase, gpalimit;\n\n\tfor (i = 0; i < vm->num_mem_segs; i++) {\n\t\tgpabase = vm->mem_segs[i].gpa;\n\t\tgpalimit = gpabase + vm->mem_segs[i].len;\n\t\tif (gpa >= gpabase && gpa < gpalimit)\n\t\t\treturn (TRUE);\t\t/* 'gpa' is regular memory */\n\t}\n\n\treturn (FALSE);\n}\n\nint\nvm_malloc(struct vm *vm, uint64_t gpa, size_t len, uint64_t prot)\n{\n\tint available, allocated;\n\tstruct mem_seg *seg;\n\tvoid *object;\n\tuint64_t g;\n\n\tif ((gpa & XHYVE_PAGE_MASK) || (len & XHYVE_PAGE_MASK) || len == 0)\n\t\treturn (EINVAL);\n\t\n\tavailable = allocated = 0;\n\tg = gpa;\n\twhile (g < gpa + len) {\n\t\tif (vm_mem_allocated(vm, g))\n\t\t\tallocated++;\n\t\telse\n\t\t\tavailable++;\n\n\t\tg += XHYVE_PAGE_SIZE;\n\t}\n\n\t/*\n\t * If there are some allocated and some available pages in the address\n\t * range then it is an error.\n\t */\n\tif (allocated && available)\n\t\treturn (EINVAL);\n\n\t/*\n\t * If the entire address range being requested has already been\n\t * allocated then there isn't anything more to do.\n\t */\n\tif (allocated && available == 0)\n\t\treturn (0);\n\n\tif (vm->num_mem_segs >= VM_MAX_MEMORY_SEGMENTS)\n\t\treturn (E2BIG);\n\n\tseg = &vm->mem_segs[vm->num_mem_segs];\n\n\tif ((object = vmm_mem_alloc(gpa, len, prot)) == NULL)\n\t\treturn (ENOMEM);\n\n\tseg->gpa = gpa;\n\tseg->len = len;\n\tseg->object = object;\n\n\tvm->num_mem_segs++;\n\n\treturn (0);\n}\n\nvoid *\nvm_gpa2hva(struct vm *vm, uint64_t gpa, uint64_t len) {\n\tvoid *base;\n\tuint64_t offset;\n\n\tif (vm_get_memobj(vm, gpa, len, &offset, &base)) {\n\t\treturn NULL;\n\t}\n\n\treturn (void *) (((uintptr_t) base) + offset);\n}\n\nint\nvm_gpabase2memseg(struct vm *vm, uint64_t gpabase,\n\t\t  struct vm_memory_segment *seg)\n{\n\tint i;\n\n\tfor (i = 0; i < vm->num_mem_segs; i++) {\n\t\tif (gpabase == vm->mem_segs[i].gpa) {\n\t\t\tseg->gpa = vm->mem_segs[i].gpa;\n\t\t\tseg->len = vm->mem_segs[i].len;\n\t\t\treturn (0);\n\t\t}\n\t}\n\treturn (-1);\n}\n\nint\nvm_get_memobj(struct vm *vm, uint64_t gpa, size_t len,\n\t      uint64_t *offset, void **object)\n{\n\tint i;\n\tsize_t seg_len;\n\tuint64_t seg_gpa;\n\tvoid *seg_obj;\n\n\tfor (i = 0; i < vm->num_mem_segs; i++) {\n\t\tif ((seg_obj = vm->mem_segs[i].object) == NULL)\n\t\t\tcontinue;\n\n\t\tseg_gpa = vm->mem_segs[i].gpa;\n\t\tseg_len = vm->mem_segs[i].len;\n\n\t\tif ((gpa >= seg_gpa) && ((gpa + len) <= (seg_gpa + seg_len))) {\n\t\t\t*offset = gpa - seg_gpa;\n\t\t\t*object = seg_obj;\n\t\t\treturn (0);\n\t\t}\n\t}\n\n\treturn (EINVAL);\n}\n\nint\nvm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval)\n{\n\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (reg >= VM_REG_LAST)\n\t\treturn (EINVAL);\n\n\treturn (VMGETREG(vm->cookie, vcpu, reg, retval));\n}\n\nint\nvm_set_register(struct vm *vm, int vcpuid, int reg, uint64_t val)\n{\n\tstruct vcpu *vcpu;\n\tint error;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (reg >= VM_REG_LAST)\n\t\treturn (EINVAL);\n\n\terror = VMSETREG(vm->cookie, vcpuid, reg, val);\n\tif (error || reg != VM_REG_GUEST_RIP)\n\t\treturn (error);\n\n\t/* Set 'nextrip' to match the value of %rip */\n\tVCPU_CTR1(vm, vcpuid, \"Setting nextrip to %#llx\", val);\n\tvcpu = &vm->vcpu[vcpuid];\n\tvcpu->nextrip = val;\n\treturn (0);\n}\n\nstatic bool\nis_descriptor_table(int reg)\n{\n\tswitch (reg) {\n\tcase VM_REG_GUEST_IDTR:\n\tcase VM_REG_GUEST_GDTR:\n\t\treturn (TRUE);\n\tdefault:\n\t\treturn (FALSE);\n\t}\n}\n\nstatic bool\nis_segment_register(int reg)\n{\n\tswitch (reg) {\n\tcase VM_REG_GUEST_ES:\n\tcase VM_REG_GUEST_CS:\n\tcase VM_REG_GUEST_SS:\n\tcase VM_REG_GUEST_DS:\n\tcase VM_REG_GUEST_FS:\n\tcase VM_REG_GUEST_GS:\n\tcase VM_REG_GUEST_TR:\n\tcase VM_REG_GUEST_LDTR:\n\t\treturn (TRUE);\n\tdefault:\n\t\treturn (FALSE);\n\t}\n}\n\nint\nvm_get_seg_desc(struct vm *vm, int vcpu, int reg,\n\t\tstruct seg_desc *desc)\n{\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (!is_segment_register(reg) && !is_descriptor_table(reg))\n\t\treturn (EINVAL);\n\n\treturn (VMGETDESC(vm->cookie, vcpu, reg, desc));\n}\n\nint\nvm_set_seg_desc(struct vm *vm, int vcpu, int reg,\n\t\tstruct seg_desc *desc)\n{\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (!is_segment_register(reg) && !is_descriptor_table(reg))\n\t\treturn (EINVAL);\n\n\treturn (VMSETDESC(vm->cookie, vcpu, reg, desc));\n}\n\n// static VMM_STAT(VCPU_IDLE_TICKS, \"number of ticks vcpu was idle\");\n\nstatic int\nvcpu_set_state_locked(struct vcpu *vcpu, enum vcpu_state newstate,\n    bool from_idle)\n{\n\tint error;\n\tconst struct timespec ts = {.tv_sec = 1, .tv_nsec = 0}; /* 1 second */\n\n\t/*\n\t * State transitions from the vmmdev_ioctl() must always begin from\n\t * the VCPU_IDLE state. This guarantees that there is only a single\n\t * ioctl() operating on a vcpu at any point.\n\t */\n\tif (from_idle) {\n\t\twhile (vcpu->state != VCPU_IDLE) {\n\t\t\tpthread_mutex_lock(&vcpu->state_sleep_mtx);\n\t\t\tvcpu_unlock(vcpu);\n\t\t\tpthread_cond_timedwait_relative_np(&vcpu->state_sleep_cnd,\n\t\t\t\t&vcpu->state_sleep_mtx, &ts);\n\t\t\tvcpu_lock(vcpu);\n\t\t\tpthread_mutex_unlock(&vcpu->state_sleep_mtx);\n\t\t\t//msleep_spin(&vcpu->state, &vcpu->mtx, \"vmstat\", hz);\n\t\t}\n\t} else {\n\t\tKASSERT(vcpu->state != VCPU_IDLE, (\"invalid transition from \"\n\t\t    \"vcpu idle state\"));\n\t}\n\n\t/*\n\t * The following state transitions are allowed:\n\t * IDLE -> FROZEN -> IDLE\n\t * FROZEN -> RUNNING -> FROZEN\n\t * FROZEN -> SLEEPING -> FROZEN\n\t */\n\tswitch (vcpu->state) {\n\tcase VCPU_IDLE:\n\tcase VCPU_RUNNING:\n\tcase VCPU_SLEEPING:\n\t\terror = (newstate != VCPU_FROZEN);\n\t\tbreak;\n\tcase VCPU_FROZEN:\n\t\terror = (newstate == VCPU_FROZEN);\n\t\tbreak;\n\t}\n\n\tif (error)\n\t\treturn (EBUSY);\n\n\tvcpu->state = newstate;\n\n\tif (newstate == VCPU_IDLE)\n\t\tpthread_cond_broadcast(&vcpu->state_sleep_cnd);\n\t\t//wakeup(&vcpu->state);\n\n\treturn (0);\n}\n\nstatic void\nvcpu_require_state(struct vm *vm, int vcpuid, enum vcpu_state newstate)\n{\n\tint error;\n\n\tif ((error = vcpu_set_state(vm, vcpuid, newstate, false)) != 0)\n\t\txhyve_abort(\"Error %d setting state to %d\\n\", error, newstate);\n}\n\nstatic void\nvcpu_require_state_locked(struct vcpu *vcpu, enum vcpu_state newstate)\n{\n\tint error;\n\n\tif ((error = vcpu_set_state_locked(vcpu, newstate, false)) != 0)\n\t\txhyve_abort(\"Error %d setting state to %d\", error, newstate);\n}\n\nstatic void\nvm_set_rendezvous_func(struct vm *vm, vm_rendezvous_func_t func)\n{\n\t/*\n\t * Update 'rendezvous_func' and execute a write memory barrier to\n\t * ensure that it is visible across all host cpus. This is not needed\n\t * for correctness but it does ensure that all the vcpus will notice\n\t * that the rendezvous is requested immediately.\n\t */\n\tvm->rendezvous_func = func;\n\twmb();\n}\n\n#define\tRENDEZVOUS_CTR0(vm, vcpuid, fmt) \\\n\tdo { \\\n\t\tif (vcpuid >= 0) {\\\n\t\t\tVCPU_CTR0(vm, vcpuid, fmt); \\\n\t\t} else {\\\n\t\t\tVM_CTR0(vm, fmt); \\\n\t\t} \\\n\t} while (0)\n\nstatic void\nvm_handle_rendezvous(struct vm *vm, int vcpuid)\n{\n\n\tKASSERT(vcpuid == -1 || (vcpuid >= 0 && vcpuid < VM_MAXCPU),\n\t    (\"vm_handle_rendezvous: invalid vcpuid %d\", vcpuid));\n\n\tpthread_mutex_lock(&vm->rendezvous_mtx);\n\twhile (vm->rendezvous_func != NULL) {\n\t\t/* 'rendezvous_req_cpus' must be a subset of 'active_cpus' */\n\t\tCPU_AND(&vm->rendezvous_req_cpus, &vm->active_cpus);\n\n\t\tif (vcpuid != -1 &&\n\t\t    CPU_ISSET(((unsigned) vcpuid), &vm->rendezvous_req_cpus) &&\n\t\t    !CPU_ISSET(((unsigned) vcpuid), &vm->rendezvous_done_cpus)) {\n\t\t\tVCPU_CTR0(vm, vcpuid, \"Calling rendezvous func\");\n\t\t\t(*vm->rendezvous_func)(vm, vcpuid, vm->rendezvous_arg);\n\t\t\tCPU_SET(((unsigned) vcpuid), &vm->rendezvous_done_cpus);\n\t\t}\n\t\tif (CPU_CMP(&vm->rendezvous_req_cpus,\n\t\t    &vm->rendezvous_done_cpus) == 0) {\n\t\t\tVCPU_CTR0(vm, vcpuid, \"Rendezvous completed\");\n\t\t\tvm_set_rendezvous_func(vm, NULL);\n\t\t\tpthread_cond_broadcast(&vm->rendezvous_sleep_cnd);\n\t\t\t//wakeup(&vm->rendezvous_func);\n\t\t\tbreak;\n\t\t}\n\t\tRENDEZVOUS_CTR0(vm, vcpuid, \"Wait for rendezvous completion\");\n\t\tpthread_cond_wait(&vm->rendezvous_sleep_cnd, &vm->rendezvous_mtx);\n\t\t//mtx_sleep(&vm->rendezvous_func, &vm->rendezvous_mtx, 0, \"vmrndv\", 0);\n\t}\n\tpthread_mutex_unlock(&vm->rendezvous_mtx);\n}\n\n/*\n * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run.\n */\nstatic int\nvm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled)\n{\n\tstruct vcpu *vcpu;\n\tconst char *wmesg;\n\tint vcpu_halted, vm_halted;\n\tconst struct timespec ts = {.tv_sec = 1, .tv_nsec = 0}; /* 1 second */\n\n\tKASSERT(!CPU_ISSET(((unsigned) vcpuid), &vm->halted_cpus),\n\t\t(\"vcpu already halted\"));\n\n\tvcpu = &vm->vcpu[vcpuid];\n\tvcpu_halted = 0;\n\tvm_halted = 0;\n\n\tvcpu_lock(vcpu);\n\twhile (1) {\n\t\t/*\n\t\t * Do a final check for pending NMI or interrupts before\n\t\t * really putting this thread to sleep. Also check for\n\t\t * software events that would cause this vcpu to wakeup.\n\t\t *\n\t\t * These interrupts/events could have happened after the\n\t\t * vcpu returned from VMRUN() and before it acquired the\n\t\t * vcpu lock above.\n\t\t */\n\t\tif (vm->rendezvous_func != NULL || vm->suspend)\n\t\t\tbreak;\n\t\tif (vm_nmi_pending(vm, vcpuid))\n\t\t\tbreak;\n\t\tif (!intr_disabled) {\n\t\t\tif (vm_extint_pending(vm, vcpuid) ||\n\t\t\t    vlapic_pending_intr(vcpu->vlapic, NULL)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t/*\n\t\t * Some Linux guests implement \"halt\" by having all vcpus\n\t\t * execute HLT with interrupts disabled. 'halted_cpus' keeps\n\t\t * track of the vcpus that have entered this state. When all\n\t\t * vcpus enter the halted state the virtual machine is halted.\n\t\t */\n\t\tif (intr_disabled) {\n\t\t\twmesg = \"vmhalt\";\n\t\t\tVCPU_CTR0(vm, vcpuid, \"Halted\");\n\t\t\tif (!vcpu_halted && halt_detection_enabled) {\n\t\t\t\tvcpu_halted = 1;\n\t\t\t\tCPU_SET_ATOMIC(((unsigned) vcpuid), &vm->halted_cpus);\n\t\t\t}\n\t\t\tif (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) {\n\t\t\t\tvm_halted = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\twmesg = \"vmidle\";\n\t\t}\n\n\t\t//t = ticks;\n\t\tvcpu_require_state_locked(vcpu, VCPU_SLEEPING);\n\t\t/*\n\t\t * XXX msleep_spin() cannot be interrupted by signals so\n\t\t * wake up periodically to check pending signals.\n\t\t */\n\t\tpthread_mutex_lock(&vcpu->vcpu_sleep_mtx);\n\t\tvcpu_unlock(vcpu);\n\t\tpthread_cond_timedwait_relative_np(&vcpu->vcpu_sleep_cnd,\n\t\t\t&vcpu->vcpu_sleep_mtx, &ts);\n\t\tvcpu_lock(vcpu);\n\t\tpthread_mutex_unlock(&vcpu->vcpu_sleep_mtx);\n\t\t//msleep_spin(vcpu, &vcpu->mtx, wmesg, hz);\n\t\tvcpu_require_state_locked(vcpu, VCPU_FROZEN);\n\t\t//vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);\n\t}\n\n\tif (vcpu_halted)\n\t\tCPU_CLR_ATOMIC(((unsigned) vcpuid), &vm->halted_cpus);\n\n\tvcpu_unlock(vcpu);\n\n\tif (vm_halted)\n\t\tvm_suspend(vm, VM_SUSPEND_HALT);\n\n\treturn (0);\n}\n\nstatic int\nvm_handle_inst_emul(struct vm *vm, int vcpuid, bool *retu)\n{\n\tstruct vie *vie;\n\tstruct vcpu *vcpu;\n\tstruct vm_exit *vme;\n\tuint64_t gla, gpa, cs_base;\n\tstruct vm_guest_paging *paging;\n\tmem_region_read_t mread;\n\tmem_region_write_t mwrite;\n\tenum vm_cpu_mode cpu_mode;\n\tint cs_d, error, fault, length;\n\n\tvcpu = &vm->vcpu[vcpuid];\n\tvme = &vcpu->exitinfo;\n\n\tgla = vme->u.inst_emul.gla;\n\tgpa = vme->u.inst_emul.gpa;\n\tcs_base = vme->u.inst_emul.cs_base;\n\tcs_d = vme->u.inst_emul.cs_d;\n\tvie = &vme->u.inst_emul.vie;\n\tpaging = &vme->u.inst_emul.paging;\n\tcpu_mode = paging->cpu_mode;\n\n\tVCPU_CTR1(vm, vcpuid, \"inst_emul fault accessing gpa %#llx\", gpa);\n\n\t/* Fetch, decode and emulate the faulting instruction */\n\tif (vie->num_valid == 0) {\n\t\t/*\n\t\t * If the instruction length is not known then assume a\n\t\t * maximum size instruction.\n\t\t */\n\t\tlength = vme->inst_length ? vme->inst_length : VIE_INST_SIZE;\n\t\terror = vmm_fetch_instruction(vm, vcpuid, paging, vme->rip +\n\t\t    cs_base, length, vie, &fault);\n\t} else {\n\t\t/*\n\t\t * The instruction bytes have already been copied into 'vie'\n\t\t */\n\t\terror = fault = 0;\n\t}\n\tif (error || fault)\n\t\treturn (error);\n\n\tif (vmm_decode_instruction(vm, vcpuid, gla, cpu_mode, cs_d, vie) != 0) {\n\t\tVCPU_CTR1(vm, vcpuid, \"Error decoding instruction at %#llx\",\n\t\t    vme->rip + cs_base);\n\t\t*retu = true;\t    /* dump instruction bytes in userspace */\n\t\treturn (0);\n\t}\n\n\t/*\n\t * If the instruction length was not specified then update it now\n\t * along with 'nextrip'.\n\t */\n\tif (vme->inst_length == 0) {\n\t\tvme->inst_length = vie->num_processed;\n\t\tvcpu->nextrip += vie->num_processed;\n\t}\n \n\t/* return to userland unless this is an in-kernel emulated device */\n\tif (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + XHYVE_PAGE_SIZE) {\n\t\tmread = lapic_mmio_read;\n\t\tmwrite = lapic_mmio_write;\n\t} else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) {\n\t\tmread = vioapic_mmio_read;\n\t\tmwrite = vioapic_mmio_write;\n\t} else if (gpa >= VHPET_BASE && gpa < VHPET_BASE + VHPET_SIZE) {\n\t\tmread = vhpet_mmio_read;\n\t\tmwrite = vhpet_mmio_write;\n\t} else {\n\t\t*retu = true;\n\t\treturn (0);\n\t}\n\n\terror = vmm_emulate_instruction(vm, vcpuid, gpa, vie, paging,\n\t    mread, mwrite, retu);\n\n\treturn (error);\n}\n\nstatic int\nvm_handle_suspend(struct vm *vm, int vcpuid, bool *retu)\n{\n\tint i, done;\n\tstruct vcpu *vcpu;\n\tconst struct timespec ts = {.tv_sec = 1, .tv_nsec = 0}; /* 1 second */\n\n\tdone = 0;\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tCPU_SET_ATOMIC(((unsigned) vcpuid), &vm->suspended_cpus);\n\n\t/*\n\t * Wait until all 'active_cpus' have suspended themselves.\n\t *\n\t * Since a VM may be suspended at any time including when one or\n\t * more vcpus are doing a rendezvous we need to call the rendezvous\n\t * handler while we are waiting to prevent a deadlock.\n\t */\n\tvcpu_lock(vcpu);\n\twhile (1) {\n\t\tif (CPU_CMP(&vm->suspended_cpus, &vm->active_cpus) == 0) {\n\t\t\tVCPU_CTR0(vm, vcpuid, \"All vcpus suspended\");\n\t\t\tbreak;\n\t\t}\n\n\t\tif (vm->rendezvous_func == NULL) {\n\t\t\tVCPU_CTR0(vm, vcpuid, \"Sleeping during suspend\");\n\t\t\tvcpu_require_state_locked(vcpu, VCPU_SLEEPING);\n\n\t\t\tpthread_mutex_lock(&vcpu->vcpu_sleep_mtx);\n\t\t\tvcpu_unlock(vcpu);\n\t\t\tpthread_cond_timedwait_relative_np(&vcpu->vcpu_sleep_cnd,\n\t\t\t\t&vcpu->vcpu_sleep_mtx, &ts);\n\t\t\tvcpu_lock(vcpu);\n\t\t\tpthread_mutex_unlock(&vcpu->vcpu_sleep_mtx);\n\t\t\t//msleep_spin(vcpu, &vcpu->mtx, \"vmsusp\", hz);\n\n\t\t\tvcpu_require_state_locked(vcpu, VCPU_FROZEN);\n\t\t} else {\n\t\t\tVCPU_CTR0(vm, vcpuid, \"Rendezvous during suspend\");\n\t\t\tvcpu_unlock(vcpu);\n\t\t\tvm_handle_rendezvous(vm, vcpuid);\n\t\t\tvcpu_lock(vcpu);\n\t\t}\n\t}\n\tvcpu_unlock(vcpu);\n\n\t/*\n\t * Wakeup the other sleeping vcpus and return to userspace.\n\t */\n\tfor (i = 0; i < VM_MAXCPU; i++) {\n\t\tif (CPU_ISSET(((unsigned) i), &vm->suspended_cpus)) {\n\t\t\tvcpu_notify_event(vm, i, false);\n\t\t}\n\t}\n\n\t*retu = true;\n\treturn (0);\n}\n\nint\nvm_suspend(struct vm *vm, enum vm_suspend_how how)\n{\n\tint i;\n\n\tif (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST)\n\t\treturn (EINVAL);\n\n\tif (atomic_cmpset_int(((volatile u_int *) &vm->suspend), 0, how) == 0) {\n\t\tVM_CTR2(vm, \"virtual machine already suspended %d/%d\",\n\t\t    vm->suspend, how);\n\t\treturn (EALREADY);\n\t}\n\n\tVM_CTR1(vm, \"virtual machine successfully suspended %d\", how);\n\n\t/*\n\t * Notify all active vcpus that they are now suspended.\n\t */\n\tfor (i = 0; i < VM_MAXCPU; i++) {\n\t\tif (CPU_ISSET(((unsigned) i), &vm->active_cpus))\n\t\t\tvcpu_notify_event(vm, i, false);\n\t}\n\n\treturn (0);\n}\n\nvoid\nvm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip)\n{\n\tstruct vm_exit *vmexit;\n\n\tKASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST,\n\t    (\"vm_exit_suspended: invalid suspend type %d\", vm->suspend));\n\n\tvmexit = vm_exitinfo(vm, vcpuid);\n\tvmexit->rip = rip;\n\tvmexit->inst_length = 0;\n\tvmexit->exitcode = VM_EXITCODE_SUSPENDED;\n\tvmexit->u.suspended.how = (enum vm_suspend_how) vm->suspend;\n}\n\nvoid\nvm_exit_rendezvous(struct vm *vm, int vcpuid, uint64_t rip)\n{\n\tstruct vm_exit *vmexit;\n\n\tKASSERT(vm->rendezvous_func != NULL, (\"rendezvous not in progress\"));\n\n\tvmexit = vm_exitinfo(vm, vcpuid);\n\tvmexit->rip = rip;\n\tvmexit->inst_length = 0;\n\tvmexit->exitcode = VM_EXITCODE_RENDEZVOUS;\n\tvmm_stat_incr(vm, vcpuid, VMEXIT_RENDEZVOUS, 1);\n}\n\nvoid pittest(struct vm *thevm);\n\nint\nvm_run(struct vm *vm, int vcpuid, struct vm_exit *vm_exit)\n{\n\tint error;\n\tstruct vcpu *vcpu;\n\t// uint64_t tscval;\n\tstruct vm_exit *vme;\n\tbool retu, intr_disabled;\n\tvoid *rptr, *sptr;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (!CPU_ISSET(((unsigned) vcpuid), &vm->active_cpus))\n\t\treturn (EINVAL);\n\n\tif (CPU_ISSET(((unsigned) vcpuid), &vm->suspended_cpus))\n\t\treturn (EINVAL);\n\n\trptr = &vm->rendezvous_func;\n\tsptr = &vm->suspend;\n\tvcpu = &vm->vcpu[vcpuid];\n\tvme = &vcpu->exitinfo;\n\tretu = false;\n\nrestart:\n\t// tscval = rdtsc();\n\n\tvcpu_require_state(vm, vcpuid, VCPU_RUNNING);\n\terror = VMRUN(vm->cookie, vcpuid, (register_t) vcpu->nextrip, rptr, sptr);\n\tvcpu_require_state(vm, vcpuid, VCPU_FROZEN);\n\n\n\t// vmm_stat_incr(vm, vcpuid, VCPU_TOTAL_RUNTIME, rdtsc() - tscval);\n\n\tif (error == 0) {\n\t\tretu = false;\n\t\tvcpu->nextrip = vme->rip + ((unsigned) vme->inst_length);\n\t\tswitch (((int) (vme->exitcode))) {\n\t\tcase VM_EXITCODE_SUSPENDED:\n\t\t\terror = vm_handle_suspend(vm, vcpuid, &retu);\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_IOAPIC_EOI:\n\t\t\tvioapic_process_eoi(vm, vcpuid,\n\t\t\t    vme->u.ioapic_eoi.vector);\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_RENDEZVOUS:\n\t\t\tvm_handle_rendezvous(vm, vcpuid);\n\t\t\terror = 0;\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_HLT:\n\t\t\tintr_disabled = ((vme->u.hlt.rflags & PSL_I) == 0);\n\t\t\terror = vm_handle_hlt(vm, vcpuid, intr_disabled);\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_PAGING:\n\t\t\terror = 0;\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_INST_EMUL:\n\t\t\terror = vm_handle_inst_emul(vm, vcpuid, &retu);\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_INOUT:\n\t\tcase VM_EXITCODE_INOUT_STR:\n\t\t\terror = vm_handle_inout(vm, vcpuid, vme, &retu);\n\t\t\tbreak;\n\t\tcase VM_EXITCODE_MONITOR:\n\t\tcase VM_EXITCODE_MWAIT:\n\t\t\tvm_inject_ud(vm, vcpuid);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tretu = true;\t/* handled in userland */\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (error == 0 && retu == false)\n\t\tgoto restart;\n\n\t/* copy the exit information (FIXME: zero copy) */\n\tbcopy(vme, vm_exit, sizeof(struct vm_exit));\n\treturn (error);\n}\n\nint\nvm_restart_instruction(void *arg, int vcpuid)\n{\n\tstruct vm *vm;\n\tstruct vcpu *vcpu;\n\tenum vcpu_state state;\n\tuint64_t rip;\n\tint error;\n\n\tvm = arg;\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\tstate = vcpu_get_state(vm, vcpuid);\n\tif (state == VCPU_RUNNING) {\n\t\t/*\n\t\t * When a vcpu is \"running\" the next instruction is determined\n\t\t * by adding 'rip' and 'inst_length' in the vcpu's 'exitinfo'.\n\t\t * Thus setting 'inst_length' to zero will cause the current\n\t\t * instruction to be restarted.\n\t\t */\n\t\tvcpu->exitinfo.inst_length = 0;\n\t\tVCPU_CTR1(vm, vcpuid, \"restarting instruction at %#llx by \"\n\t\t    \"setting inst_length to zero\", vcpu->exitinfo.rip);\n\t} else if (state == VCPU_FROZEN) {\n\t\t/*\n\t\t * When a vcpu is \"frozen\" it is outside the critical section\n\t\t * around VMRUN() and 'nextrip' points to the next instruction.\n\t\t * Thus instruction restart is achieved by setting 'nextrip'\n\t\t * to the vcpu's %rip.\n\t\t */\n\t\terror = vm_get_register(vm, vcpuid, VM_REG_GUEST_RIP, &rip);\n\t\tKASSERT(!error, (\"%s: error %d getting rip\", __func__, error));\n\t\tVCPU_CTR2(vm, vcpuid, \"restarting instruction by updating \"\n\t\t    \"nextrip from %#llx to %#llx\", vcpu->nextrip, rip);\n\t\tvcpu->nextrip = rip;\n\t} else {\n\t\txhyve_abort(\"%s: invalid state %d\\n\", __func__, state);\n\t}\n\treturn (0);\n}\n\nint\nvm_exit_intinfo(struct vm *vm, int vcpuid, uint64_t info)\n{\n\tstruct vcpu *vcpu;\n\tint type, vector;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tif (info & VM_INTINFO_VALID) {\n\t\ttype = info & VM_INTINFO_TYPE;\n\t\tvector = info & 0xff;\n\t\tif (type == VM_INTINFO_NMI && vector != IDT_NMI)\n\t\t\treturn (EINVAL);\n\t\tif (type == VM_INTINFO_HWEXCEPTION && vector >= 32)\n\t\t\treturn (EINVAL);\n\t\tif (info & VM_INTINFO_RSVD)\n\t\t\treturn (EINVAL);\n\t} else {\n\t\tinfo = 0;\n\t}\n\tVCPU_CTR2(vm, vcpuid, \"%s: info1(%#llx)\", __func__, info);\n\tvcpu->exitintinfo = info;\n\treturn (0);\n}\n\nenum exc_class {\n\tEXC_BENIGN,\n\tEXC_CONTRIBUTORY,\n\tEXC_PAGEFAULT\n};\n\n#define\tIDT_VE\t20\t/* Virtualization Exception (Intel specific) */\n\nstatic enum exc_class\nexception_class(uint64_t info)\n{\n\tint type, vector;\n\n\tKASSERT(info & VM_INTINFO_VALID, (\"intinfo must be valid: %#llx\", info));\n\ttype = info & VM_INTINFO_TYPE;\n\tvector = info & 0xff;\n\n\t/* Table 6-4, \"Interrupt and Exception Classes\", Intel SDM, Vol 3 */\n\tswitch (type) {\n\tcase VM_INTINFO_HWINTR:\n\tcase VM_INTINFO_SWINTR:\n\tcase VM_INTINFO_NMI:\n\t\treturn (EXC_BENIGN);\n\tdefault:\n\t\t/*\n\t\t * Hardware exception.\n\t\t *\n\t\t * SVM and VT-x use identical type values to represent NMI,\n\t\t * hardware interrupt and software interrupt.\n\t\t *\n\t\t * SVM uses type '3' for all exceptions. VT-x uses type '3'\n\t\t * for exceptions except #BP and #OF. #BP and #OF use a type\n\t\t * value of '5' or '6'. Therefore we don't check for explicit\n\t\t * values of 'type' to classify 'intinfo' into a hardware\n\t\t * exception.\n\t\t */\n\t\tbreak;\n\t}\n\n\tswitch (vector) {\n\tcase IDT_PF:\n\tcase IDT_VE:\n\t\treturn (EXC_PAGEFAULT);\n\tcase IDT_DE:\n\tcase IDT_TS:\n\tcase IDT_NP:\n\tcase IDT_SS:\n\tcase IDT_GP:\n\t\treturn (EXC_CONTRIBUTORY);\n\tdefault:\n\t\treturn (EXC_BENIGN);\n\t}\n}\n\nstatic int\nnested_fault(struct vm *vm, int vcpuid, uint64_t info1, uint64_t info2,\n    uint64_t *retinfo)\n{\n\tenum exc_class exc1, exc2;\n\tint type1, vector1;\n\n\tKASSERT(info1 & VM_INTINFO_VALID, (\"info1 %#llx is not valid\", info1));\n\tKASSERT(info2 & VM_INTINFO_VALID, (\"info2 %#llx is not valid\", info2));\n\n\t/*\n\t * If an exception occurs while attempting to call the double-fault\n\t * handler the processor enters shutdown mode (aka triple fault).\n\t */\n\ttype1 = info1 & VM_INTINFO_TYPE;\n\tvector1 = info1 & 0xff;\n\tif (type1 == VM_INTINFO_HWEXCEPTION && vector1 == IDT_DF) {\n\t\tVCPU_CTR2(vm, vcpuid, \"triple fault: info1(%#llx), info2(%#llx)\",\n\t\t    info1, info2);\n\t\tvm_suspend(vm, VM_SUSPEND_TRIPLEFAULT);\n\t\t*retinfo = 0;\n\t\treturn (0);\n\t}\n\n\t/*\n\t * Table 6-5 \"Conditions for Generating a Double Fault\", Intel SDM, Vol3\n\t */\n\texc1 = exception_class(info1);\n\texc2 = exception_class(info2);\n\tif ((exc1 == EXC_CONTRIBUTORY && exc2 == EXC_CONTRIBUTORY) ||\n\t    (exc1 == EXC_PAGEFAULT && exc2 != EXC_BENIGN)) {\n\t\t/* Convert nested fault into a double fault. */\n\t\t*retinfo = IDT_DF;\n\t\t*retinfo |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION;\n\t\t*retinfo |= VM_INTINFO_DEL_ERRCODE;\n\t} else {\n\t\t/* Handle exceptions serially */\n\t\t*retinfo = info2;\n\t}\n\treturn (1);\n}\n\nstatic uint64_t\nvcpu_exception_intinfo(struct vcpu *vcpu)\n{\n\tuint64_t info = 0;\n\n\tif (vcpu->exception_pending) {\n\t\tinfo = vcpu->exc_vector & 0xff;\n\t\tinfo |= VM_INTINFO_VALID | VM_INTINFO_HWEXCEPTION;\n\t\tif (vcpu->exc_errcode_valid) {\n\t\t\tinfo |= VM_INTINFO_DEL_ERRCODE;\n\t\t\tinfo |= (uint64_t)vcpu->exc_errcode << 32;\n\t\t}\n\t}\n\treturn (info);\n}\n\nint\nvm_entry_intinfo(struct vm *vm, int vcpuid, uint64_t *retinfo)\n{\n\tstruct vcpu *vcpu;\n\tuint64_t info1, info2;\n\tint valid;\n\n\tKASSERT(vcpuid >= 0 && vcpuid < VM_MAXCPU, (\"invalid vcpu %d\", vcpuid));\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tinfo1 = vcpu->exitintinfo;\n\tvcpu->exitintinfo = 0;\n\n\tinfo2 = 0;\n\tif (vcpu->exception_pending) {\n\t\tinfo2 = vcpu_exception_intinfo(vcpu);\n\t\tvcpu->exception_pending = 0;\n\t\tVCPU_CTR2(vm, vcpuid, \"Exception %d delivered: %#llx\",\n\t\t    vcpu->exc_vector, info2);\n\t}\n\n\tif ((info1 & VM_INTINFO_VALID) && (info2 & VM_INTINFO_VALID)) {\n\t\tvalid = nested_fault(vm, vcpuid, info1, info2, retinfo);\n\t} else if (info1 & VM_INTINFO_VALID) {\n\t\t*retinfo = info1;\n\t\tvalid = 1;\n\t} else if (info2 & VM_INTINFO_VALID) {\n\t\t*retinfo = info2;\n\t\tvalid = 1;\n\t} else {\n\t\tvalid = 0;\n\t}\n\n\tif (valid) {\n\t\tVCPU_CTR4(vm, vcpuid, \"%s: info1(%#llx), info2(%#llx), \"\n\t\t    \"retinfo(%#llx)\", __func__, info1, info2, *retinfo);\n\t}\n\n\treturn (valid);\n}\n\nint\nvm_get_intinfo(struct vm *vm, int vcpuid, uint64_t *info1, uint64_t *info2)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\t*info1 = vcpu->exitintinfo;\n\t*info2 = vcpu_exception_intinfo(vcpu);\n\treturn (0);\n}\n\nint\nvm_inject_exception(struct vm *vm, int vcpuid, int vector, int errcode_valid,\n    uint32_t errcode, int restart_instruction)\n{\n\tstruct vcpu *vcpu;\n\tint error;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (vector < 0 || vector >= 32)\n\t\treturn (EINVAL);\n\n\t/*\n\t * A double fault exception should never be injected directly into\n\t * the guest. It is a derived exception that results from specific\n\t * combinations of nested faults.\n\t */\n\tif (vector == IDT_DF)\n\t\treturn (EINVAL);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tif (vcpu->exception_pending) {\n\t\tVCPU_CTR2(vm, vcpuid, \"Unable to inject exception %d due to \"\n\t\t    \"pending exception %d\", vector, vcpu->exc_vector);\n\t\treturn (EBUSY);\n\t}\n\n\t/*\n\t * From section 26.6.1 \"Interruptibility State\" in Intel SDM:\n\t *\n\t * Event blocking by \"STI\" or \"MOV SS\" is cleared after guest executes\n\t * one instruction or incurs an exception.\n\t */\n\terror = vm_set_register(vm, vcpuid, VM_REG_GUEST_INTR_SHADOW, 0);\n\tKASSERT(error == 0, (\"%s: error %d clearing interrupt shadow\",\n\t    __func__, error));\n\n\tif (restart_instruction)\n\t\tvm_restart_instruction(vm, vcpuid);\n\n\tvcpu->exception_pending = 1;\n\tvcpu->exc_vector = vector;\n\tvcpu->exc_errcode = errcode;\n\tvcpu->exc_errcode_valid = errcode_valid;\n\tVCPU_CTR1(vm, vcpuid, \"Exception %d pending\", vector);\n\treturn (0);\n}\n\nvoid\nvm_inject_fault(void *vmarg, int vcpuid, int vector, int errcode_valid,\n    int errcode)\n{\n\tstruct vm *vm;\n\tint error, restart_instruction;\n\n\tvm = vmarg;\n\trestart_instruction = 1;\n\n\terror = vm_inject_exception(vm, vcpuid, vector, errcode_valid,\n\t    ((uint32_t) errcode), restart_instruction);\n\tKASSERT(error == 0, (\"vm_inject_exception error %d\", error));\n}\n\nvoid\nvm_inject_pf(void *vmarg, int vcpuid, int error_code, uint64_t cr2)\n{\n\tstruct vm *vm;\n\tint error;\n\n\tvm = vmarg;\n\tVCPU_CTR2(vm, vcpuid, \"Injecting page fault: error_code %#x, cr2 %#llx\",\n\t    error_code, cr2);\n\n\terror = vm_set_register(vm, vcpuid, VM_REG_GUEST_CR2, cr2);\n\tKASSERT(error == 0, (\"vm_set_register(cr2) error %d\", error));\n\n\tvm_inject_fault(vm, vcpuid, IDT_PF, 1, error_code);\n}\n\nstatic VMM_STAT(VCPU_NMI_COUNT, \"number of NMIs delivered to vcpu\");\n\nint\nvm_inject_nmi(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tvcpu->nmi_pending = 1;\n\tvcpu_notify_event(vm, vcpuid, false);\n\treturn (0);\n}\n\nint\nvm_nmi_pending(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_nmi_pending: invalid vcpuid %d\\n\", vcpuid);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\treturn (vcpu->nmi_pending);\n}\n\nvoid\nvm_nmi_clear(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_nmi_pending: invalid vcpuid %d\\n\", vcpuid);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tif (vcpu->nmi_pending == 0)\n\t\txhyve_abort(\"vm_nmi_clear: inconsistent nmi_pending state\\n\");\n\n\tvcpu->nmi_pending = 0;\n\tvmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1);\n}\n\nstatic VMM_STAT(VCPU_EXTINT_COUNT, \"number of ExtINTs delivered to vcpu\");\n\nint\nvm_inject_extint(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tvcpu->extint_pending = 1;\n\tvcpu_notify_event(vm, vcpuid, false);\n\treturn (0);\n}\n\nint\nvm_extint_pending(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_extint_pending: invalid vcpuid %d\\n\", vcpuid);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\treturn (vcpu->extint_pending);\n}\n\nvoid\nvm_extint_clear(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_extint_pending: invalid vcpuid %d\\n\", vcpuid);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tif (vcpu->extint_pending == 0)\n\t\txhyve_abort(\"vm_extint_clear: inconsistent extint_pending state\\n\");\n\n\tvcpu->extint_pending = 0;\n\tvmm_stat_incr(vm, vcpuid, VCPU_EXTINT_COUNT, 1);\n}\n\nint\nvm_get_capability(struct vm *vm, int vcpu, int type, int *retval)\n{\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (type < 0 || type >= VM_CAP_MAX)\n\t\treturn (EINVAL);\n\n\treturn (VMGETCAP(vm->cookie, vcpu, type, retval));\n}\n\nint\nvm_set_capability(struct vm *vm, int vcpu, int type, int val)\n{\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (type < 0 || type >= VM_CAP_MAX)\n\t\treturn (EINVAL);\n\n\treturn (VMSETCAP(vm->cookie, vcpu, type, val));\n}\n\nstruct vlapic *\nvm_lapic(struct vm *vm, int cpu)\n{\n\treturn (vm->vcpu[cpu].vlapic);\n}\n\nstruct vioapic *\nvm_ioapic(struct vm *vm)\n{\n\n\treturn (vm->vioapic);\n}\n\nstruct vhpet *\nvm_hpet(struct vm *vm)\n{\n\n\treturn (vm->vhpet);\n}\n\nint\nvcpu_set_state(struct vm *vm, int vcpuid, enum vcpu_state newstate,\n    bool from_idle)\n{\n\tint error;\n\tstruct vcpu *vcpu;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_set_run_state: invalid vcpuid %d\\n\", vcpuid);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tvcpu_lock(vcpu);\n\terror = vcpu_set_state_locked(vcpu, newstate, from_idle);\n\tvcpu_unlock(vcpu);\n\treturn (error);\n}\n\nenum vcpu_state\nvcpu_get_state(struct vm *vm, int vcpuid)\n{\n\tstruct vcpu *vcpu;\n\tenum vcpu_state state;\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\txhyve_abort(\"vm_get_run_state: invalid vcpuid %d\\n\", vcpuid);\n\n\tvcpu = &vm->vcpu[vcpuid];\n\n\tvcpu_lock(vcpu);\n\tstate = vcpu->state;\n\tvcpu_unlock(vcpu);\n\n\treturn (state);\n}\n\nint\nvm_activate_cpu(struct vm *vm, int vcpuid)\n{\n\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (CPU_ISSET(((unsigned) vcpuid), &vm->active_cpus))\n\t\treturn (EBUSY);\n\n\tVCPU_CTR0(vm, vcpuid, \"activated\");\n\tCPU_SET_ATOMIC(((unsigned) vcpuid), &vm->active_cpus);\n\treturn (0);\n}\n\ncpuset_t\nvm_active_cpus(struct vm *vm)\n{\n\n\treturn (vm->active_cpus);\n}\n\ncpuset_t\nvm_suspended_cpus(struct vm *vm)\n{\n\n\treturn (vm->suspended_cpus);\n}\n\nvoid *\nvcpu_stats(struct vm *vm, int vcpuid)\n{\n\n\treturn (vm->vcpu[vcpuid].stats);\n}\n\nint\nvm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state)\n{\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\t*state = vm->vcpu[vcpuid].x2apic_state;\n\n\treturn (0);\n}\n\nint\nvm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state)\n{\n\tif (vcpuid < 0 || vcpuid >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (state >= X2APIC_STATE_LAST)\n\t\treturn (EINVAL);\n\n\tvm->vcpu[vcpuid].x2apic_state = state;\n\n\tvlapic_set_x2apic_state(vm, vcpuid, state);\n\n\treturn (0);\n}\n\n/*\n * This function is called to ensure that a vcpu \"sees\" a pending event\n * as soon as possible:\n * - If the vcpu thread is sleeping then it is woken up.\n * - If the vcpu is running on a different host_cpu then an IPI will be directed\n *   to the host_cpu to cause the vcpu to trap into the hypervisor.\n */\nvoid\nvcpu_notify_event(struct vm *vm, int vcpuid, UNUSED bool lapic_intr)\n{\n\tstruct vcpu *vcpu;\n\n\tvcpu = &vm->vcpu[vcpuid];\n\tvcpu_lock(vcpu);\n\tif (vcpu->state == VCPU_RUNNING) {\n\t\tVCPU_INTERRUPT(vcpuid);\n\t\t/* FIXME */\n\t\t// if (hostcpu != curcpu) {\n\t\t// \tif (lapic_intr) {\n\t\t// \t\tvlapic_post_intr(vcpu->vlapic, hostcpu,\n\t\t// \t\t    vmm_ipinum);\n\t\t// \t} else {\n\t\t// \t\tipi_cpu(hostcpu, vmm_ipinum);\n\t\t// \t}\n\t\t// } else {\n\t\t//\t/*\n\t\t//\t * If the 'vcpu' is running on 'curcpu' then it must\n\t\t//\t * be sending a notification to itself (e.g. SELF_IPI).\n\t\t//\t * The pending event will be picked up when the vcpu\n\t\t//\t * transitions back to guest context.\n\t\t//\t */\n\t\t// }\n\t} else {\n\t\tif (vcpu->state == VCPU_SLEEPING)\n\t\t\tpthread_cond_signal(&vcpu->vcpu_sleep_cnd);\n\t\t\t//wakeup_one(vcpu);\n\t}\n\tvcpu_unlock(vcpu);\n}\n\nint\nvm_apicid2vcpuid(UNUSED struct vm *vm, int apicid)\n{\n\t/*\n\t * XXX apic id is assumed to be numerically identical to vcpu id\n\t */\n\treturn (apicid);\n}\n\nvoid\nvm_smp_rendezvous(struct vm *vm, int vcpuid, cpuset_t dest,\n    vm_rendezvous_func_t func, void *arg)\n{\n\tint i;\n\n\tKASSERT(vcpuid == -1 || (vcpuid >= 0 && vcpuid < VM_MAXCPU),\n\t    (\"vm_smp_rendezvous: invalid vcpuid %d\", vcpuid));\n\nrestart:\n\tpthread_mutex_lock(&vm->rendezvous_mtx);\n\tif (vm->rendezvous_func != NULL) {\n\t\t/*\n\t\t * If a rendezvous is already in progress then we need to\n\t\t * call the rendezvous handler in case this 'vcpuid' is one\n\t\t * of the targets of the rendezvous.\n\t\t */\n\t\tRENDEZVOUS_CTR0(vm, vcpuid, \"Rendezvous already in progress\");\n\t\tpthread_mutex_unlock(&vm->rendezvous_mtx);\n\t\tvm_handle_rendezvous(vm, vcpuid);\n\t\tgoto restart;\n\t}\n\tKASSERT(vm->rendezvous_func == NULL, (\"vm_smp_rendezvous: previous \"\n\t    \"rendezvous is still in progress\"));\n\n\tRENDEZVOUS_CTR0(vm, vcpuid, \"Initiating rendezvous\");\n\tvm->rendezvous_req_cpus = dest;\n\tCPU_ZERO(&vm->rendezvous_done_cpus);\n\tvm->rendezvous_arg = arg;\n\tvm_set_rendezvous_func(vm, func);\n\tpthread_mutex_unlock(&vm->rendezvous_mtx);\n\n\t/*\n\t * Wake up any sleeping vcpus and trigger a VM-exit in any running\n\t * vcpus so they handle the rendezvous as soon as possible.\n\t */\n\tfor (i = 0; i < VM_MAXCPU; i++) {\n\t\tif (CPU_ISSET(((unsigned) i), &dest))\n\t\t\tvcpu_notify_event(vm, i, false);\n\t}\n\n\tvm_handle_rendezvous(vm, vcpuid);\n}\n\nstruct vatpic *\nvm_atpic(struct vm *vm)\n{\n\treturn (vm->vatpic);\n}\n\nstruct vatpit *\nvm_atpit(struct vm *vm)\n{\n\treturn (vm->vatpit);\n}\n\nstruct vpmtmr *\nvm_pmtmr(struct vm *vm)\n{\n\n\treturn (vm->vpmtmr);\n}\n\nstruct vrtc *\nvm_rtc(struct vm *vm)\n{\n\n\treturn (vm->vrtc);\n}\n\nenum vm_reg_name\nvm_segment_name(int seg)\n{\n\tstatic enum vm_reg_name seg_names[] = {\n\t\tVM_REG_GUEST_ES,\n\t\tVM_REG_GUEST_CS,\n\t\tVM_REG_GUEST_SS,\n\t\tVM_REG_GUEST_DS,\n\t\tVM_REG_GUEST_FS,\n\t\tVM_REG_GUEST_GS\n\t};\n\n\tKASSERT(seg >= 0 && seg < ((int) nitems(seg_names)),\n\t    (\"%s: invalid segment encoding %d\", __func__, seg));\n\treturn (seg_names[seg]);\n}\n\nvoid\nvm_copy_teardown(UNUSED struct vm *vm, UNUSED int vcpuid,\n\tstruct vm_copyinfo *copyinfo, int num_copyinfo)\n{\n\tbzero(copyinfo, ((unsigned) num_copyinfo) * sizeof(struct vm_copyinfo));\n}\n\nint\nvm_copy_setup(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,\n    uint64_t gla, size_t len, int prot, struct vm_copyinfo *copyinfo,\n    int num_copyinfo, int *fault)\n{\n\tint error, idx, nused;\n\tsize_t n, off, remaining;\n\tvoid *hva;\n\tuint64_t gpa;\n\n\tbzero(copyinfo, sizeof(struct vm_copyinfo) * ((unsigned) num_copyinfo));\n\n\tnused = 0;\n\tremaining = len;\n\twhile (remaining > 0) {\n\t\tKASSERT(nused < num_copyinfo, (\"insufficient vm_copyinfo\"));\n\t\terror = vm_gla2gpa(vm, vcpuid, paging, gla, prot, &gpa, fault);\n\t\tif (error || *fault)\n\t\t\treturn (error);\n\t\toff = gpa & XHYVE_PAGE_MASK;\n\t\tn = min(remaining, XHYVE_PAGE_SIZE - off);\n\t\tcopyinfo[nused].gpa = gpa;\n\t\tcopyinfo[nused].len = n;\n\t\tremaining -= n;\n\t\tgla += n;\n\t\tnused++;\n\t}\n\n\tfor (idx = 0; idx < nused; idx++) {\n\t\thva = vm_gpa2hva(vm, copyinfo[idx].gpa, copyinfo[idx].len);\n\t\tif (hva == NULL)\n\t\t\tbreak;\n\t\tcopyinfo[idx].hva = hva;\n\t}\n\n\tif (idx != nused) {\n\t\tvm_copy_teardown(vm, vcpuid, copyinfo, num_copyinfo);\n\t\treturn (EFAULT);\n\t} else {\n\t\t*fault = 0;\n\t\treturn (0);\n\t}\n}\n\nvoid\nvm_copyin(UNUSED struct vm *vm, UNUSED int vcpuid, struct vm_copyinfo *copyinfo,\n\tvoid *kaddr, size_t len)\n{\n\tchar *dst;\n\tint idx;\n\t\n\tdst = kaddr;\n\tidx = 0;\n\twhile (len > 0) {\n\t\tbcopy(copyinfo[idx].hva, dst, copyinfo[idx].len);\n\t\tlen -= copyinfo[idx].len;\n\t\tdst += copyinfo[idx].len;\n\t\tidx++;\n\t}\n}\n\nvoid\nvm_copyout(UNUSED struct vm *vm, UNUSED int vcpuid, const void *kaddr,\n    struct vm_copyinfo *copyinfo, size_t len)\n{\n\tconst char *src;\n\tint idx;\n\n\tsrc = kaddr;\n\tidx = 0;\n\twhile (len > 0) {\n\t\tbcopy(src, copyinfo[idx].hva, copyinfo[idx].len);\n\t\tlen -= copyinfo[idx].len;\n\t\tsrc += copyinfo[idx].len;\n\t\tidx++;\n\t}\n}\n"
  },
  {
    "path": "src/vmm/vmm_api.c",
    "content": "/*-\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <string.h>\n#include <assert.h>\n#include <errno.h>\n#include <sys/time.h>\n#include <sys/uio.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/vmm_instruction_emul.h>\n#include <xhyve/vmm/vmm_callout.h>\n#include <xhyve/vmm/vmm_stat.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vhpet.h>\n#include <xhyve/vmm/io/vioapic.h>\n#include <xhyve/vmm/io/vrtc.h>\n\nstatic struct vm *vm;\nstatic int memflags;\nstatic uint32_t lowmem_limit;\nstatic enum vm_mmap_style mmap_style;\nstatic size_t lowmem;\nstatic void *lowmem_addr;\nstatic size_t highmem;\nstatic void *highmem_addr;\n\nstatic void\nvcpu_freeze(int vcpu, bool freeze)\n{\n\tenum vcpu_state state;\n\n\tstate = (freeze) ? VCPU_FROZEN : VCPU_IDLE;\n\n\tif (vcpu_set_state(vm, vcpu, state, freeze)) {\n\t\txhyve_abort(\"vcpu_set_state failed\\n\");\n\t}\n}\n\nstatic void\nvcpu_freeze_all(bool freeze)\n{\n\tenum vcpu_state state;\n\tint vcpu;\n\n\tstate = (freeze) ? VCPU_FROZEN : VCPU_IDLE;\n\n\tfor (vcpu = 0; vcpu < VM_MAXCPU; vcpu++) {\n\t\tif (vcpu_set_state(vm, vcpu, state, freeze)) {\n\t\t\txhyve_abort(\"vcpu_set_state failed\\n\");\n\t\t}\n\t}\n}\n\nint\nxh_vm_create(void)\n{\n\tint error;\n\n\tif (vm != NULL) {\n\t\treturn (EEXIST);\n\t}\n\n\terror =\tvmm_init();\n\n\tif (error != 0) {\n\t\treturn (error);\n\t}\n\n\tmemflags = 0;\n\tlowmem_limit = (3ull << 30);\n\n\treturn (vm_create(&vm));\n}\n\nvoid\nxh_vm_destroy(void)\n{\n\tassert(vm != NULL);\n\n\tvm_destroy(vm);\n\n\tif (vmm_cleanup() == 0) {\n\t\tvm = NULL;\n\t}\n}\n\nint\nxh_vcpu_create(int vcpu)\n{\n\tassert(vm != NULL);\n\treturn (vcpu_create(vm, vcpu));\n}\n\nvoid\nxh_vcpu_destroy(int vcpu)\n{\n\tassert(vm != NULL);\n\tvcpu_destroy(vm, vcpu);\n}\n\nint\nxh_vm_get_memory_seg(uint64_t gpa, size_t *ret_len)\n{\n\tint error;\n\n\tstruct vm_memory_segment seg;\n\n\terror = vm_gpabase2memseg(vm, gpa, &seg);\n\n\tif (error == 0) {\n\t\t*ret_len = seg.len;\n\t}\n\n\treturn (error);\n}\n\nstatic int\nsetup_memory_segment(uint64_t gpa, size_t len, uint64_t prot, void **addr)\n{\n\tvoid *object;\n\tuint64_t offset;\n\tint error;\n\n\tvcpu_freeze_all(true);\n\terror = vm_malloc(vm, gpa, len, prot);\n\tif (error == 0) {\n\t\terror = vm_get_memobj(vm, gpa, len, &offset, &object);\n\t\tif (error == 0) {\n\t\t\t*addr = (void *) (((uintptr_t) object) + offset);\n\t\t}\n\t}\n\tvcpu_freeze_all(false);\n\treturn (error);\n}\n\nint\nxh_vm_setup_memory(size_t len, enum vm_mmap_style vms)\n{\n\tvoid **addr;\n\tint error;\n    const uint64_t protFlags = XHYVE_PROT_READ | XHYVE_PROT_WRITE | XHYVE_PROT_EXECUTE;\n\n\t/* XXX VM_MMAP_SPARSE not implemented yet */\n\tassert(vms == VM_MMAP_NONE || vms == VM_MMAP_ALL);\n\n\tmmap_style = vms;\n\n\t/*\n\t * If 'len' cannot fit entirely in the 'lowmem' segment then\n\t * create another 'highmem' segment above 4GB for the remainder.\n\t */\n\n\tlowmem = (len > lowmem_limit) ? lowmem_limit : len;\n\thighmem = (len > lowmem_limit) ? (len - lowmem) : 0;\n\n\tif (lowmem > 0) {\n\t\taddr = (vms == VM_MMAP_ALL) ? &lowmem_addr : NULL;\n\t\tif ((error = setup_memory_segment(0, lowmem, protFlags, addr))) {\n\t\t\treturn (error);\n\t\t}\n\t}\n\n\tif (highmem > 0) {\n\t\taddr = (vms == VM_MMAP_ALL) ? &highmem_addr : NULL;\n\t\tif ((error = setup_memory_segment((4ull << 30), highmem, protFlags, addr))) {\n\t\t\treturn (error);\n\t\t}\n\t}\n\n\treturn (0);\n}\n\nint\nxh_setup_bootrom_memory(size_t len, void **addr)\n{\n    int error;\n\n    assert(len % XHYVE_PAGE_SIZE == 0);\n\n    /* place the bootrom memory just below 4GB and mark it non-writeable */\n    uint64_t gpa = (4ull << 30) - len;\n    error = setup_memory_segment(gpa, len, XHYVE_PROT_READ | XHYVE_PROT_EXECUTE, addr);\n\n    return error;\n}\n\nint\nxh_setup_video_memory(uint64_t gpa, size_t len, void **addr)\n{\n    int error;\n\n    assert(len % XHYVE_PAGE_SIZE == 0);\n\n    /* place video memory and mark it non-executable */\n    error = setup_memory_segment(gpa, len, XHYVE_PROT_READ | XHYVE_PROT_WRITE, addr);\n\n    return error;\n}\n\nvoid *\nxh_vm_map_gpa(uint64_t gpa, size_t len)\n{\n\tassert(mmap_style == VM_MMAP_ALL);\n\n\tif ((gpa < lowmem) && (len <= lowmem) && ((gpa + len) <= lowmem)) {\n\t\treturn ((void *) (((uintptr_t) lowmem_addr) + gpa));\n\t}\n\n\tif (gpa >= (4ull << 30)) {\n\t\tgpa -= (4ull << 30);\n\t\tif ((gpa < highmem) && (len <= highmem) && ((gpa + len) <= highmem)) {\n\t\t\treturn ((void *) (((uintptr_t) highmem_addr) + gpa));\n\t\t}\n\t}\n\n\treturn (NULL);\n}\n\nint\nxh_vm_gla2gpa(int vcpu, struct vm_guest_paging *paging, uint64_t gla,\n\tint prot, uint64_t *gpa, int *fault)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_gla2gpa(vm, vcpu, paging, gla, prot, gpa, fault);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nuint32_t\nxh_vm_get_lowmem_limit(void)\n{\n\treturn (lowmem_limit);\n}\n\nvoid\nxh_vm_set_lowmem_limit(uint32_t limit)\n{\n\tlowmem_limit = limit;\n}\n\nvoid\nxh_vm_set_memflags(int flags)\n{\n\tmemflags = flags;\n}\n\nsize_t\nxh_vm_get_lowmem_size(void)\n{\n\treturn (lowmem);\n}\n\nsize_t\nxh_vm_get_highmem_size(void)\n{\n\treturn (highmem);\n}\n\nint\nxh_vm_set_desc(int vcpu, int reg, uint64_t base, uint32_t limit,\n\tuint32_t access)\n{\n\tstruct seg_desc sd;\n\tint error;\n\n\tsd.base = base;\n\tsd.limit = limit;\n\tsd.access = access;\n\tvcpu_freeze(vcpu, true);\n\terror = vm_set_seg_desc(vm, vcpu, reg, &sd);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_get_desc(int vcpu, int reg, uint64_t *base, uint32_t *limit,\n\tuint32_t *access)\n{\n\tstruct seg_desc sd;\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_get_seg_desc(vm, vcpu, reg, &sd);\n\tif (error == 0) {\n\t\t*base = sd.base;\n\t\t*limit = sd.limit;\n\t\t*access = sd.access;\n\t} \n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\t\n}\n\nint\nxh_vm_get_seg_desc(int vcpu, int reg, struct seg_desc *seg_desc)\n{\n\tint error;\n\n\terror = xh_vm_get_desc(vcpu, reg, &seg_desc->base, &seg_desc->limit,\n\t\t&seg_desc->access);\n\n\treturn (error);\n}\n\nint\nxh_vm_set_register(int vcpu, int reg, uint64_t val)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_set_register(vm, vcpu, reg, val);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\t\n}\n\nint\nxh_vm_get_register(int vcpu, int reg, uint64_t *retval)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_get_register(vm, vcpu, reg, retval);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_run(int vcpu, struct vm_exit *ret_vmexit)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_run(vm, vcpu, ret_vmexit);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_suspend(enum vm_suspend_how how)\n{\n\treturn (vm_suspend(vm, how));\n}\n\nint\nxh_vm_reinit(void)\n{\n\tint error;\n\n\tvcpu_freeze_all(true);\n\terror = vm_reinit(vm);\n\tvcpu_freeze_all(false);\n\n\treturn (error);\n}\n\nint\nxh_vm_apicid2vcpu(int apicid)\n{\n\treturn (apicid);\n}\n\nint\nxh_vm_inject_exception(int vcpu, int vector, int errcode_valid,\n\tuint32_t errcode, int restart_instruction)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_inject_exception(vm, vcpu, vector, errcode_valid, errcode,\n\t\trestart_instruction);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_lapic_irq(int vcpu, int vector)\n{\n\treturn (lapic_intr_edge(vm, vcpu, vector));\n}\n\nint\nxh_vm_lapic_local_irq(int vcpu, int vector)\n{\n\treturn (lapic_set_local_intr(vm, vcpu, vector));\n}\n\nint\nxh_vm_lapic_msi(uint64_t addr, uint64_t msg)\n{\n\treturn (lapic_intr_msi(vm, addr, msg));\n}\n\nint\nxh_vm_ioapic_assert_irq(int irq)\n{\n\treturn (vioapic_assert_irq(vm, irq));\n}\n\nint\nxh_vm_ioapic_deassert_irq(int irq)\n{\n\treturn (vioapic_deassert_irq(vm, irq));\n}\n\nint\nxh_vm_ioapic_pulse_irq(int irq)\n{\n\treturn (vioapic_pulse_irq(vm, irq));\n}\n\nint\nxh_vm_ioapic_pincount(int *pincount)\n{\n\t*pincount = vioapic_pincount(vm);\n\treturn (0);\n}\n\nint\nxh_vm_isa_assert_irq(int atpic_irq, int ioapic_irq)\n{\n\tint error;\n\n\terror = vatpic_assert_irq(vm, atpic_irq);\n\n\tif ((error == 0) && (ioapic_irq != -1)) {\n\t\terror = vioapic_assert_irq(vm, ioapic_irq);\n\t}\n\n\treturn (error);\n}\n\nint\nxh_vm_isa_deassert_irq(int atpic_irq, int ioapic_irq)\n{\n\tint error;\n\n\terror = vatpic_deassert_irq(vm, atpic_irq);\n\tif ((error == 0) && (ioapic_irq != -1)) {\n\t\terror = vioapic_deassert_irq(vm, ioapic_irq);\n\t}\n\n\treturn (error);\n}\n\nint\nxh_vm_isa_pulse_irq(int atpic_irq, int ioapic_irq)\n{\n\tint error;\n\n\terror = vatpic_pulse_irq(vm, atpic_irq);\n\tif ((error == 0) && (ioapic_irq != -1)) {\n\t\terror = vioapic_pulse_irq(vm, ioapic_irq);\n\t}\n\n\treturn (error);\n}\n\nint\nxh_vm_isa_set_irq_trigger(int atpic_irq, enum vm_intr_trigger trigger)\n{\n\treturn (vatpic_set_irq_trigger(vm, atpic_irq, trigger));\n}\n\nint\nxh_vm_inject_nmi(int vcpu)\n{\n\treturn (vm_inject_nmi(vm, vcpu));\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstatic struct {\n\tconst char *name;\n\tint type;\n} capstrmap[] = {\n\t{ \"hlt_exit\", VM_CAP_HALT_EXIT },\n\t{ \"mtrap_exit\", VM_CAP_MTRAP_EXIT },\n\t{ \"pause_exit\", VM_CAP_PAUSE_EXIT },\n\t{ NULL, 0 }\n};\n#pragma clang diagnostic pop\n\nint\nxh_vm_capability_name2type(const char *capname)\n{\n\tint i;\n\n\tfor (i = 0; (capstrmap[i].name != NULL) && (capname != NULL); i++) {\n\t\tif (strcmp(capstrmap[i].name, capname) == 0) {\n\t\t\treturn (capstrmap[i].type);\n\t\t}\n\t}\n\n\treturn (-1);\n}\n\nconst char *\nxh_vm_capability_type2name(int type)\n{\n\tint i;\n\n\tfor (i = 0; (capstrmap[i].name != NULL); i++) {\n\t\tif (capstrmap[i].type == type) {\n\t\t\treturn (capstrmap[i].name);\n\t\t}\n\t}\n\n\treturn (NULL);\n}\n\nint\nxh_vm_get_capability(int vcpu, enum vm_cap_type cap, int *retval)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_get_capability(vm, vcpu, (int) cap, retval);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_set_capability(int vcpu, enum vm_cap_type cap, int val)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_set_capability(vm, vcpu, (int) cap, val);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\t\n}\n\nint\nxh_vm_get_intinfo(int vcpu, uint64_t *i1, uint64_t *i2)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_get_intinfo(vm, vcpu, i1, i2);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\t\n}\n\nint\nxh_vm_set_intinfo(int vcpu, uint64_t exit_intinfo)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_exit_intinfo(vm, vcpu, exit_intinfo);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\t\n}\n\nuint64_t *\nxh_vm_get_stats(int vcpu, struct timeval *ret_tv, int *ret_entries)\n{\n\tstatic uint64_t statbuf[64];\n\tstruct timeval tv;\n\tint re;\n\tint error;\n\n\tgetmicrotime(&tv);\n\terror = vmm_stat_copy(vm, vcpu, &re, ((uint64_t *) &statbuf));\n\n\tif (error == 0) {\n\t\tif (ret_entries) {\n\t\t\t*ret_entries = re;\n\t\t}\n\t\tif (ret_tv) {\n\t\t\t*ret_tv = tv;\n\t\t}\n\t\treturn (((uint64_t *) &statbuf));\n\t} else {\n\t\treturn (NULL);\n\t}\n}\n\nconst char *\nxh_vm_get_stat_desc(int index)\n{\n\tstatic char desc[128];\n\n\tif (vmm_stat_desc_copy(index, ((char *) &desc), sizeof(desc)) == 0) {\n\t\treturn (desc);\n\t} else {\n\t\treturn (NULL);\n\t}\n}\n\nint\nxh_vm_get_x2apic_state(int vcpu, enum x2apic_state *s)\n{\n\treturn (vm_get_x2apic_state(vm, vcpu, s));\n}\n\nint\nxh_vm_set_x2apic_state(int vcpu, enum x2apic_state s)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_set_x2apic_state(vm, vcpu, s);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_get_hpet_capabilities(uint32_t *capabilities)\n{\n\treturn (vhpet_getcap(capabilities));\n}\n\nint\nxh_vm_copy_setup(int vcpu, struct vm_guest_paging *pg, uint64_t gla, size_t len,\n\tint prot, struct iovec *iov, int iovcnt, int *fault)\n{\n\tvoid *va;\n\tuint64_t gpa;\n\tsize_t n, off;\n\tint i, error;\n\n\tfor (i = 0; i < iovcnt; i++) {\n\t\tiov[i].iov_base = 0;\n\t\tiov[i].iov_len = 0;\n\t}\n\n\twhile (len) {\n\t\tassert(iovcnt > 0);\n\n\t\terror = xh_vm_gla2gpa(vcpu, pg, gla, prot, &gpa, fault);\n\t\tif ((error) || *fault) {\n\t\t\treturn (error);\n\t\t}\n\n\t\toff = gpa & XHYVE_PAGE_MASK;\n\t\tn = min(len, XHYVE_PAGE_SIZE - off);\n\n\t\tva = xh_vm_map_gpa(gpa, n);\n\t\tif (va == NULL) {\n\t\t\treturn (EFAULT);\n\t\t}\n\n\t\tiov->iov_base = va;\n\t\tiov->iov_len = n;\n\t\tiov++;\n\t\tiovcnt--;\n\n\t\tgla += n;\n\t\tlen -= n;\n\t}\n\n\treturn (0);\n}\n\nvoid\nxh_vm_copyin(struct iovec *iov, void *dst, size_t len)\n{\n\tconst char *src;\n\tchar *d;\n\tsize_t n;\n\n\td = dst;\n\twhile (len) {\n\t\tassert(iov->iov_len);\n\t\tn = min(len, iov->iov_len);\n\t\tsrc = iov->iov_base;\n\t\tbcopy(src, d, n);\n\t\tiov++;\n\t\td += n;\n\t\tlen -= n;\n\t}\n}\n\nvoid\nxh_vm_copyout(const void *src, struct iovec *iov, size_t len)\n{\n\tconst char *s;\n\tchar *dst;\n\tsize_t n;\n\n\ts = src;\n\twhile (len) {\n\t\tassert(iov->iov_len);\n\t\tn = min(len, iov->iov_len);\n\t\tdst = iov->iov_base;\n\t\tbcopy(s, dst, n);\n\t\tiov++;\n\t\ts += n;\n\t\tlen -= n;\n\t}\n}\n\nint\nxh_vm_rtc_write(int offset, uint8_t value)\n{\n\treturn (vrtc_nvram_write(vm, offset, value));\n}\n\nint\nxh_vm_rtc_read(int offset, uint8_t *retval)\n{\n\treturn (vrtc_nvram_read(vm, offset, retval));\n}\n\nint\nxh_vm_rtc_settime(time_t secs)\n{\n\treturn (vrtc_set_time(vm, secs));\n}\n\nint\nxh_vm_rtc_gettime(time_t *secs)\n{\n\t*secs = vrtc_get_time(vm);\n\treturn (0);\n}\n\nint\nxh_vcpu_reset(int vcpu)\n{\n\tint error;\n\n#define SET_REG(r, v) (error = xh_vm_set_register(vcpu, (r), (v)))\n#define SET_DESC(d, b, l, a) (error = xh_vm_set_desc(vcpu, (d), (b), (l), (a)))\n\n\tif (SET_REG(VM_REG_GUEST_RFLAGS, 0x2) ||\n\t\tSET_REG(VM_REG_GUEST_RIP, 0xfff0) ||\n\t\tSET_REG(VM_REG_GUEST_CR0, CR0_NE) ||\n\t\tSET_REG(VM_REG_GUEST_CR3, 0) ||\n\t\tSET_REG(VM_REG_GUEST_CR4, 0) ||\n\t\tSET_REG(VM_REG_GUEST_CS, 0xf000) ||\n\t\tSET_REG(VM_REG_GUEST_SS, 0) ||\n\t\tSET_REG(VM_REG_GUEST_DS, 0) ||\n\t\tSET_REG(VM_REG_GUEST_ES, 0) ||\n\t\tSET_REG(VM_REG_GUEST_FS, 0) ||\n\t\tSET_REG(VM_REG_GUEST_GS, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RAX, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RBX, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RCX, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RDX, 0xf00) ||\n\t\tSET_REG(VM_REG_GUEST_RSI, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RDI, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RBP, 0) ||\n\t\tSET_REG(VM_REG_GUEST_RSP, 0) ||\n\t\tSET_REG(VM_REG_GUEST_TR, 0) ||\n\t\tSET_REG(VM_REG_GUEST_LDTR, 0) ||\n\t\tSET_DESC(VM_REG_GUEST_CS, 0xffff0000, 0xffff, 0x0093) ||\n\t\tSET_DESC(VM_REG_GUEST_SS, 0, 0xffff, 0x0093) ||\n\t\tSET_DESC(VM_REG_GUEST_DS, 0, 0xffff, 0x0093) ||\n\t\tSET_DESC(VM_REG_GUEST_ES, 0, 0xffff, 0x0093) ||\n\t\tSET_DESC(VM_REG_GUEST_FS, 0, 0xffff, 0x0093) ||\n\t\tSET_DESC(VM_REG_GUEST_GS, 0, 0xffff, 0x0093) ||\n\t\tSET_DESC(VM_REG_GUEST_GDTR, 0, 0xffff, 0) ||\n\t\tSET_DESC(VM_REG_GUEST_IDTR, 0, 0xffff, 0) ||\n\t\tSET_DESC(VM_REG_GUEST_TR, 0, 0, 0x0000008b) ||\n\t\tSET_DESC(VM_REG_GUEST_LDTR, 0, 0xffff, 0x00000082))\n\t{\n\t\treturn (error);\n\t}\n\n\treturn (0);\n}\n\nint\nxh_vm_active_cpus(cpuset_t *cpus)\n{\n\t*cpus = vm_active_cpus(vm);\n\treturn (0);\n}\n\nint\nxh_vm_suspended_cpus(cpuset_t *cpus)\n{\n\t*cpus = vm_suspended_cpus(vm);\n\treturn (0);\n}\n\nint\nxh_vm_activate_cpu(int vcpu)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_activate_cpu(vm, vcpu);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_restart_instruction(int vcpu)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vm_restart_instruction(vm, vcpu);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n\nint\nxh_vm_emulate_instruction(int vcpu, uint64_t gpa, struct vie *vie,\n\tstruct vm_guest_paging *paging, mem_region_read_t memread,\n\tmem_region_write_t memwrite, void *memarg)\n{\n\tint error;\n\n\tvcpu_freeze(vcpu, true);\n\terror = vmm_emulate_instruction(vm, vcpu, gpa, vie, paging, memread,\n\t\tmemwrite, memarg);\n\tvcpu_freeze(vcpu, false);\n\n\treturn (error);\n}\n"
  },
  {
    "path": "src/vmm/vmm_callout.c",
    "content": "/*-\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdio.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdlib.h>\n#include <errno.h>\n#include <sys/time.h>\n#include <mach/mach.h>\n#include <mach/mach_time.h>\n#include <dispatch/dispatch.h>\n\n#include <xhyve/vmm/vmm_callout.h>\n\nstatic mach_timebase_info_data_t timebase_info;\nstatic dispatch_queue_t queue;\nstatic bool initialized = false;\nint tc_precexp;\n\nstatic inline uint64_t nanos_to_mat(uint64_t nanos) {\n  return (nanos * timebase_info.denom) / timebase_info.numer;\n}\n\nstatic inline uint64_t mat_to_nanos(uint64_t abs) {\n  return (abs * timebase_info.numer) / timebase_info.denom;\n}\n\nstatic inline uint64_t sbt_to_nanos(sbintime_t sbt) {\n  uint64_t s, ns;\n\n  s = (((uint64_t) sbt) >> 32);\n  ns = (((uint64_t) 1000000000) * (uint32_t) sbt) >> 32;\n\n  return (s * 1000000000) + ns;\n}\n\nstatic inline uint64_t sbt_to_mat(sbintime_t sbt) {\n  return nanos_to_mat(sbt_to_nanos(sbt));\n}\n\nvoid binuptime(struct bintime *bt) {\n  uint64_t ns;\n  \n  ns = mat_to_nanos(mach_absolute_time());\n\n  bt->sec = (ns / 1000000000);\n  bt->frac = (((ns % 1000000000) * (((uint64_t) 1 << 63) / 500000000)));\n}\n\nvoid getmicrotime(struct timeval *tv) {\n  uint64_t ns, sns;\n\n  ns = mat_to_nanos(mach_absolute_time());\n\n  sns = (ns / 1000000000);\n  tv->tv_sec = (long) sns;\n  tv->tv_usec = (int) ((ns - sns) / 1000);\n}\n\nstatic void dispatcher(void* data) {\n  struct callout *c = (struct callout *) data;\n\n  if (!(c->flags & (CALLOUT_ACTIVE | CALLOUT_PENDING))) {\n    abort();\n  }\n\n  c->flags &= ~CALLOUT_PENDING;\n\n  dispatch_group_enter(c->group);\n\n  c->callout(c->argument);\n\n  /* note: after the handler has been invoked the callout structure can look\n   *       much differently, the handler may have rescheduled the callout or\n   *       even freed it.\n   *\n   *       if the callout is still enqueued it means that it hasn't been\n   *       freed by the user\n   *\n   *       reset || drain || !stop\n   */\n\n  if (c->queued) {\n    /* if the callout hasn't been rescheduled, remove it */\n    if (((c->flags & CALLOUT_PENDING) == 0) || (c->flags & CALLOUT_WAITING)) {\n      dispatch_suspend(c->timer);\n      c->queued = 0;\n      c->flags |= CALLOUT_COMPLETED;\n    }\n  }\n\n  dispatch_group_leave(c->group);\n}\n\nvoid callout_init(struct callout *c, int mpsafe) {\n  if (!mpsafe) {\n    abort();\n  }\n\n  memset(c, 0, sizeof(struct callout));\n\n  c->group = dispatch_group_create();\n  c->timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);\n  dispatch_set_context(c->timer, c);\n  dispatch_source_set_event_handler_f(c->timer, dispatcher);\n}\n\nint callout_stop_safe(struct callout *c, int drain) {\n  int result = 0;\n\n  if (drain) {\n    if ((callout_pending(c) || (callout_active(c) && !callout_completed(c)))) {\n      if (c->flags & CALLOUT_WAITING) {\n        abort();\n      }\n\n      /* wait for callout */\n      c->flags |= CALLOUT_WAITING;\n\n      dispatch_group_wait(c->group, DISPATCH_TIME_FOREVER);\n\n      c->flags &= ~CALLOUT_WAITING;\n      result = 1;\n    }\n\n    /* According to the FreeBSD manpages, callout_drain has to be called prior to\n       releasing the storage for the callout structure, thus it's a good place to \n       release the dispatch_source. NOTE: this makes the structure unusable! */\n    dispatch_release(c->group);\n    dispatch_release(c->timer);\n  }\n\n  if (c->queued) {\n    dispatch_suspend(c->timer);\n    c->queued = 0;\n  }\n\n  /* clear flags */\n  c->flags &= ~(CALLOUT_ACTIVE | CALLOUT_PENDING | CALLOUT_COMPLETED | CALLOUT_WAITING);\n\n  return result;\n}\n\nint callout_reset_sbt(struct callout *c, sbintime_t sbt, sbintime_t precision,\n                      void (*ftn)(void *), void *arg, int flags) {\n  int result;\n\n  if (!((flags == 0) || (flags == C_ABSOLUTE)) || (c->flags != 0)) {\n    /* FIXME */\n    //printf(\"XHYVE: callout_reset_sbt 0x%08x 0x%08x\\r\\n\", flags, c->flags);\n    //abort();\n  }\n\n  c->timeout = sbt_to_mat(sbt);\n\n  if (flags != C_ABSOLUTE) {\n    c->timeout += mach_absolute_time();\n  }\n\n  c->precision = sbt_to_nanos(precision);\n\n  result = callout_stop_safe(c, 0);\n\n  c->callout = ftn;\n  c->argument = arg;\n  c->flags |= (CALLOUT_PENDING | CALLOUT_ACTIVE);\n\n  dispatch_source_set_timer(c->timer, c->timeout, DISPATCH_TIME_FOREVER, c->precision);\n  dispatch_resume(c->timer);\n  c->queued = 1;\n\n  return result;\n}\n\nvoid callout_system_init(void) {\n  if (initialized) {\n    return;\n  }\n\n  mach_timebase_info(&timebase_info);\n\n  queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);\n\n  tc_precexp = 4; // by default in sys/kern/kern_tc.c\n\n  initialized = true;\n}\n"
  },
  {
    "path": "src/vmm/vmm_host.c",
    "content": "/*-\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <sys/sysctl.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_host.h>\n\nstatic struct xsave_limits vmm_xsave_limits;\n\nvoid\nvmm_host_state_init(void)\n{\n\tuint32_t avx1_0, regs[4];\n\tsize_t ln;\n\n\tvmm_xsave_limits.xsave_enabled = 0;\n\n\tln = sizeof(uint32_t);\n\tif (!sysctlbyname(\"hw.optional.avx1_0\", &avx1_0, &ln, NULL, 0) && avx1_0) {\n\t\tcpuid_count(0xd, 0x0, regs);\n\t\tvmm_xsave_limits.xsave_enabled = 1;\n\t\tvmm_xsave_limits.xcr0_allowed = XFEATURE_AVX;\n\t\tvmm_xsave_limits.xsave_max_size = regs[1];\n\t}\n}\n\nconst struct xsave_limits *\nvmm_get_xsave_limits(void)\n{\n\treturn (&vmm_xsave_limits);\n}\n"
  },
  {
    "path": "src/vmm/vmm_instruction_emul.c",
    "content": "/*-\n * Copyright (c) 2012 Sandvine, Inc.\n * Copyright (c) 2012 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <strings.h>\n#include <errno.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/psl.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm_instruction_emul.h>\n\n#define PG_V 0x001 /* P\tValid */\n#define PG_RW 0x002 /* R/W Read/Write */\n#define PG_U 0x004 /* U/S  User/Supervisor */\n#define PG_A 0x020 /* A\tAccessed */\n#define PG_M 0x040 /* D\tDirty */\n#define PG_PS 0x080 /* PS Page size (0=4k,1=4M) */\n#define PGEX_P 0x01 /* Protection violation vs. not present */\n#define PGEX_W 0x02 /* during a Write cycle */\n#define PGEX_U 0x04 /* access from User mode (UPL) */\n#define PGEX_RSV 0x08 /* reserved PTE field is non-zero */\n#define PGEX_I 0x10 /* during an instruction fetch */\n\n/* struct vie_op.op_type */\nenum {\n\tVIE_OP_TYPE_NONE = 0,\n\tVIE_OP_TYPE_MOV,\n\tVIE_OP_TYPE_MOVSX,\n\tVIE_OP_TYPE_MOVZX,\n\tVIE_OP_TYPE_AND,\n\tVIE_OP_TYPE_OR,\n\tVIE_OP_TYPE_SUB,\n\tVIE_OP_TYPE_TWO_BYTE,\n\tVIE_OP_TYPE_PUSH,\n\tVIE_OP_TYPE_CMP,\n\tVIE_OP_TYPE_POP,\n\tVIE_OP_TYPE_MOVS,\n\tVIE_OP_TYPE_GROUP1,\n\tVIE_OP_TYPE_STOS,\n\tVIE_OP_TYPE_BITTEST,\n\tVIE_OP_TYPE_TEST,\n\tVIE_OP_TYPE_LAST\n};\n\n/* struct vie_op.op_flags */\n#define\tVIE_OP_F_IMM\t\t(1 << 0)  /* 16/32-bit immediate operand */\n#define\tVIE_OP_F_IMM8\t\t(1 << 1)  /* 8-bit immediate operand */\n#define\tVIE_OP_F_MOFFSET\t(1 << 2)  /* 16/32/64-bit immediate moffset */\n#define\tVIE_OP_F_NO_MODRM\t(1 << 3)\n#define\tVIE_OP_F_NO_GLA_VERIFICATION (1 << 4)\n\nstatic const struct vie_op two_byte_opcodes[256] = {\n\t[0xB6] = {\n\t\t.op_byte = 0xB6,\n\t\t.op_type = VIE_OP_TYPE_MOVZX,\n\t},\n\t[0xB7] = {\n\t\t.op_byte = 0xB7,\n\t\t.op_type = VIE_OP_TYPE_MOVZX,\n\t},\n\t[0xBA] = {\n\t\t.op_byte = 0xBA,\n\t\t.op_type = VIE_OP_TYPE_BITTEST,\n\t\t.op_flags = VIE_OP_F_IMM8,\n\t},\n\t[0xBE] = {\n\t\t.op_byte = 0xBE,\n\t\t.op_type = VIE_OP_TYPE_MOVSX,\n\t},\n};\n\nstatic const struct vie_op one_byte_opcodes[256] = {\n\t[0x0F] = {\n\t\t.op_byte = 0x0F,\n\t\t.op_type = VIE_OP_TYPE_TWO_BYTE\n\t},\n\t[0x2B] = {\n\t\t.op_byte = 0x2B,\n\t\t.op_type = VIE_OP_TYPE_SUB,\n\t},\n\t[0x3B] = {\n\t\t.op_byte = 0x3B,\n\t\t.op_type = VIE_OP_TYPE_CMP,\n\t},\n\t[0x88] = {\n\t\t.op_byte = 0x88,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t},\n\t[0x89] = {\n\t\t.op_byte = 0x89,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t},\n\t[0x8A] = {\n\t\t.op_byte = 0x8A,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t},\n\t[0x8B] = {\n\t\t.op_byte = 0x8B,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t},\n\t[0xA1] = {\n\t\t.op_byte = 0xA1,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t\t.op_flags = VIE_OP_F_MOFFSET | VIE_OP_F_NO_MODRM,\n\t},\n\t[0xA3] = {\n\t\t.op_byte = 0xA3,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t\t.op_flags = VIE_OP_F_MOFFSET | VIE_OP_F_NO_MODRM,\n\t},\n\t[0xA4] = {\n\t\t.op_byte = 0xA4,\n\t\t.op_type = VIE_OP_TYPE_MOVS,\n\t\t.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION\n\t},\n\t[0xA5] = {\n\t\t.op_byte = 0xA5,\n\t\t.op_type = VIE_OP_TYPE_MOVS,\n\t\t.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION\n\t},\n\t[0xAA] = {\n\t\t.op_byte = 0xAA,\n\t\t.op_type = VIE_OP_TYPE_STOS,\n\t\t.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION\n\t},\n\t[0xAB] = {\n\t\t.op_byte = 0xAB,\n\t\t.op_type = VIE_OP_TYPE_STOS,\n\t\t.op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION\n\t},\n\t[0xC6] = {\n\t\t/* XXX Group 11 extended opcode - not just MOV */\n\t\t.op_byte = 0xC6,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t\t.op_flags = VIE_OP_F_IMM8,\n\t},\n\t[0xC7] = {\n\t\t.op_byte = 0xC7,\n\t\t.op_type = VIE_OP_TYPE_MOV,\n\t\t.op_flags = VIE_OP_F_IMM,\n\t},\n\t[0x23] = {\n\t\t.op_byte = 0x23,\n\t\t.op_type = VIE_OP_TYPE_AND,\n\t},\n\t[0x80] = {\n\t\t/* Group 1 extended opcode */\n\t\t.op_byte = 0x80,\n\t\t.op_type = VIE_OP_TYPE_GROUP1,\n\t\t.op_flags = VIE_OP_F_IMM8,\n\t},\n\t[0x81] = {\n\t\t/* Group 1 extended opcode */\n\t\t.op_byte = 0x81,\n\t\t.op_type = VIE_OP_TYPE_GROUP1,\n\t\t.op_flags = VIE_OP_F_IMM,\n\t},\n\t[0x83] = {\n\t\t/* Group 1 extended opcode */\n\t\t.op_byte = 0x83,\n\t\t.op_type = VIE_OP_TYPE_GROUP1,\n\t\t.op_flags = VIE_OP_F_IMM8,\n\t},\n\t[0x8F] = {\n\t\t/* XXX Group 1A extended opcode - not just POP */\n\t\t.op_byte = 0x8F,\n\t\t.op_type = VIE_OP_TYPE_POP,\n\t},\n\t[0xF7] = {\n\t\t/* XXX Group 3 extended opcode - not just TEST */\n\t\t.op_byte = 0xF7,\n\t\t.op_type = VIE_OP_TYPE_TEST,\n\t\t.op_flags = VIE_OP_F_IMM,\n\t},\n\t[0xFF] = {\n\t\t/* XXX Group 5 extended opcode - not just PUSH */\n\t\t.op_byte = 0xFF,\n\t\t.op_type = VIE_OP_TYPE_PUSH,\n\t}\n};\n\n/* struct vie.mod */\n#define\tVIE_MOD_INDIRECT\t\t0\n#define\tVIE_MOD_INDIRECT_DISP8\t\t1\n#define\tVIE_MOD_INDIRECT_DISP32\t\t2\n#define\tVIE_MOD_DIRECT\t\t\t3\n\n/* struct vie.rm */\n#define\tVIE_RM_SIB\t\t\t4\n#define\tVIE_RM_DISP32\t\t\t5\n\n#define\tGB\t\t\t\t(1024 * 1024 * 1024)\n\nstatic enum vm_reg_name gpr_map[16] = {\n\tVM_REG_GUEST_RAX,\n\tVM_REG_GUEST_RCX,\n\tVM_REG_GUEST_RDX,\n\tVM_REG_GUEST_RBX,\n\tVM_REG_GUEST_RSP,\n\tVM_REG_GUEST_RBP,\n\tVM_REG_GUEST_RSI,\n\tVM_REG_GUEST_RDI,\n\tVM_REG_GUEST_R8,\n\tVM_REG_GUEST_R9,\n\tVM_REG_GUEST_R10,\n\tVM_REG_GUEST_R11,\n\tVM_REG_GUEST_R12,\n\tVM_REG_GUEST_R13,\n\tVM_REG_GUEST_R14,\n\tVM_REG_GUEST_R15\n};\n\nstatic uint64_t size2mask[] = {\n\t[1] = 0xff,\n\t[2] = 0xffff,\n\t[4] = 0xffffffff,\n\t[8] = 0xffffffffffffffff,\n};\n\nstatic int\nvie_read_register(void *vm, int vcpuid, enum vm_reg_name reg, uint64_t *rval)\n{\n\tint error;\n\n\terror = vm_get_register(vm, vcpuid, (int) reg, rval);\n\n\treturn (error);\n}\n\nstatic void\nvie_calc_bytereg(struct vie *vie, enum vm_reg_name *reg, int *lhbr)\n{\n\t*lhbr = 0;\n\t*reg = gpr_map[vie->reg];\n\n\t/*\n\t * 64-bit mode imposes limitations on accessing legacy high byte\n\t * registers (lhbr).\n\t *\n\t * The legacy high-byte registers cannot be addressed if the REX\n\t * prefix is present. In this case the values 4, 5, 6 and 7 of the\n\t * 'ModRM:reg' field address %spl, %bpl, %sil and %dil respectively.\n\t *\n\t * If the REX prefix is not present then the values 4, 5, 6 and 7\n\t * of the 'ModRM:reg' field address the legacy high-byte registers,\n\t * %ah, %ch, %dh and %bh respectively.\n\t */\n\tif (!vie->rex_present) {\n\t\tif (vie->reg & 0x4) {\n\t\t\t*lhbr = 1;\n\t\t\t*reg = gpr_map[vie->reg & 0x3];\n\t\t}\n\t}\n}\n\nstatic int\nvie_read_bytereg(void *vm, int vcpuid, struct vie *vie, uint8_t *rval)\n{\n\tuint64_t val;\n\tint error, lhbr;\n\tenum vm_reg_name reg;\n\n\tvie_calc_bytereg(vie, &reg, &lhbr);\n\terror = vm_get_register(vm, vcpuid, (int) reg, &val);\n\n\t/*\n\t * To obtain the value of a legacy high byte register shift the\n\t * base register right by 8 bits (%ah = %rax >> 8).\n\t */\n\tif (lhbr)\n\t\t*rval = (uint8_t) (val >> 8);\n\telse\n\t\t*rval = (uint8_t) val;\n\treturn (error);\n}\n\nstatic int\nvie_write_bytereg(void *vm, int vcpuid, struct vie *vie, uint8_t byte)\n{\n\tuint64_t origval, val, mask;\n\tint error, lhbr;\n\tenum vm_reg_name reg;\n\n\tvie_calc_bytereg(vie, &reg, &lhbr);\n\terror = vm_get_register(vm, vcpuid, (int) reg, &origval);\n\tif (error == 0) {\n\t\tval = byte;\n\t\tmask = 0xff;\n\t\tif (lhbr) {\n\t\t\t/*\n\t\t\t * Shift left by 8 to store 'byte' in a legacy high\n\t\t\t * byte register.\n\t\t\t */\n\t\t\tval <<= 8;\n\t\t\tmask <<= 8;\n\t\t}\n\t\tval |= origval & ~mask;\n\t\terror = vm_set_register(vm, vcpuid, (int) reg, val);\n\t}\n\treturn (error);\n}\n\nint\nvie_update_register(void *vm, int vcpuid, enum vm_reg_name reg,\n\t\t    uint64_t val, int size)\n{\n\tint error;\n\tuint64_t origval;\n\n\tswitch (size) {\n\tcase 1:\n\tcase 2:\n\t\terror = vie_read_register(vm, vcpuid, reg, &origval);\n\t\tif (error)\n\t\t\treturn (error);\n\t\tval &= size2mask[size];\n\t\tval |= origval & ~size2mask[size];\n\t\tbreak;\n\tcase 4:\n\t\tval &= 0xffffffffUL;\n\t\tbreak;\n\tcase 8:\n\t\tbreak;\n\tdefault:\n\t\treturn (EINVAL);\n\t}\n\n\terror = vm_set_register(vm, vcpuid, (int) reg, val);\n\treturn (error);\n}\n\n#define\tRFLAGS_STATUS_BITS    (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_V)\n\n/*\n * Return the status flags that would result from doing (x - y).\n */\n#define\tGETCC(sz)\t\t\t\t\t\t\t\\\nstatic u_long\t\t\t\t\t\t\t\t\\\ngetcc##sz(uint##sz##_t x, uint##sz##_t y)\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tu_long rflags;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t__asm __volatile(\"sub %2,%1; pushfq; popq %0\" :\t\t\t\\\n\t    \"=r\" (rflags), \"+r\" (x) : \"m\" (y));\t\t\t\t\\\n\treturn (rflags);\t\t\t\t\t\t\\\n} struct __hack\n\nGETCC(8);\nGETCC(16);\nGETCC(32);\nGETCC(64);\n\nstatic u_long\ngetcc(int opsize, uint64_t x, uint64_t y)\n{\n\tKASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8,\n\t    (\"getcc: invalid operand size %d\", opsize));\n\n\tif (opsize == 1)\n\t\treturn (getcc8(((uint8_t) x), ((uint8_t) y)));\n\telse if (opsize == 2)\n\t\treturn (getcc16(((uint16_t) x), ((uint16_t) y)));\n\telse if (opsize == 4)\n\t\treturn (getcc32(((uint32_t) x), ((uint32_t) y)));\n\telse\n\t\treturn (getcc64(x, y));\n}\n\n/*\n * Return the status flags that would result from doing (x & y).\n */\n#define\tGETANDFLAGS(sz)\t\t\t\t\t\t\t\\\nstatic u_long\t\t\t\t\t\t\t\t\\\ngetandflags##sz(uint##sz##_t x, uint##sz##_t y)\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tu_long rflags;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\\\n\t__asm __volatile(\"and %2,%1; pushfq; popq %0\" :\t\t\t\\\n\t    \"=r\" (rflags), \"+r\" (x) : \"m\" (y));\t\t\t\t\\\n\treturn (rflags);\t\t\t\t\t\t\\\n} struct __hack\n\nGETANDFLAGS(8);\nGETANDFLAGS(16);\nGETANDFLAGS(32);\nGETANDFLAGS(64);\n\nstatic u_long\ngetandflags(int opsize, uint64_t x, uint64_t y)\n{\n\tKASSERT(opsize == 1 || opsize == 2 || opsize == 4 || opsize == 8,\n\t    (\"getandflags: invalid operand size %d\", opsize));\n\n\tif (opsize == 1)\n\t\treturn (getandflags8((uint8_t) x, (uint8_t) y));\n\telse if (opsize == 2)\n\t\treturn (getandflags16((uint16_t) x, (uint16_t) y));\n\telse if (opsize == 4)\n\t\treturn (getandflags32((uint32_t) x, (uint32_t) y));\n\telse\n\t\treturn (getandflags64(x, y));\n}\n\nstatic int\nemulate_mov(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n\t    mem_region_read_t memread, mem_region_write_t memwrite, void *arg)\n{\n\tint error, size;\n\tenum vm_reg_name reg;\n\tuint8_t byte;\n\tuint64_t val;\n\n\tsize = vie->opsize;\n\terror = EINVAL;\n\n\tswitch (vie->op.op_byte) {\n\tcase 0x88:\n\t\t/*\n\t\t * MOV byte from reg (ModRM:reg) to mem (ModRM:r/m)\n\t\t * 88/r:\tmov r/m8, r8\n\t\t * REX + 88/r:\tmov r/m8, r8 (%ah, %ch, %dh, %bh not available)\n\t\t */\n\t\tsize = 1;\t/* override for byte operation */\n\t\terror = vie_read_bytereg(vm, vcpuid, vie, &byte);\n\t\tif (error == 0)\n\t\t\terror = memwrite(vm, vcpuid, gpa, byte, size, arg);\n\t\tbreak;\n\tcase 0x89:\n\t\t/*\n\t\t * MOV from reg (ModRM:reg) to mem (ModRM:r/m)\n\t\t * 89/r:\tmov r/m16, r16\n\t\t * 89/r:\tmov r/m32, r32\n\t\t * REX.W + 89/r\tmov r/m64, r64\n\t\t */\n\t\treg = gpr_map[vie->reg];\n\t\terror = vie_read_register(vm, vcpuid, reg, &val);\n\t\tif (error == 0) {\n\t\t\tval &= size2mask[size];\n\t\t\terror = memwrite(vm, vcpuid, gpa, val, size, arg);\n\t\t}\n\t\tbreak;\n\tcase 0x8A:\n\t\t/*\n\t\t * MOV byte from mem (ModRM:r/m) to reg (ModRM:reg)\n\t\t * 8A/r:\tmov r8, r/m8\n\t\t * REX + 8A/r:\tmov r8, r/m8\n\t\t */\n\t\tsize = 1;\t/* override for byte operation */\n\t\terror = memread(vm, vcpuid, gpa, &val, size, arg);\n\t\tif (error == 0)\n\t\t\terror = vie_write_bytereg(vm, vcpuid, vie, ((uint8_t) val));\n\t\tbreak;\n\tcase 0x8B:\n\t\t/*\n\t\t * MOV from mem (ModRM:r/m) to reg (ModRM:reg)\n\t\t * 8B/r:\tmov r16, r/m16\n\t\t * 8B/r:\tmov r32, r/m32\n\t\t * REX.W 8B/r:\tmov r64, r/m64\n\t\t */\n\t\terror = memread(vm, vcpuid, gpa, &val, size, arg);\n\t\tif (error == 0) {\n\t\t\treg = gpr_map[vie->reg];\n\t\t\terror = vie_update_register(vm, vcpuid, reg, val, size);\n\t\t}\n\t\tbreak;\n\tcase 0xA1:\n\t\t/*\n\t\t * MOV from seg:moffset to AX/EAX/RAX\n\t\t * A1:\t\tmov AX, moffs16\n\t\t * A1:\t\tmov EAX, moffs32\n\t\t * REX.W + A1:\tmov RAX, moffs64\n\t\t */\n\t\terror = memread(vm, vcpuid, gpa, &val, size, arg);\n\t\tif (error == 0) {\n\t\t\treg = VM_REG_GUEST_RAX;\n\t\t\terror = vie_update_register(vm, vcpuid, reg, val, size);\n\t\t}\n\t\tbreak;\n\tcase 0xA3:\n\t\t/*\n\t\t * MOV from AX/EAX/RAX to seg:moffset\n\t\t * A3:\t\tmov moffs16, AX\n\t\t * A3:\t\tmov moffs32, EAX \n\t\t * REX.W + A3:\tmov moffs64, RAX\n\t\t */\n\t\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RAX, &val);\n\t\tif (error == 0) {\n\t\t\tval &= size2mask[size];\n\t\t\terror = memwrite(vm, vcpuid, gpa, val, size, arg);\n\t\t}\n\t\tbreak;\n\tcase 0xC6:\n\t\t/*\n\t\t * MOV from imm8 to mem (ModRM:r/m)\n\t\t * C6/0\t\tmov r/m8, imm8\n\t\t * REX + C6/0\tmov r/m8, imm8\n\t\t */\n\t\tsize = 1;\t/* override for byte operation */\n\t\terror = memwrite(vm, vcpuid, gpa, ((uint64_t) vie->immediate), size,\n\t\t\targ);\n\t\tbreak;\n\tcase 0xC7:\n\t\t/*\n\t\t * MOV from imm16/imm32 to mem (ModRM:r/m)\n\t\t * C7/0\t\tmov r/m16, imm16\n\t\t * C7/0\t\tmov r/m32, imm32\n\t\t * REX.W + C7/0\tmov r/m64, imm32 (sign-extended to 64-bits)\n\t\t */\n\t\tval = ((uint64_t) vie->immediate) & size2mask[size];\n\t\terror = memwrite(vm, vcpuid, gpa, val, size, arg);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn (error);\n}\n\nstatic int\nemulate_movx(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n\t     mem_region_read_t memread, UNUSED mem_region_write_t memwrite,\n\t     void *arg)\n{\n\tint error, size;\n\tenum vm_reg_name reg;\n\tuint64_t val;\n\n\tsize = vie->opsize;\n\terror = EINVAL;\n\n\tswitch (vie->op.op_byte) {\n\tcase 0xB6:\n\t\t/*\n\t\t * MOV and zero extend byte from mem (ModRM:r/m) to\n\t\t * reg (ModRM:reg).\n\t\t *\n\t\t * 0F B6/r\t\tmovzx r16, r/m8\n\t\t * 0F B6/r\t\tmovzx r32, r/m8\n\t\t * REX.W + 0F B6/r\tmovzx r64, r/m8\n\t\t */\n\n\t\t/* get the first operand */\n\t\terror = memread(vm, vcpuid, gpa, &val, 1, arg);\n\t\tif (error)\n\t\t\tbreak;\n\n\t\t/* get the second operand */\n\t\treg = gpr_map[vie->reg];\n\n\t\t/* zero-extend byte */\n\t\tval = (uint8_t)val;\n\n\t\t/* write the result */\n\t\terror = vie_update_register(vm, vcpuid, reg, val, size);\n\t\tbreak;\n\tcase 0xB7:\n\t\t/*\n\t\t * MOV and zero extend word from mem (ModRM:r/m) to\n\t\t * reg (ModRM:reg).\n\t\t *\n\t\t * 0F B7/r\t\tmovzx r32, r/m16\n\t\t * REX.W + 0F B7/r\tmovzx r64, r/m16\n\t\t */\n\t\terror = memread(vm, vcpuid, gpa, &val, 2, arg);\n\t\tif (error)\n\t\t\treturn (error);\n\n\t\treg = gpr_map[vie->reg];\n\n\t\t/* zero-extend word */\n\t\tval = (uint16_t)val;\n\n\t\terror = vie_update_register(vm, vcpuid, reg, val, size);\n\t\tbreak;\n\tcase 0xBE:\n\t\t/*\n\t\t * MOV and sign extend byte from mem (ModRM:r/m) to\n\t\t * reg (ModRM:reg).\n\t\t *\n\t\t * 0F BE/r\t\tmovsx r16, r/m8\n\t\t * 0F BE/r\t\tmovsx r32, r/m8\n\t\t * REX.W + 0F BE/r\tmovsx r64, r/m8\n\t\t */\n\n\t\t/* get the first operand */\n\t\terror = memread(vm, vcpuid, gpa, &val, 1, arg);\n\t\tif (error)\n\t\t\tbreak;\n\n\t\t/* get the second operand */\n\t\treg = gpr_map[vie->reg];\n\n\t\t/* sign extend byte */\n\t\tval = (uint64_t) ((int64_t) ((int8_t) val));\n\n\t\t/* write the result */\n\t\terror = vie_update_register(vm, vcpuid, reg, val, size);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn (error);\n}\n\n/*\n * Helper function to calculate and validate a linear address.\n */\nstatic int\nget_gla(void *vm, int vcpuid, UNUSED struct vie *vie,\n\tstruct vm_guest_paging *paging, int opsize, int addrsize, int prot,\n\tenum vm_reg_name seg, enum vm_reg_name gpr, uint64_t *gla, int *fault)\n{\n\tstruct seg_desc desc;\n\tuint64_t cr0, val, rflags;\n\tint error;\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_CR0, &cr0);\n\tKASSERT(error == 0, (\"%s: error %d getting cr0\", __func__, error));\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tKASSERT(error == 0, (\"%s: error %d getting rflags\", __func__, error));\n\n\terror = vm_get_seg_desc(vm, vcpuid, (int) seg, &desc);\n\tKASSERT(error == 0, (\"%s: error %d getting segment descriptor %d\",\n\t    __func__, error, seg));\n\n\terror = vie_read_register(vm, vcpuid, gpr, &val);\n\tKASSERT(error == 0, (\"%s: error %d getting register %d\", __func__,\n\t    error, gpr));\n\n\tif (vie_calculate_gla(paging->cpu_mode, seg, &desc, val, opsize,\n\t    addrsize, prot, gla)) {\n\t\tif (seg == VM_REG_GUEST_SS)\n\t\t\tvm_inject_ss(vm, vcpuid, 0);\n\t\telse\n\t\t\tvm_inject_gp(vm, vcpuid);\n\t\tgoto guest_fault;\n\t}\n\n\tif (vie_canonical_check(paging->cpu_mode, *gla)) {\n\t\tif (seg == VM_REG_GUEST_SS)\n\t\t\tvm_inject_ss(vm, vcpuid, 0);\n\t\telse\n\t\t\tvm_inject_gp(vm, vcpuid);\n\t\tgoto guest_fault;\n\t}\n\n\tif (vie_alignment_check(paging->cpl, opsize, cr0, rflags, *gla)) {\n\t\tvm_inject_ac(vm, vcpuid, 0);\n\t\tgoto guest_fault;\n\t}\n\n\t*fault = 0;\n\treturn (0);\n\nguest_fault:\n\t*fault = 1;\n\treturn (0);\n}\n\nstatic int\nemulate_movs(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n    struct vm_guest_paging *paging, mem_region_read_t memread,\n    mem_region_write_t memwrite, void *arg)\n{\n\tstruct vm_copyinfo copyinfo[2];\n\tuint64_t dstaddr, srcaddr, dstgpa, srcgpa, val;\n\tuint64_t rcx, rdi, rsi, rflags;\n\tint error, fault, opsize, seg, repeat;\n\n\topsize = (vie->op.op_byte == 0xA4) ? 1 : vie->opsize;\n\tval = 0;\n\trcx = 0;\n\terror = 0;\n\n\t/*\n\t * XXX although the MOVS instruction is only supposed to be used with\n\t * the \"rep\" prefix some guests like FreeBSD will use \"repnz\" instead.\n\t *\n\t * Empirically the \"repnz\" prefix has identical behavior to \"rep\"\n\t * and the zero flag does not make a difference.\n\t */\n\trepeat = vie->repz_present | vie->repnz_present;\n\n\tif (repeat) {\n\t\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RCX, &rcx);\n\t\tKASSERT(!error, (\"%s: error %d getting rcx\", __func__, error));\n\n\t\t/*\n\t\t * The count register is %rcx, %ecx or %cx depending on the\n\t\t * address size of the instruction.\n\t\t */\n\t\tif ((rcx & vie_size2mask(vie->addrsize)) == 0) {\n\t\t\terror = 0;\n\t\t\tgoto done;\n\t\t}\n\t}\n\n\t/*\n\t *\tSource\t\tDestination\tComments\n\t *\t--------------------------------------------\n\t * (1)  memory\t\tmemory\t\tn/a\n\t * (2)  memory\t\tmmio\t\temulated\n\t * (3)  mmio\t\tmemory\t\temulated\n\t * (4)  mmio\t\tmmio\t\temulated\n\t *\n\t * At this point we don't have sufficient information to distinguish\n\t * between (2), (3) and (4). We use 'vm_copy_setup()' to tease this\n\t * out because it will succeed only when operating on regular memory.\n\t *\n\t * XXX the emulation doesn't properly handle the case where 'gpa'\n\t * is straddling the boundary between the normal memory and MMIO.\n\t */\n\n\tseg = vie->segment_override ? vie->segment_register : VM_REG_GUEST_DS;\n\terror = get_gla(vm, vcpuid, vie, paging, opsize, vie->addrsize,\n\t    XHYVE_PROT_READ, ((enum vm_reg_name) seg), VM_REG_GUEST_RSI, &srcaddr,\n\t     &fault);\n\tif (error || fault)\n\t\tgoto done;\n\n\terror = vm_copy_setup(vm, vcpuid, paging, srcaddr, ((size_t) opsize),\n\t\tXHYVE_PROT_READ, copyinfo, nitems(copyinfo), &fault);\n\tif (error == 0) {\n\t\tif (fault)\n\t\t\tgoto done;\t/* Resume guest to handle fault */\n\n\t\t/*\n\t\t * case (2): read from system memory and write to mmio.\n\t\t */\n\t\tvm_copyin(vm, vcpuid, copyinfo, &val, ((size_t) opsize));\n\t\tvm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));\n\t\terror = memwrite(vm, vcpuid, gpa, val, opsize, arg);\n\t\tif (error)\n\t\t\tgoto done;\n\t} else {\n\t\t/*\n\t\t * 'vm_copy_setup()' is expected to fail for cases (3) and (4)\n\t\t * if 'srcaddr' is in the mmio space.\n\t\t */\n\n\t\terror = get_gla(vm, vcpuid, vie, paging, opsize, vie->addrsize,\n\t\t    XHYVE_PROT_WRITE, VM_REG_GUEST_ES, VM_REG_GUEST_RDI, &dstaddr,\n\t\t    &fault);\n\t\tif (error || fault)\n\t\t\tgoto done;\n\n\t\terror = vm_copy_setup(vm, vcpuid, paging, dstaddr, ((size_t) opsize),\n\t\t    XHYVE_PROT_WRITE, copyinfo, nitems(copyinfo), &fault);\n\t\tif (error == 0) {\n\t\t\tif (fault)\n\t\t\t\tgoto done;    /* Resume guest to handle fault */\n\n\t\t\t/*\n\t\t\t * case (3): read from MMIO and write to system memory.\n\t\t\t *\n\t\t\t * A MMIO read can have side-effects so we\n\t\t\t * commit to it only after vm_copy_setup() is\n\t\t\t * successful. If a page-fault needs to be\n\t\t\t * injected into the guest then it will happen\n\t\t\t * before the MMIO read is attempted.\n\t\t\t */\n\t\t\terror = memread(vm, vcpuid, gpa, &val, opsize, arg);\n\t\t\tif (error)\n\t\t\t\tgoto done;\n\n\t\t\tvm_copyout(vm, vcpuid, &val, copyinfo, ((size_t) opsize));\n\t\t\tvm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));\n\t\t} else {\n\t\t\t/*\n\t\t\t * Case (4): read from and write to mmio.\n\t\t\t *\n\t\t\t * Commit to the MMIO read/write (with potential\n\t\t\t * side-effects) only after we are sure that the\n\t\t\t * instruction is not going to be restarted due\n\t\t\t * to address translation faults.\n\t\t\t */\n\t\t\terror = vm_gla2gpa(vm, vcpuid, paging, srcaddr,\n\t\t\t\tXHYVE_PROT_READ, &srcgpa, &fault);\n\t\t\tif (error || fault)\n\t\t\t\tgoto done;\n\n\t\t\terror = vm_gla2gpa(vm, vcpuid, paging, dstaddr,\n\t\t\t\tXHYVE_PROT_WRITE, &dstgpa, &fault);\n\t\t\tif (error || fault)\n\t\t\t\tgoto done;\n\n\t\t\terror = memread(vm, vcpuid, srcgpa, &val, opsize, arg);\n\t\t\tif (error)\n\t\t\t\tgoto done;\n\n\t\t\terror = memwrite(vm, vcpuid, dstgpa, val, opsize, arg);\n\t\t\tif (error)\n\t\t\t\tgoto done;\n\t\t}\n\t}\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RSI, &rsi);\n\tKASSERT(error == 0, (\"%s: error %d getting rsi\", __func__, error));\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RDI, &rdi);\n\tKASSERT(error == 0, (\"%s: error %d getting rdi\", __func__, error));\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tKASSERT(error == 0, (\"%s: error %d getting rflags\", __func__, error));\n\n\tif (rflags & PSL_D) {\n\t\trsi -= ((uint64_t) opsize);\n\t\trdi -= ((uint64_t) opsize);\n\t} else {\n\t\trsi += ((uint64_t) opsize);\n\t\trdi += ((uint64_t) opsize);\n\t}\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RSI, rsi,\n\t    vie->addrsize);\n\tKASSERT(error == 0, (\"%s: error %d updating rsi\", __func__, error));\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RDI, rdi,\n\t    vie->addrsize);\n\tKASSERT(error == 0, (\"%s: error %d updating rdi\", __func__, error));\n\n\tif (repeat) {\n\t\trcx = rcx - 1;\n\t\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RCX,\n\t\t    rcx, vie->addrsize);\n\t\tKASSERT(!error, (\"%s: error %d updating rcx\", __func__, error));\n\n\t\t/*\n\t\t * Repeat the instruction if the count register is not zero.\n\t\t */\n\t\tif ((rcx & vie_size2mask(vie->addrsize)) != 0)\n\t\t\tvm_restart_instruction(vm, vcpuid);\n\t}\ndone:\n\tKASSERT(error == 0 || error == EFAULT, (\"%s: unexpected error %d\",\n\t    __func__, error));\n\treturn (error);\n}\n\nstatic int\nemulate_stos(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n    UNUSED struct vm_guest_paging *paging, UNUSED mem_region_read_t memread,\n    mem_region_write_t memwrite, void *arg)\n{\n\tint error, opsize, repeat;\n\tuint64_t val;\n\tuint64_t rcx, rdi, rflags;\n\n\topsize = (vie->op.op_byte == 0xAA) ? 1 : vie->opsize;\n\trepeat = vie->repz_present | vie->repnz_present;\n\trcx = 0;\n\n\tif (repeat) {\n\t\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RCX, &rcx);\n\t\tKASSERT(!error, (\"%s: error %d getting rcx\", __func__, error));\n\n\t\t/*\n\t\t * The count register is %rcx, %ecx or %cx depending on the\n\t\t * address size of the instruction.\n\t\t */\n\t\tif ((rcx & vie_size2mask(vie->addrsize)) == 0)\n\t\t\treturn (0);\n\t}\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RAX, &val);\n\tKASSERT(!error, (\"%s: error %d getting rax\", __func__, error));\n\n\terror = memwrite(vm, vcpuid, gpa, val, opsize, arg);\n\tif (error)\n\t\treturn (error);\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RDI, &rdi);\n\tKASSERT(error == 0, (\"%s: error %d getting rdi\", __func__, error));\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tKASSERT(error == 0, (\"%s: error %d getting rflags\", __func__, error));\n\n\tif (rflags & PSL_D)\n\t\trdi -= ((uint64_t) opsize);\n\telse\n\t\trdi += ((uint64_t) opsize);\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RDI, rdi,\n\t    vie->addrsize);\n\tKASSERT(error == 0, (\"%s: error %d updating rdi\", __func__, error));\n\n\tif (repeat) {\n\t\trcx = rcx - 1;\n\t\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RCX,\n\t\t    rcx, vie->addrsize);\n\t\tKASSERT(!error, (\"%s: error %d updating rcx\", __func__, error));\n\n\t\t/*\n\t\t * Repeat the instruction if the count register is not zero.\n\t\t */\n\t\tif ((rcx & vie_size2mask(vie->addrsize)) != 0)\n\t\t\tvm_restart_instruction(vm, vcpuid);\n\t}\n\n\treturn (0);\n}\n\nstatic int\nemulate_and(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n\t    mem_region_read_t memread, mem_region_write_t memwrite, void *arg)\n{\n\tint error, size;\n\tenum vm_reg_name reg;\n\tuint64_t result, rflags, rflags2, val1, val2;\n\n\tsize = vie->opsize;\n\tresult = 0;\n\terror = EINVAL;\n\n\tswitch (vie->op.op_byte) {\n\tcase 0x23:\n\t\t/*\n\t\t * AND reg (ModRM:reg) and mem (ModRM:r/m) and store the\n\t\t * result in reg.\n\t\t *\n\t\t * 23/r\t\tand r16, r/m16\n\t\t * 23/r\t\tand r32, r/m32\n\t\t * REX.W + 23/r\tand r64, r/m64\n\t\t */\n\n\t\t/* get the first operand */\n\t\treg = gpr_map[vie->reg];\n\t\terror = vie_read_register(vm, vcpuid, reg, &val1);\n\t\tif (error)\n\t\t\tbreak;\n\n\t\t/* get the second operand */\n\t\terror = memread(vm, vcpuid, gpa, &val2, size, arg);\n\t\tif (error)\n\t\t\tbreak;\n\n\t\t/* perform the operation and write the result */\n\t\tresult = val1 & val2;\n\t\terror = vie_update_register(vm, vcpuid, reg, result, size);\n\t\tbreak;\n\tcase 0x81:\n\tcase 0x83:\n\t\t/*\n\t\t * AND mem (ModRM:r/m) with immediate and store the\n\t\t * result in mem.\n\t\t *\n\t\t * 81 /4\t\tand r/m16, imm16\n\t\t * 81 /4\t\tand r/m32, imm32\n\t\t * REX.W + 81 /4\tand r/m64, imm32 sign-extended to 64\n\t\t *\n\t\t * 83 /4\t\tand r/m16, imm8 sign-extended to 16\n\t\t * 83 /4\t\tand r/m32, imm8 sign-extended to 32\n\t\t * REX.W + 83/4\t\tand r/m64, imm8 sign-extended to 64\n\t\t */\n\n\t\t/* get the first operand */\n                error = memread(vm, vcpuid, gpa, &val1, size, arg);\n                if (error)\n\t\t\tbreak;\n\n                /*\n\t\t * perform the operation with the pre-fetched immediate\n\t\t * operand and write the result\n\t\t */\n                result = val1 & ((uint64_t) vie->immediate);\n                error = memwrite(vm, vcpuid, gpa, result, size, arg);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\tif (error)\n\t\treturn (error);\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tif (error)\n\t\treturn (error);\n\n\t/*\n\t * OF and CF are cleared; the SF, ZF and PF flags are set according\n\t * to the result; AF is undefined.\n\t *\n\t * The updated status flags are obtained by subtracting 0 from 'result'.\n\t */\n\trflags2 = getcc(size, result, 0);\n\trflags &= ~((uint64_t) RFLAGS_STATUS_BITS);\n\trflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N);\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);\n\treturn (error);\n}\n\nstatic int\nemulate_or(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n\t    mem_region_read_t memread, mem_region_write_t memwrite, void *arg)\n{\n\tint error, size;\n\tuint64_t val1, result, rflags, rflags2;\n\n\tsize = vie->opsize;\n\tresult = 0;\n\terror = EINVAL;\n\n\tswitch (vie->op.op_byte) {\n\tcase 0x81:\n\tcase 0x83:\n\t\t/*\n\t\t * OR mem (ModRM:r/m) with immediate and store the\n\t\t * result in mem.\n\t\t *\n\t\t * 81 /1\t\tor r/m16, imm16\n\t\t * 81 /1\t\tor r/m32, imm32\n\t\t * REX.W + 81 /1\tor r/m64, imm32 sign-extended to 64\n\t\t *\n\t\t * 83 /1\t\tor r/m16, imm8 sign-extended to 16\n\t\t * 83 /1\t\tor r/m32, imm8 sign-extended to 32\n\t\t * REX.W + 83/1\t\tor r/m64, imm8 sign-extended to 64\n\t\t */\n\n\t\t/* get the first operand */\n                error = memread(vm, vcpuid, gpa, &val1, size, arg);\n                if (error)\n\t\t\tbreak;\n\n                /*\n\t\t * perform the operation with the pre-fetched immediate\n\t\t * operand and write the result\n\t\t */\n                result = val1 | ((uint64_t) vie->immediate);\n                error = memwrite(vm, vcpuid, gpa, result, size, arg);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\tif (error)\n\t\treturn (error);\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tif (error)\n\t\treturn (error);\n\n\t/*\n\t * OF and CF are cleared; the SF, ZF and PF flags are set according\n\t * to the result; AF is undefined.\n\t *\n\t * The updated status flags are obtained by subtracting 0 from 'result'.\n\t */\n\trflags2 = getcc(size, result, 0);\n\trflags &= ~((uint64_t) RFLAGS_STATUS_BITS);\n\trflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N);\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);\n\treturn (error);\n}\n\nstatic int\nemulate_cmp(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n\t    mem_region_read_t memread, UNUSED mem_region_write_t memwrite,\n\t    void *arg)\n{\n\tint error, size;\n\tuint64_t op1, op2, rflags, rflags2;\n\tenum vm_reg_name reg;\n\n\tsize = vie->opsize;\n\tswitch (vie->op.op_byte) {\n\tcase 0x3B:\n\t\t/*\n\t\t * 3B/r\t\tCMP r16, r/m16\n\t\t * 3B/r\t\tCMP r32, r/m32\n\t\t * REX.W + 3B/r\tCMP r64, r/m64\n\t\t *\n\t\t * Compare first operand (reg) with second operand (r/m) and\n\t\t * set status flags in EFLAGS register. The comparison is\n\t\t * performed by subtracting the second operand from the first\n\t\t * operand and then setting the status flags.\n\t\t */\n\n\t\t/* Get the first operand */\n\t\treg = gpr_map[vie->reg];\n\t\terror = vie_read_register(vm, vcpuid, reg, &op1);\n\t\tif (error)\n\t\t\treturn (error);\n\n\t\t/* Get the second operand */\n\t\terror = memread(vm, vcpuid, gpa, &op2, size, arg);\n\t\tif (error)\n\t\t\treturn (error);\n\n\t\trflags2 = getcc(size, op1, op2);\n\t\tbreak;\n\tcase 0x80:\n\tcase 0x81:\n\tcase 0x83:\n\t\t/*\n\t\t * 80 /7\t\tcmp r/m8, imm8\n\t\t * REX + 80 /7\t\tcmp r/m8, imm8\n\t\t *\n\t\t * 81 /7\t\tcmp r/m16, imm16\n\t\t * 81 /7\t\tcmp r/m32, imm32\n\t\t * REX.W + 81 /7\tcmp r/m64, imm32 sign-extended to 64\n\t\t *\n\t\t * 83 /7\t\tcmp r/m16, imm8 sign-extended to 16\n\t\t * 83 /7\t\tcmp r/m32, imm8 sign-extended to 32\n\t\t * REX.W + 83 /7\tcmp r/m64, imm8 sign-extended to 64\n\t\t *\n\t\t * Compare mem (ModRM:r/m) with immediate and set\n\t\t * status flags according to the results.  The\n\t\t * comparison is performed by subtracting the\n\t\t * immediate from the first operand and then setting\n\t\t * the status flags.\n\t\t *\n\t\t */\n\t\tif (vie->op.op_byte == 0x80)\n\t\t\tsize = 1;\n\n\t\t/* get the first operand */\n                error = memread(vm, vcpuid, gpa, &op1, size, arg);\n\t\tif (error)\n\t\t\treturn (error);\n\n\t\trflags2 = getcc(size, op1, ((uint64_t) vie->immediate));\n\t\tbreak;\n\tdefault:\n\t\treturn (EINVAL);\n\t}\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tif (error)\n\t\treturn (error);\n\trflags &= ~((uint64_t) RFLAGS_STATUS_BITS);\n\trflags |= rflags2 & RFLAGS_STATUS_BITS;\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);\n\treturn (error);\n}\n\nstatic int\nemulate_test(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n    mem_region_read_t memread, UNUSED mem_region_write_t memwrite, void *arg)\n{\n\tint error, size;\n\tuint64_t op1, rflags, rflags2;\n\n\tsize = vie->opsize;\n\terror = EINVAL;\n\n\tswitch (vie->op.op_byte) {\n\tcase 0xF7:\n\t\t/*\n\t\t * F7 /0\t\ttest r/m16, imm16\n\t\t * F7 /0\t\ttest r/m32, imm32\n\t\t * REX.W + F7 /0\ttest r/m64, imm32 sign-extended to 64\n\t\t *\n\t\t * Test mem (ModRM:r/m) with immediate and set status\n\t\t * flags according to the results.  The comparison is\n\t\t * performed by anding the immediate from the first\n\t\t * operand and then setting the status flags.\n\t\t */\n\t\tif ((vie->reg & 7) != 0)\n\t\t\treturn (EINVAL);\n\n\t\terror = memread(vm, vcpuid, gpa, &op1, size, arg);\n\t\tif (error)\n\t\t\treturn (error);\n\n\t\trflags2 = getandflags(size, op1, (uint64_t) vie->immediate);\n\t\tbreak;\n\tdefault:\n\t\treturn (EINVAL);\n\t}\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tif (error)\n\t\treturn (error);\n\n\t/*\n\t * OF and CF are cleared; the SF, ZF and PF flags are set according\n\t * to the result; AF is undefined.\n\t */\n\trflags &= ~((uint64_t) RFLAGS_STATUS_BITS);\n\trflags |= rflags2 & (PSL_PF | PSL_Z | PSL_N);\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);\n\treturn (error);\n}\n\nstatic int\nemulate_sub(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n\t    mem_region_read_t memread, UNUSED mem_region_write_t memwrite,\n\t    void *arg)\n{\n\tint error, size;\n\tuint64_t nval, rflags, rflags2, val1, val2;\n\tenum vm_reg_name reg;\n\n\tsize = vie->opsize;\n\tval1 = 0;\n\tval2 = 0;\n\terror = EINVAL;\n\n\tswitch (vie->op.op_byte) {\n\tcase 0x2B:\n\t\t/*\n\t\t * SUB r/m from r and store the result in r\n\t\t * \n\t\t * 2B/r            SUB r16, r/m16\n\t\t * 2B/r            SUB r32, r/m32\n\t\t * REX.W + 2B/r    SUB r64, r/m64\n\t\t */\n\n\t\t/* get the first operand */\n\t\treg = gpr_map[vie->reg];\n\t\terror = vie_read_register(vm, vcpuid, reg, &val1);\n\t\tif (error)\n\t\t\tbreak;\n\n\t\t/* get the second operand */\n\t\terror = memread(vm, vcpuid, gpa, &val2, size, arg);\n\t\tif (error)\n\t\t\tbreak;\n\n\t\t/* perform the operation and write the result */\n\t\tnval = val1 - val2;\n\t\terror = vie_update_register(vm, vcpuid, reg, nval, size);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (!error) {\n\t\trflags2 = getcc(size, val1, val2);\n\t\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS,\n\t\t    &rflags);\n\t\tif (error)\n\t\t\treturn (error);\n\n\t\trflags &= ~((uint64_t) RFLAGS_STATUS_BITS);\n\t\trflags |= rflags2 & RFLAGS_STATUS_BITS;\n\t\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS,\n\t\t    rflags, 8);\n\t}\n\n\treturn (error);\n}\n\nstatic int\nemulate_stack_op(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,\n    struct vm_guest_paging *paging, mem_region_read_t memread,\n    mem_region_write_t memwrite, void *arg)\n{\n\tstruct vm_copyinfo copyinfo[2];\n\tstruct seg_desc ss_desc;\n\tuint64_t cr0, rflags, rsp, stack_gla, val;\n\tint error, fault, size, stackaddrsize, pushop;\n\n\tval = 0;\n\tsize = vie->opsize;\n\tpushop = (vie->op.op_type == VIE_OP_TYPE_PUSH) ? 1 : 0;\n\n\t/*\n\t * From \"Address-Size Attributes for Stack Accesses\", Intel SDL, Vol 1\n\t */\n\tif (paging->cpu_mode == CPU_MODE_REAL) {\n\t\tstackaddrsize = 2;\n\t} else if (paging->cpu_mode == CPU_MODE_64BIT) {\n\t\t/*\n\t\t * \"Stack Manipulation Instructions in 64-bit Mode\", SDM, Vol 3\n\t\t * - Stack pointer size is always 64-bits.\n\t\t * - PUSH/POP of 32-bit values is not possible in 64-bit mode.\n\t\t * - 16-bit PUSH/POP is supported by using the operand size\n\t\t *   override prefix (66H).\n\t\t */\n\t\tstackaddrsize = 8;\n\t\tsize = vie->opsize_override ? 2 : 8;\n\t} else {\n\t\t/*\n\t\t * In protected or compability mode the 'B' flag in the\n\t\t * stack-segment descriptor determines the size of the\n\t\t * stack pointer.\n\t\t */\n\t\terror = vm_get_seg_desc(vm, vcpuid, VM_REG_GUEST_SS, &ss_desc);\n\t\tKASSERT(error == 0, (\"%s: error %d getting SS descriptor\",\n\t\t    __func__, error));\n\t\tif (SEG_DESC_DEF32(ss_desc.access))\n\t\t\tstackaddrsize = 4;\n\t\telse\n\t\t\tstackaddrsize = 2;\n\t}\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_CR0, &cr0);\n\tKASSERT(error == 0, (\"%s: error %d getting cr0\", __func__, error));\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tKASSERT(error == 0, (\"%s: error %d getting rflags\", __func__, error));\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RSP, &rsp);\n\tKASSERT(error == 0, (\"%s: error %d getting rsp\", __func__, error));\n\tif (pushop) {\n\t\trsp -= ((uint64_t) size);\n\t}\n\n\tif (vie_calculate_gla(paging->cpu_mode, VM_REG_GUEST_SS, &ss_desc,\n\t    rsp, size, stackaddrsize, pushop ? XHYVE_PROT_WRITE : XHYVE_PROT_READ,\n\t    &stack_gla)) {\n\t\tvm_inject_ss(vm, vcpuid, 0);\n\t\treturn (0);\n\t}\n\n\tif (vie_canonical_check(paging->cpu_mode, stack_gla)) {\n\t\tvm_inject_ss(vm, vcpuid, 0);\n\t\treturn (0);\n\t}\n\n\tif (vie_alignment_check(paging->cpl, size, cr0, rflags, stack_gla)) {\n\t\tvm_inject_ac(vm, vcpuid, 0);\n\t\treturn (0);\n\t}\n\n\terror = vm_copy_setup(vm, vcpuid, paging, stack_gla, ((size_t) size),\n\t    pushop ? XHYVE_PROT_WRITE : XHYVE_PROT_READ, copyinfo, nitems(copyinfo),\n\t    &fault);\n\tif (error || fault)\n\t\treturn (error);\n\n\tif (pushop) {\n\t\terror = memread(vm, vcpuid, mmio_gpa, &val, size, arg);\n\t\tif (error == 0)\n\t\t\tvm_copyout(vm, vcpuid, &val, copyinfo, ((size_t) size));\n\t} else {\n\t\tvm_copyin(vm, vcpuid, copyinfo, &val, ((size_t) size));\n\t\terror = memwrite(vm, vcpuid, mmio_gpa, val, size, arg);\n\t\trsp += ((uint64_t) size);\n\t}\n\tvm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));\n\n\tif (error == 0) {\n\t\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RSP, rsp,\n\t\t    stackaddrsize);\n\t\tKASSERT(error == 0, (\"error %d updating rsp\", error));\n\t}\n\treturn (error);\n}\n\nstatic int\nemulate_push(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,\n    struct vm_guest_paging *paging, mem_region_read_t memread,\n    mem_region_write_t memwrite, void *arg)\n{\n\tint error;\n\n\t/*\n\t * Table A-6, \"Opcode Extensions\", Intel SDM, Vol 2.\n\t *\n\t * PUSH is part of the group 5 extended opcodes and is identified\n\t * by ModRM:reg = b110.\n\t */\n\tif ((vie->reg & 7) != 6)\n\t\treturn (EINVAL);\n\n\terror = emulate_stack_op(vm, vcpuid, mmio_gpa, vie, paging, memread,\n\t    memwrite, arg);\n\treturn (error);\n}\n\nstatic int\nemulate_pop(void *vm, int vcpuid, uint64_t mmio_gpa, struct vie *vie,\n    struct vm_guest_paging *paging, mem_region_read_t memread,\n    mem_region_write_t memwrite, void *arg)\n{\n\tint error;\n\n\t/*\n\t * Table A-6, \"Opcode Extensions\", Intel SDM, Vol 2.\n\t *\n\t * POP is part of the group 1A extended opcodes and is identified\n\t * by ModRM:reg = b000.\n\t */\n\tif ((vie->reg & 7) != 0)\n\t\treturn (EINVAL);\n\n\terror = emulate_stack_op(vm, vcpuid, mmio_gpa, vie, paging, memread,\n\t    memwrite, arg);\n\treturn (error);\n}\n\nstatic int\nemulate_group1(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n    UNUSED struct vm_guest_paging *paging, mem_region_read_t memread,\n    mem_region_write_t memwrite, void *memarg)\n{\n\tint error;\n\n\tswitch (vie->reg & 7) {\n\tcase 0x1:\t/* OR */\n\t\terror = emulate_or(vm, vcpuid, gpa, vie,\n\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase 0x4:\t/* AND */\n\t\terror = emulate_and(vm, vcpuid, gpa, vie,\n\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase 0x7:\t/* CMP */\n\t\terror = emulate_cmp(vm, vcpuid, gpa, vie,\n\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tdefault:\n\t\terror = EINVAL;\n\t\tbreak;\n\t}\n\n\treturn (error);\n}\n\nstatic int\nemulate_bittest(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n    mem_region_read_t memread, UNUSED mem_region_write_t memwrite, void *memarg)\n{\n\tuint64_t val, rflags;\n\tint error, bitmask, bitoff;\n\n\t/*\n\t * 0F BA is a Group 8 extended opcode.\n\t *\n\t * Currently we only emulate the 'Bit Test' instruction which is\n\t * identified by a ModR/M:reg encoding of 100b.\n\t */\n\tif ((vie->reg & 7) != 4)\n\t\treturn (EINVAL);\n\n\terror = vie_read_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, &rflags);\n\tKASSERT(error == 0, (\"%s: error %d getting rflags\", __func__, error));\n\n\terror = memread(vm, vcpuid, gpa, &val, vie->opsize, memarg);\n\tif (error)\n\t\treturn (error);\n\n\t/*\n\t * Intel SDM, Vol 2, Table 3-2:\n\t * \"Range of Bit Positions Specified by Bit Offset Operands\"\n\t */\n\tbitmask = vie->opsize * 8 - 1;\n\tbitoff = (uint8_t)(vie->immediate & bitmask);\n\n\t/* Copy the bit into the Carry flag in %rflags */\n\tif (val & (1UL << bitoff))\n\t\trflags |= PSL_C;\n\telse\n\t\trflags &= ~((uint64_t) PSL_C);\n\n\terror = vie_update_register(vm, vcpuid, VM_REG_GUEST_RFLAGS, rflags, 8);\n\tKASSERT(error == 0, (\"%s: error %d updating rflags\", __func__, error));\n\n\treturn (0);\n}\n\nint\nvmm_emulate_instruction(void *vm, int vcpuid, uint64_t gpa, struct vie *vie,\n    struct vm_guest_paging *paging, mem_region_read_t memread,\n    mem_region_write_t memwrite, void *memarg)\n{\n\tint error;\n\n\tif (!vie->decoded)\n\t\treturn (EINVAL);\n\n\tswitch (vie->op.op_type) {\n\tcase VIE_OP_TYPE_GROUP1:\n\t\terror = emulate_group1(vm, vcpuid, gpa, vie, paging, memread,\n\t\t    memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_POP:\n\t\terror = emulate_pop(vm, vcpuid, gpa, vie, paging, memread,\n\t\t    memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_PUSH:\n\t\terror = emulate_push(vm, vcpuid, gpa, vie, paging, memread,\n\t\t    memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_CMP:\n\t\terror = emulate_cmp(vm, vcpuid, gpa, vie,\n\t\t\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_MOV:\n\t\terror = emulate_mov(vm, vcpuid, gpa, vie,\n\t\t\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_MOVSX:\n\tcase VIE_OP_TYPE_MOVZX:\n\t\terror = emulate_movx(vm, vcpuid, gpa, vie,\n\t\t\t\t     memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_MOVS:\n\t\terror = emulate_movs(vm, vcpuid, gpa, vie, paging, memread,\n\t\t    memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_STOS:\n\t\terror = emulate_stos(vm, vcpuid, gpa, vie, paging, memread,\n\t\t    memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_AND:\n\t\terror = emulate_and(vm, vcpuid, gpa, vie,\n\t\t\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_OR:\n\t\terror = emulate_or(vm, vcpuid, gpa, vie,\n\t\t\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_SUB:\n\t\terror = emulate_sub(vm, vcpuid, gpa, vie,\n\t\t\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_BITTEST:\n\t\terror = emulate_bittest(vm, vcpuid, gpa, vie,\n\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tcase VIE_OP_TYPE_TEST:\n\t\terror = emulate_test(vm, vcpuid, gpa, vie,\n\t\t    memread, memwrite, memarg);\n\t\tbreak;\n\tdefault:\n\t\terror = EINVAL;\n\t\tbreak;\n\t}\n\n\treturn (error);\n}\n\nint\nvie_alignment_check(int cpl, int size, uint64_t cr0, uint64_t rf, uint64_t gla)\n{\n\tKASSERT(size == 1 || size == 2 || size == 4 || size == 8,\n\t    (\"%s: invalid size %d\", __func__, size));\n\tKASSERT(cpl >= 0 && cpl <= 3, (\"%s: invalid cpl %d\", __func__, cpl));\n\n\tif (cpl != 3 || (cr0 & CR0_AM) == 0 || (rf & PSL_AC) == 0)\n\t\treturn (0);\n\n\treturn ((gla & ((uint64_t) (size - 1))) ? 1 : 0);\n}\n\nint\nvie_canonical_check(enum vm_cpu_mode cpu_mode, uint64_t gla)\n{\n\tuint64_t mask;\n\n\tif (cpu_mode != CPU_MODE_64BIT)\n\t\treturn (0);\n\n\t/*\n\t * The value of the bit 47 in the 'gla' should be replicated in the\n\t * most significant 16 bits.\n\t */\n\tmask = ~((1UL << 48) - 1);\n\tif (gla & (1UL << 47))\n\t\treturn ((gla & mask) != mask);\n\telse\n\t\treturn ((gla & mask) != 0);\n}\n\nuint64_t\nvie_size2mask(int size)\n{\n\tKASSERT(size == 1 || size == 2 || size == 4 || size == 8,\n\t    (\"vie_size2mask: invalid size %d\", size));\n\treturn (size2mask[size]);\n}\n\nint\nvie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg,\n    struct seg_desc *desc, uint64_t offset, int length, int addrsize,\n    int prot, uint64_t *gla)\n{\n\tuint64_t firstoff, low_limit, high_limit, segbase;\n\tint glasize, type;\n\n\tKASSERT(seg >= VM_REG_GUEST_ES && seg <= VM_REG_GUEST_GS,\n\t    (\"%s: invalid segment %d\", __func__, seg));\n\tKASSERT(length == 1 || length == 2 || length == 4 || length == 8,\n\t    (\"%s: invalid operand size %d\", __func__, length));\n\tKASSERT((prot & ~(XHYVE_PROT_READ | XHYVE_PROT_WRITE)) == 0,\n\t    (\"%s: invalid prot %#x\", __func__, prot));\n\n\tfirstoff = offset;\n\tif (cpu_mode == CPU_MODE_64BIT) {\n\t\tKASSERT(addrsize == 4 || addrsize == 8, (\"%s: invalid address \"\n\t\t    \"size %d for cpu_mode %d\", __func__, addrsize, cpu_mode));\n\t\tglasize = 8;\n\t} else {\n\t\tKASSERT(addrsize == 2 || addrsize == 4, (\"%s: invalid address \"\n\t\t    \"size %d for cpu mode %d\", __func__, addrsize, cpu_mode));\n\t\tglasize = 4;\n\t\t/*\n\t\t * If the segment selector is loaded with a NULL selector\n\t\t * then the descriptor is unusable and attempting to use\n\t\t * it results in a #GP(0).\n\t\t */\n\t\tif (SEG_DESC_UNUSABLE(desc->access))\n\t\t\treturn (-1);\n\n\t\t/* \n\t\t * The processor generates a #NP exception when a segment\n\t\t * register is loaded with a selector that points to a\n\t\t * descriptor that is not present. If this was the case then\n\t\t * it would have been checked before the VM-exit.\n\t\t */\n\t\tKASSERT(SEG_DESC_PRESENT(desc->access),\n\t\t    (\"segment %d not present: %#x\", seg, desc->access));\n\n\t\t/*\n\t\t * The descriptor type must indicate a code/data segment.\n\t\t */\n\t\ttype = SEG_DESC_TYPE(desc->access);\n\t\tKASSERT(type >= 16 && type <= 31, (\"segment %d has invalid \"\n\t\t    \"descriptor type %#x\", seg, type));\n\n\t\tif (prot & XHYVE_PROT_READ) {\n\t\t\t/* #GP on a read access to a exec-only code segment */\n\t\t\tif ((type & 0xA) == 0x8)\n\t\t\t\treturn (-1);\n\t\t}\n\n\t\tif (prot & XHYVE_PROT_WRITE) {\n\t\t\t/*\n\t\t\t * #GP on a write access to a code segment or a\n\t\t\t * read-only data segment.\n\t\t\t */\n\t\t\tif (type & 0x8)\t\t\t/* code segment */\n\t\t\t\treturn (-1);\n\n\t\t\tif ((type & 0xA) == 0)\t\t/* read-only data seg */\n\t\t\t\treturn (-1);\n\t\t}\n\n\t\t/*\n\t\t * 'desc->limit' is fully expanded taking granularity into\n\t\t * account.\n\t\t */\n\t\tif ((type & 0xC) == 0x4) {\n\t\t\t/* expand-down data segment */\n\t\t\tlow_limit = desc->limit + 1;\n\t\t\thigh_limit = SEG_DESC_DEF32(desc->access) ?\n\t\t\t    0xffffffff : 0xffff;\n\t\t} else {\n\t\t\t/* code segment or expand-up data segment */\n\t\t\tlow_limit = 0;\n\t\t\thigh_limit = desc->limit;\n\t\t}\n\n\t\twhile (length > 0) {\n\t\t\toffset &= vie_size2mask(addrsize);\n\t\t\tif (offset < low_limit || offset > high_limit)\n\t\t\t\treturn (-1);\n\t\t\toffset++;\n\t\t\tlength--;\n\t\t}\n\t}\n\n\t/*\n\t * In 64-bit mode all segments except %fs and %gs have a segment\n\t * base address of 0.\n\t */\n\tif (cpu_mode == CPU_MODE_64BIT && seg != VM_REG_GUEST_FS &&\n\t    seg != VM_REG_GUEST_GS) {\n\t\tsegbase = 0;\n\t} else {\n\t\tsegbase = desc->base;\n\t}\n\n\t/*\n\t * Truncate 'firstoff' to the effective address size before adding\n\t * it to the segment base.\n\t */\n\tfirstoff &= vie_size2mask(addrsize);\n\t*gla = (segbase + firstoff) & vie_size2mask(glasize);\n\treturn (0);\n}\n\nvoid\nvie_init(struct vie *vie, const char *inst_bytes, int inst_length)\n{\n\tKASSERT(inst_length >= 0 && inst_length <= VIE_INST_SIZE,\n\t    (\"%s: invalid instruction length (%d)\", __func__, inst_length));\n\n\tbzero(vie, sizeof(struct vie));\n\n\tvie->base_register = VM_REG_LAST;\n\tvie->index_register = VM_REG_LAST;\n\tvie->segment_register = VM_REG_LAST;\n\n\tif (inst_length) {\n\t\tbcopy(inst_bytes, vie->inst, ((size_t) inst_length));\n\t\tvie->num_valid = ((uint8_t) inst_length);\n\t}\n}\n\nstatic int\npf_error_code(int usermode, int prot, int rsvd, uint64_t pte)\n{\n\tint error_code = 0;\n\n\tif (pte & PG_V)\n\t\terror_code |= PGEX_P;\n\tif (prot & XHYVE_PROT_WRITE)\n\t\terror_code |= PGEX_W;\n\tif (usermode)\n\t\terror_code |= PGEX_U;\n\tif (rsvd)\n\t\terror_code |= PGEX_RSV;\n\tif (prot & XHYVE_PROT_EXECUTE)\n\t\terror_code |= PGEX_I;\n\n\treturn (error_code);\n}\n\nint\nvm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,\n    uint64_t gla, int prot, uint64_t *gpa, int *guest_fault)\n{\n\tint nlevels, pfcode, ptpshift, ptpindex, retval, usermode, writable;\n\tu_int retries;\n\tuint64_t *ptpbase, ptpphys, pte, pgsize;\n\tuint32_t *ptpbase32, pte32;\n\tvoid *cookie;\n\n\t*guest_fault = 0;\n\n\tusermode = (paging->cpl == 3 ? 1 : 0);\n\twritable = prot & XHYVE_PROT_WRITE;\n\tcookie = NULL;\n\tretval = 0;\n\tretries = 0;\n\tpte = 0;\n\tpte32 = 0;\n\tptpshift = 0;\n\tpgsize = 0;\n\tptpindex = 0;\n\tptpbase = NULL;\n\tptpbase32 = NULL;\n\nrestart:\n\tptpphys = paging->cr3;\t\t/* root of the page tables */\n\n\tif (vie_canonical_check(paging->cpu_mode, gla)) {\n\t\t/*\n\t\t * XXX assuming a non-stack reference otherwise a stack fault\n\t\t * should be generated.\n\t\t */\n\t\tvm_inject_gp(vm, vcpuid);\n\t\tgoto fault;\n\t}\n\n\tif (paging->paging_mode == PAGING_MODE_FLAT) {\n\t\t*gpa = gla;\n\t\tgoto done;\n\t}\n\n\tif (paging->paging_mode == PAGING_MODE_32) {\n\t\tnlevels = 2;\n\t\twhile (--nlevels >= 0) {\n\t\t\t/* Zero out the lower 12 bits. */\n\t\t\tptpphys &= ~((uint64_t) 0xfff);\n\n\t\t\tptpbase32 = vm_gpa2hva(vm, ptpphys, XHYVE_PAGE_SIZE);\n\n\t\t\tif (ptpbase32 == NULL)\n\t\t\t\tgoto error;\n\n\t\t\tptpshift = XHYVE_PAGE_SHIFT + nlevels * 10;\n\t\t\tptpindex = (gla >> ptpshift) & 0x3FF;\n\t\t\tpgsize = 1UL << ptpshift;\n\n\t\t\tpte32 = ptpbase32[ptpindex];\n\n\t\t\tif ((pte32 & PG_V) == 0 ||\n\t\t\t    (usermode && (pte32 & PG_U) == 0) ||\n\t\t\t    (writable && (pte32 & PG_RW) == 0)) {\n\t\t\t\tpfcode = pf_error_code(usermode, prot, 0,\n\t\t\t\t    pte32);\n\t\t\t\tvm_inject_pf(vm, vcpuid, pfcode, gla);\n\t\t\t\tgoto fault;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Emulate the x86 MMU's management of the accessed\n\t\t\t * and dirty flags. While the accessed flag is set\n\t\t\t * at every level of the page table, the dirty flag\n\t\t\t * is only set at the last level providing the guest\n\t\t\t * physical address.\n\t\t\t */\n\t\t\tif ((pte32 & PG_A) == 0) {\n\t\t\t\tif (atomic_cmpset_32(&ptpbase32[ptpindex],\n\t\t\t\t    pte32, pte32 | PG_A) == 0) {\n\t\t\t\t\tgoto restart;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* XXX must be ignored if CR4.PSE=0 */\n\t\t\tif (nlevels > 0 && (pte32 & PG_PS) != 0)\n\t\t\t\tbreak;\n\n\t\t\tptpphys = pte32;\n\t\t}\n\n\t\t/* Set the dirty bit in the page table entry if necessary */\n\t\tif (writable && (pte32 & PG_M) == 0) {\n\t\t\tif (atomic_cmpset_32(&ptpbase32[ptpindex],\n\t\t\t    pte32, pte32 | PG_M) == 0) {\n\t\t\t\tgoto restart;\n\t\t\t}\n\t\t}\n\n\t\t/* Zero out the lower 'ptpshift' bits */\n\t\tpte32 >>= ptpshift; pte32 <<= ptpshift;\n\t\t*gpa = pte32 | (gla & (pgsize - 1));\n\t\tgoto done;\n\t}\n\n\tif (paging->paging_mode == PAGING_MODE_PAE) {\n\t\t/* Zero out the lower 5 bits and the upper 32 bits */\n\t\tptpphys &= 0xffffffe0UL;\n\n\t\tptpbase = vm_gpa2hva(vm, ptpphys, (sizeof(*ptpbase) * 4));\n\t\tif (ptpbase == NULL)\n\t\t\tgoto error;\n\n\t\tptpindex = (gla >> 30) & 0x3;\n\n\t\tpte = ptpbase[ptpindex];\n\n\t\tif ((pte & PG_V) == 0) {\n\t\t\tpfcode = pf_error_code(usermode, prot, 0, pte);\n\t\t\tvm_inject_pf(vm, vcpuid, pfcode, gla);\n\t\t\tgoto fault;\n\t\t}\n\n\t\tptpphys = pte;\n\n\t\tnlevels = 2;\n\t} else\n\t\tnlevels = 4;\n\twhile (--nlevels >= 0) {\n\t\t/* Zero out the lower 12 bits and the upper 12 bits */\n\t\tptpphys >>= 12; ptpphys <<= 24; ptpphys >>= 12;\n\n\t\tptpbase = vm_gpa2hva(vm, ptpphys, XHYVE_PAGE_SIZE);\n\t\tif (ptpbase == NULL)\n\t\t\tgoto error;\n\n\t\tptpshift = XHYVE_PAGE_SHIFT + nlevels * 9;\n\t\tptpindex = (gla >> ptpshift) & 0x1FF;\n\t\tpgsize = 1UL << ptpshift;\n\n\t\tpte = ptpbase[ptpindex];\n\n\t\tif ((pte & PG_V) == 0 ||\n\t\t    (usermode && (pte & PG_U) == 0) ||\n\t\t    (writable && (pte & PG_RW) == 0)) {\n\t\t\tpfcode = pf_error_code(usermode, prot, 0, pte);\n\t\t\tvm_inject_pf(vm, vcpuid, pfcode, gla);\n\t\t\tgoto fault;\n\t\t}\n\n\t\t/* Set the accessed bit in the page table entry */\n\t\tif ((pte & PG_A) == 0) {\n\t\t\tif (atomic_cmpset_64(((volatile u_long *) &ptpbase[ptpindex]),\n\t\t\t    pte, pte | PG_A) == 0) {\n\t\t\t\tgoto restart;\n\t\t\t}\n\t\t}\n\n\t\tif (nlevels > 0 && (pte & PG_PS) != 0) {\n\t\t\tif (pgsize > 1 * GB) {\n\t\t\t\tpfcode = pf_error_code(usermode, prot, 1, pte);\n\t\t\t\tvm_inject_pf(vm, vcpuid, pfcode, gla);\n\t\t\t\tgoto fault;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tptpphys = pte;\n\t}\n\n\t/* Set the dirty bit in the page table entry if necessary */\n\tif (writable && (pte & PG_M) == 0) {\n\t\tif (atomic_cmpset_64(((volatile u_long *) &ptpbase[ptpindex]), pte,\n\t\t\tpte | PG_M) == 0)\n\t\t{\n\t\t\tgoto restart;\n\t\t}\n\t}\n\n\t/* Zero out the lower 'ptpshift' bits and the upper 12 bits */\n\tpte >>= ptpshift; pte <<= (ptpshift + 12); pte >>= 12;\n\t*gpa = pte | (gla & (pgsize - 1));\ndone:\n\tKASSERT(retval == 0 || retval == EFAULT, (\"%s: unexpected retval %d\",\n\t    __func__, retval));\n\treturn (retval);\nerror:\n\tretval = EFAULT;\n\tgoto done;\nfault:\n\t*guest_fault = 1;\n\tgoto done;\n}\n\nint\nvmm_fetch_instruction(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,\n    uint64_t rip, int inst_length, struct vie *vie, int *faultptr)\n{\n\tstruct vm_copyinfo copyinfo[2];\n\tint error, prot;\n\n\tif (inst_length > VIE_INST_SIZE)\n\t\txhyve_abort(\"vmm_fetch_instruction: invalid length %d\\n\", inst_length);\n\n\tprot = XHYVE_PROT_READ | XHYVE_PROT_EXECUTE;\n\terror = vm_copy_setup(vm, vcpuid, paging, rip, ((size_t) inst_length), prot,\n\t    copyinfo, nitems(copyinfo), faultptr);\n\tif (error || *faultptr)\n\t\treturn (error);\n\n\tvm_copyin(vm, vcpuid, copyinfo, vie->inst, ((size_t) inst_length));\n\tvm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo));\n\tvie->num_valid = (uint8_t) inst_length;\n\treturn (0);\n}\n\nstatic int\nvie_peek(struct vie *vie, uint8_t *x)\n{\n\n\tif (vie->num_processed < vie->num_valid) {\n\t\t*x = vie->inst[vie->num_processed];\n\t\treturn (0);\n\t} else\n\t\treturn (-1);\n}\n\nstatic void\nvie_advance(struct vie *vie)\n{\n\n\tvie->num_processed++;\n}\n\nstatic bool\nsegment_override(uint8_t x, int *seg)\n{\n\n\tswitch (x) {\n\tcase 0x2E:\n\t\t*seg = VM_REG_GUEST_CS;\n\t\tbreak;\n\tcase 0x36:\n\t\t*seg = VM_REG_GUEST_SS;\n\t\tbreak;\n\tcase 0x3E:\n\t\t*seg = VM_REG_GUEST_DS;\n\t\tbreak;\n\tcase 0x26:\n\t\t*seg = VM_REG_GUEST_ES;\n\t\tbreak;\n\tcase 0x64:\n\t\t*seg = VM_REG_GUEST_FS;\n\t\tbreak;\n\tcase 0x65:\n\t\t*seg = VM_REG_GUEST_GS;\n\t\tbreak;\n\tdefault:\n\t\treturn (false);\n\t}\n\treturn (true);\n}\n\nstatic int\ndecode_prefixes(struct vie *vie, enum vm_cpu_mode cpu_mode, int cs_d)\n{\n\tuint8_t x;\n\n\twhile (1) {\n\t\tif (vie_peek(vie, &x))\n\t\t\treturn (-1);\n\n\t\tif (x == 0x66)\n\t\t\tvie->opsize_override = 1;\n\t\telse if (x == 0x67)\n\t\t\tvie->addrsize_override = 1;\n\t\telse if (x == 0xF3)\n\t\t\tvie->repz_present = 1;\n\t\telse if (x == 0xF2)\n\t\t\tvie->repnz_present = 1;\n\t\telse if (segment_override(x, &vie->segment_register))\n\t\t\tvie->segment_override = 1;\n\t\telse\n\t\t\tbreak;\n\n\t\tvie_advance(vie);\n\t}\n\n\t/*\n\t * From section 2.2.1, \"REX Prefixes\", Intel SDM Vol 2:\n\t * - Only one REX prefix is allowed per instruction.\n\t * - The REX prefix must immediately precede the opcode byte or the\n\t *   escape opcode byte.\n\t * - If an instruction has a mandatory prefix (0x66, 0xF2 or 0xF3)\n\t *   the mandatory prefix must come before the REX prefix.\n\t */\n\tif (cpu_mode == CPU_MODE_64BIT && x >= 0x40 && x <= 0x4F) {\n\t\tvie->rex_present = 1;\n\t\tvie->rex_w = x & 0x8 ? 1 : 0;\n\t\tvie->rex_r = x & 0x4 ? 1 : 0;\n\t\tvie->rex_x = x & 0x2 ? 1 : 0;\n\t\tvie->rex_b = x & 0x1 ? 1 : 0;\n\t\tvie_advance(vie);\n\t}\n\n\t/*\n\t * Section \"Operand-Size And Address-Size Attributes\", Intel SDM, Vol 1\n\t */\n\tif (cpu_mode == CPU_MODE_64BIT) {\n\t\t/*\n\t\t * Default address size is 64-bits and default operand size\n\t\t * is 32-bits.\n\t\t */\n\t\tvie->addrsize = vie->addrsize_override ? 4 : 8;\n\t\tif (vie->rex_w)\n\t\t\tvie->opsize = 8;\n\t\telse if (vie->opsize_override)\n\t\t\tvie->opsize = 2;\n\t\telse\n\t\t\tvie->opsize = 4;\n\t} else if (cs_d) {\n\t\t/* Default address and operand sizes are 32-bits */\n\t\tvie->addrsize = vie->addrsize_override ? 2 : 4;\n\t\tvie->opsize = vie->opsize_override ? 2 : 4;\n\t} else {\n\t\t/* Default address and operand sizes are 16-bits */\n\t\tvie->addrsize = vie->addrsize_override ? 4 : 2;\n\t\tvie->opsize = vie->opsize_override ? 4 : 2;\n\t}\n\treturn (0);\n}\n\nstatic int\ndecode_two_byte_opcode(struct vie *vie)\n{\n\tuint8_t x;\n\n\tif (vie_peek(vie, &x))\n\t\treturn (-1);\n\n\tvie->op = two_byte_opcodes[x];\n\n\tif (vie->op.op_type == VIE_OP_TYPE_NONE)\n\t\treturn (-1);\n\n\tvie_advance(vie);\n\treturn (0);\n}\n\nstatic int\ndecode_opcode(struct vie *vie)\n{\n\tuint8_t x;\n\n\tif (vie_peek(vie, &x))\n\t\treturn (-1);\n\n\tvie->op = one_byte_opcodes[x];\n\n\tif (vie->op.op_type == VIE_OP_TYPE_NONE)\n\t\treturn (-1);\n\n\tvie_advance(vie);\n\n\tif (vie->op.op_type == VIE_OP_TYPE_TWO_BYTE)\n\t\treturn (decode_two_byte_opcode(vie));\n\n\treturn (0);\n}\n\nstatic int\ndecode_modrm(struct vie *vie, enum vm_cpu_mode cpu_mode)\n{\n\tuint8_t x;\n\n\tif (vie->op.op_flags & VIE_OP_F_NO_MODRM)\n\t\treturn (0);\n\n\tif (cpu_mode == CPU_MODE_REAL)\n\t\treturn (-1);\n\n\tif (vie_peek(vie, &x))\n\t\treturn (-1);\n\n\tvie->mod = (x >> 6) & 0x3;\n\tvie->rm =  (x >> 0) & 0x7;\n\tvie->reg = (x >> 3) & 0x7;\n\n\t/*\n\t * A direct addressing mode makes no sense in the context of an EPT\n\t * fault. There has to be a memory access involved to cause the\n\t * EPT fault.\n\t */\n\tif (vie->mod == VIE_MOD_DIRECT)\n\t\treturn (-1);\n\n\tif ((vie->mod == VIE_MOD_INDIRECT && vie->rm == VIE_RM_DISP32) ||\n\t    (vie->mod != VIE_MOD_DIRECT && vie->rm == VIE_RM_SIB)) {\n\t\t/*\n\t\t * Table 2-5: Special Cases of REX Encodings\n\t\t *\n\t\t * mod=0, r/m=5 is used in the compatibility mode to\n\t\t * indicate a disp32 without a base register.\n\t\t *\n\t\t * mod!=3, r/m=4 is used in the compatibility mode to\n\t\t * indicate that the SIB byte is present.\n\t\t *\n\t\t * The 'b' bit in the REX prefix is don't care in\n\t\t * this case.\n\t\t */\n\t} else {\n\t\tvie->rm |= (vie->rex_b << 3);\n\t}\n\n\tvie->reg |= (vie->rex_r << 3);\n\n\t/* SIB */\n\tif (vie->mod != VIE_MOD_DIRECT && vie->rm == VIE_RM_SIB)\n\t\tgoto done;\n\n\tvie->base_register = (int) gpr_map[vie->rm];\n\n\tswitch (vie->mod) {\n\tcase VIE_MOD_INDIRECT_DISP8:\n\t\tvie->disp_bytes = 1;\n\t\tbreak;\n\tcase VIE_MOD_INDIRECT_DISP32:\n\t\tvie->disp_bytes = 4;\n\t\tbreak;\n\tcase VIE_MOD_INDIRECT:\n\t\tif (vie->rm == VIE_RM_DISP32) {\n\t\t\tvie->disp_bytes = 4;\n\t\t\t/*\n\t\t\t * Table 2-7. RIP-Relative Addressing\n\t\t\t *\n\t\t\t * In 64-bit mode mod=00 r/m=101 implies [rip] + disp32\n\t\t\t * whereas in compatibility mode it just implies disp32.\n\t\t\t */\n\n\t\t\tif (cpu_mode == CPU_MODE_64BIT)\n\t\t\t\tvie->base_register = VM_REG_GUEST_RIP;\n\t\t\telse\n\t\t\t\tvie->base_register = VM_REG_LAST;\n\t\t}\n\t\tbreak;\n\t}\n\ndone:\n\tvie_advance(vie);\n\n\treturn (0);\n}\n\nstatic int\ndecode_sib(struct vie *vie)\n{\n\tuint8_t x;\n\n\t/* Proceed only if SIB byte is present */\n\tif (vie->mod == VIE_MOD_DIRECT || vie->rm != VIE_RM_SIB)\n\t\treturn (0);\n\n\tif (vie_peek(vie, &x))\n\t\treturn (-1);\n\n\t/* De-construct the SIB byte */\n\tvie->ss = (x >> 6) & 0x3;\n\tvie->index = (x >> 3) & 0x7;\n\tvie->base = (x >> 0) & 0x7;\n\n\t/* Apply the REX prefix modifiers */\n\tvie->index |= vie->rex_x << 3;\n\tvie->base |= vie->rex_b << 3;\n\n\tswitch (vie->mod) {\n\tcase VIE_MOD_INDIRECT_DISP8:\n\t\tvie->disp_bytes = 1;\n\t\tbreak;\n\tcase VIE_MOD_INDIRECT_DISP32:\n\t\tvie->disp_bytes = 4;\n\t\tbreak;\n\t}\n\n\tif (vie->mod == VIE_MOD_INDIRECT &&\n\t    (vie->base == 5 || vie->base == 13)) {\n\t\t/*\n\t\t * Special case when base register is unused if mod = 0\n\t\t * and base = %rbp or %r13.\n\t\t *\n\t\t * Documented in:\n\t\t * Table 2-3: 32-bit Addressing Forms with the SIB Byte\n\t\t * Table 2-5: Special Cases of REX Encodings\n\t\t */\n\t\tvie->disp_bytes = 4;\n\t} else {\n\t\tvie->base_register = (int) gpr_map[vie->base];\n\t}\n\n\t/*\n\t * All encodings of 'index' are valid except for %rsp (4).\n\t *\n\t * Documented in:\n\t * Table 2-3: 32-bit Addressing Forms with the SIB Byte\n\t * Table 2-5: Special Cases of REX Encodings\n\t */\n\tif (vie->index != 4)\n\t\tvie->index_register = (int) gpr_map[vie->index];\n\n\t/* 'scale' makes sense only in the context of an index register */\n\tif (vie->index_register < VM_REG_LAST)\n\t\tvie->scale = (uint8_t) (1 << vie->ss);\n\n\tvie_advance(vie);\n\n\treturn (0);\n}\n\nstatic int\ndecode_displacement(struct vie *vie)\n{\n\tint n, i;\n\tuint8_t x;\n\n\tunion {\n\t\tchar\tbuf[4];\n\t\tint8_t\tsigned8;\n\t\tint32_t\tsigned32;\n\t} u;\n\n\tif ((n = vie->disp_bytes) == 0)\n\t\treturn (0);\n\n\tif (n != 1 && n != 4)\n\t\txhyve_abort(\"decode_displacement: invalid disp_bytes %d\\n\", n);\n\n\tfor (i = 0; i < n; i++) {\n\t\tif (vie_peek(vie, &x))\n\t\t\treturn (-1);\n\n\t\tu.buf[i] = (char) x;\n\t\tvie_advance(vie);\n\t}\n\n\tif (n == 1)\n\t\tvie->displacement = u.signed8;\t\t/* sign-extended */\n\telse\n\t\tvie->displacement = u.signed32;\t\t/* sign-extended */\n\n\treturn (0);\n}\n\nstatic int\ndecode_immediate(struct vie *vie)\n{\n\tint i, n;\n\tuint8_t x;\n\tunion {\n\t\tchar\tbuf[4];\n\t\tint8_t\tsigned8;\n\t\tint16_t\tsigned16;\n\t\tint32_t\tsigned32;\n\t} u;\n\n\t/* Figure out immediate operand size (if any) */\n\tif (vie->op.op_flags & VIE_OP_F_IMM) {\n\t\t/*\n\t\t * Section 2.2.1.5 \"Immediates\", Intel SDM:\n\t\t * In 64-bit mode the typical size of immediate operands\n\t\t * remains 32-bits. When the operand size if 64-bits, the\n\t\t * processor sign-extends all immediates to 64-bits prior\n\t\t * to their use.\n\t\t */\n\t\tif (vie->opsize == 4 || vie->opsize == 8)\n\t\t\tvie->imm_bytes = 4;\n\t\telse\n\t\t\tvie->imm_bytes = 2;\n\t} else if (vie->op.op_flags & VIE_OP_F_IMM8) {\n\t\tvie->imm_bytes = 1;\n\t}\n\n\tif ((n = vie->imm_bytes) == 0)\n\t\treturn (0);\n\n\tKASSERT(n == 1 || n == 2 || n == 4,\n\t    (\"%s: invalid number of immediate bytes: %d\", __func__, n));\n\n\tfor (i = 0; i < n; i++) {\n\t\tif (vie_peek(vie, &x))\n\t\t\treturn (-1);\n\n\t\tu.buf[i] = (char) x;\n\t\tvie_advance(vie);\n\t}\n\n\t/* sign-extend the immediate value before use */\n\tif (n == 1)\n\t\tvie->immediate = u.signed8;\n\telse if (n == 2)\n\t\tvie->immediate = u.signed16;\n\telse\n\t\tvie->immediate = u.signed32;\n\n\treturn (0);\n}\n\nstatic int\ndecode_moffset(struct vie *vie)\n{\n\tint i, n;\n\tuint8_t x;\n\tunion {\n\t\tchar\tbuf[8];\n\t\tuint64_t u64;\n\t} u;\n\n\tif ((vie->op.op_flags & VIE_OP_F_MOFFSET) == 0)\n\t\treturn (0);\n\n\t/*\n\t * Section 2.2.1.4, \"Direct Memory-Offset MOVs\", Intel SDM:\n\t * The memory offset size follows the address-size of the instruction.\n\t */\n\tn = vie->addrsize;\n\tKASSERT(n == 2 || n == 4 || n == 8, (\"invalid moffset bytes: %d\", n));\n\n\tu.u64 = 0;\n\tfor (i = 0; i < n; i++) {\n\t\tif (vie_peek(vie, &x))\n\t\t\treturn (-1);\n\n\t\tu.buf[i] = (char) x;\n\t\tvie_advance(vie);\n\t}\n\tvie->displacement = (int64_t) u.u64;\n\treturn (0);\n}\n\n/*\n * Verify that all the bytes in the instruction buffer were consumed.\n */\nstatic int\nverify_inst_length(struct vie *vie)\n{\n\n\tif (vie->num_processed)\n\t\treturn (0);\n\telse\n\t\treturn (-1);\n}\n\n/*\n * Verify that the 'guest linear address' provided as collateral of the nested\n * page table fault matches with our instruction decoding.\n */\nstatic int\nverify_gla(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie)\n{\n\tint error;\n\tuint64_t base, idx, gla2;\n\n\t/* Skip 'gla' verification */\n\tif (gla == VIE_INVALID_GLA)\n\t\treturn (0);\n\n\tbase = 0;\n\tif (vie->base_register != VM_REG_LAST) {\n\t\terror = vm_get_register(vm, cpuid, vie->base_register, &base);\n\t\tif (error) {\n\t\t\tprintf(\"verify_gla: error %d getting base reg %d\\n\",\n\t\t\t\terror, vie->base_register);\n\t\t\treturn (-1);\n\t\t}\n\n\t\t/*\n\t\t * RIP-relative addressing starts from the following\n\t\t * instruction\n\t\t */\n\t\tif (vie->base_register == VM_REG_GUEST_RIP)\n\t\t\tbase += vie->num_valid;\n\t}\n\n\tidx = 0;\n\tif (vie->index_register != VM_REG_LAST) {\n\t\terror = vm_get_register(vm, cpuid, vie->index_register, &idx);\n\t\tif (error) {\n\t\t\tprintf(\"verify_gla: error %d getting index reg %d\\n\",\n\t\t\t\terror, vie->index_register);\n\t\t\treturn (-1);\n\t\t}\n\t}\n\n\t/* XXX assuming that the base address of the segment is 0 */\n\tgla2 = base + vie->scale * idx + ((uint64_t) vie->displacement);\n\tgla2 &= size2mask[vie->addrsize];\n\tif (gla != gla2) {\n\t\tprintf(\"verify_gla mismatch: \"\n\t\t       \"base(0x%0llx), scale(%d), index(0x%0llx), \"\n\t\t       \"disp(0x%0llx), gla(0x%0llx), gla2(0x%0llx)\\n\",\n\t\t       base, vie->scale, idx, vie->displacement, gla, gla2);\n\t\treturn (-1);\n\t}\n\n\treturn (0);\n}\n\nint\nvmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla,\n\t\t       enum vm_cpu_mode cpu_mode, int cs_d, struct vie *vie)\n{\n\n\tif (decode_prefixes(vie, cpu_mode, cs_d))\n\t\treturn (-1);\n\n\tif (decode_opcode(vie))\n\t\treturn (-1);\n\n\tif (decode_modrm(vie, cpu_mode))\n\t\treturn (-1);\n\n\tif (decode_sib(vie))\n\t\treturn (-1);\n\n\tif (decode_displacement(vie))\n\t\treturn (-1);\n\n\tif (decode_immediate(vie))\n\t\treturn (-1);\n\n\tif (decode_moffset(vie))\n\t\treturn (-1);\n\n\tif (verify_inst_length(vie))\n\t\treturn (-1);\n\n\tif ((vie->op.op_flags & VIE_OP_F_NO_GLA_VERIFICATION) == 0) {\n\t\tif (verify_gla(vm, cpuid, gla, vie))\n\t\t\treturn (-1);\n\t}\n\n\tvie->decoded = 1;\t/* success */\n\n\treturn (0);\n}\n"
  },
  {
    "path": "src/vmm/vmm_ioport.c",
    "content": "/*-\n * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <errno.h>\n#include <xhyve/support/timerreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_instruction_emul.h>\n#include <xhyve/vmm/vmm_ioport.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/io/vatpic.h>\n#include <xhyve/vmm/io/vatpit.h>\n#include <xhyve/vmm/io/vpmtmr.h>\n#include <xhyve/vmm/io/vrtc.h>\n\n#define\tMAX_IOPORTS\t\t1280\n\nstatic const ioport_handler_func_t ioport_handler[MAX_IOPORTS] = {\n\t[TIMER_MODE] = vatpit_handler,\n\t[TIMER_CNTR0] = vatpit_handler,\n\t[TIMER_CNTR1] = vatpit_handler,\n\t[TIMER_CNTR2] = vatpit_handler,\n\t[NMISC_PORT] = vatpit_nmisc_handler,\n\t[IO_ICU1] = vatpic_master_handler,\n\t[IO_ICU1 + ICU_IMR_OFFSET] = vatpic_master_handler,\n\t[IO_ICU2] = vatpic_slave_handler,\n\t[IO_ICU2 + ICU_IMR_OFFSET] = vatpic_slave_handler,\n\t[IO_ELCR1] = vatpic_elc_handler,\n\t[IO_ELCR2] = vatpic_elc_handler,\n\t[IO_PMTMR] = vpmtmr_handler,\n\t[IO_RTC] = vrtc_addr_handler,\n\t[IO_RTC + 1] = vrtc_data_handler,\n};\n\n#ifdef XHYVE_CONFIG_TRACE\nstatic const char *\ninout_instruction(struct vm_exit *vmexit)\n{\n\tint index;\n\n\tstatic const char *iodesc[] = {\n\t\t\"outb\", \"outw\", \"outl\",\n\t\t\"inb\", \"inw\", \"inl\",\n\t\t\"outsb\", \"outsw\", \"outsd\",\n\t\t\"insb\", \"insw\", \"insd\",\n\t};\n\n\tswitch (vmexit->u.inout.bytes) {\n\tcase 1:\n\t\tindex = 0;\n\t\tbreak;\n\tcase 2:\n\t\tindex = 1;\n\t\tbreak;\n\tdefault:\n\t\tindex = 2;\n\t\tbreak;\n\t}\n\n\tif (vmexit->u.inout.in)\n\t\tindex += 3;\n\n\tif (vmexit->u.inout.string)\n\t\tindex += 6;\n\n\tKASSERT(((unsigned) index) < nitems(iodesc), (\"%s: invalid index %d\",\n\t    __func__, index));\n\n\treturn (iodesc[index]);\n}\n#endif\t/* XHYVE_CONFIG_TRACE */\n\nstatic int\nemulate_inout_port(struct vm *vm, int vcpuid, struct vm_exit *vmexit,\n    bool *retu)\n{\n\tioport_handler_func_t handler;\n\tuint32_t mask, val;\n\tint error;\n\n\t/*\n\t * If there is no handler for the I/O port then punt to userspace.\n\t */\n\tif (vmexit->u.inout.port >= MAX_IOPORTS ||\n\t    (handler = ioport_handler[vmexit->u.inout.port]) == NULL) {\n\t\t*retu = true;\n\t\treturn (0);\n\t}\n\n\tmask = (uint32_t) vie_size2mask(vmexit->u.inout.bytes);\n\n\tif (!vmexit->u.inout.in) {\n\t\tval = vmexit->u.inout.eax & mask;\n\t}\n\n\terror = (*handler)(vm, vcpuid, vmexit->u.inout.in,\n\t    vmexit->u.inout.port, vmexit->u.inout.bytes, &val);\n\tif (error) {\n\t\t/*\n\t\t * The value returned by this function is also the return value\n\t\t * of vm_run(). This needs to be a positive number otherwise it\n\t\t * can be interpreted as a \"pseudo-error\" like ERESTART.\n\t\t *\n\t\t * Enforce this by mapping all errors to EIO.\n\t\t */\n\t\treturn (EIO);\n\t}\n\n\tif (vmexit->u.inout.in) {\n\t\tvmexit->u.inout.eax &= ~mask;\n\t\tvmexit->u.inout.eax |= val & mask;\n\t\terror = vm_set_register(vm, vcpuid, VM_REG_GUEST_RAX,\n\t\t    vmexit->u.inout.eax);\n\t\tKASSERT(error == 0, (\"emulate_ioport: error %d setting guest \"\n\t\t    \"rax register\", error));\n\t}\n\t*retu = false;\n\treturn (0);\n}\n\nstatic int\nemulate_inout_str(bool *retu)\n{\n\t*retu = true;\n\treturn (0);\t/* Return to userspace to finish emulation */\n}\n\nint\nvm_handle_inout(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu)\n{\n\tint bytes, error;\n\n\tbytes = vmexit->u.inout.bytes;\n\tKASSERT(bytes == 1 || bytes == 2 || bytes == 4,\n\t    (\"vm_handle_inout: invalid operand size %d\", bytes));\n\n\tif (vmexit->u.inout.string)\n\t\terror = emulate_inout_str(retu);\n\telse\n\t\terror = emulate_inout_port(vm, vcpuid, vmexit, retu);\n\n#ifdef XHYVE_CONFIG_TRACE\n\tVCPU_CTR4(vm, vcpuid, \"%s%s 0x%04x: %s\",\n\t    vmexit->u.inout.rep ? \"rep \" : \"\",\n\t    inout_instruction(vmexit),\n\t    vmexit->u.inout.port,\n\t    error ? \"error\" : (*retu ? \"userspace\" : \"handled\"));\n#endif\n\n\treturn (error);\n}\n"
  },
  {
    "path": "src/vmm/vmm_lapic.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdbool.h>\n#include <errno.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/support/apicreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/vmm_lapic.h>\n#include <xhyve/vmm/io/vlapic.h>\n\n/*\n * Some MSI message definitions\n */\n#define\tMSI_X86_ADDR_MASK\t0xfff00000\n#define\tMSI_X86_ADDR_BASE\t0xfee00000\n#define\tMSI_X86_ADDR_RH\t\t0x00000008\t/* Redirection Hint */\n#define\tMSI_X86_ADDR_LOG\t0x00000004\t/* Destination Mode */\n\nint\nlapic_set_intr(struct vm *vm, int cpu, int vector, bool level)\n{\n\tstruct vlapic *vlapic;\n\n\tif (cpu < 0 || cpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\t/*\n\t * According to section \"Maskable Hardware Interrupts\" in Intel SDM\n\t * vectors 16 through 255 can be delivered through the local APIC.\n\t */\n\tif (vector < 16 || vector > 255)\n\t\treturn (EINVAL);\n\n\tvlapic = vm_lapic(vm, cpu);\n\tif (vlapic_set_intr_ready(vlapic, vector, level))\n\t\tvcpu_notify_event(vm, cpu, true);\n\treturn (0);\n}\n\nint\nlapic_set_local_intr(struct vm *vm, int cpu, int vector)\n{\n\tstruct vlapic *vlapic;\n\tcpuset_t dmask;\n\tint error;\n\n\tif (cpu < -1 || cpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\tif (cpu == -1)\n\t\tdmask = vm_active_cpus(vm);\n\telse\n\t\tCPU_SETOF(((unsigned) cpu), &dmask);\n\terror = 0;\n\twhile ((cpu = CPU_FFS(&dmask)) != 0) {\n\t\tcpu--;\n\t\tCPU_CLR(((unsigned) cpu), &dmask);\n\t\tvlapic = vm_lapic(vm, cpu);\n\t\terror = vlapic_trigger_lvt(vlapic, vector);\n\t\tif (error)\n\t\t\tbreak;\n\t}\n\n\treturn (error);\n}\n\nint\nlapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg)\n{\n\tint delmode, vec;\n\tuint32_t dest;\n\tbool phys;\n\n\tVM_CTR2(vm, \"lapic MSI addr: %#llx msg: %#llx\", addr, msg);\n\n\tif ((addr & MSI_X86_ADDR_MASK) != MSI_X86_ADDR_BASE) {\n\t\tVM_CTR1(vm, \"lapic MSI invalid addr %#llx\", addr);\n\t\treturn (-1);\n\t}\n\n\t/*\n\t * Extract the x86-specific fields from the MSI addr/msg\n\t * params according to the Intel Arch spec, Vol3 Ch 10.\n\t *\n\t * The PCI specification does not support level triggered\n\t * MSI/MSI-X so ignore trigger level in 'msg'.\n\t *\n\t * The 'dest' is interpreted as a logical APIC ID if both\n\t * the Redirection Hint and Destination Mode are '1' and\n\t * physical otherwise.\n\t */\n\tdest = (addr >> 12) & 0xff;\n\tphys = ((addr & (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG)) !=\n\t    (MSI_X86_ADDR_RH | MSI_X86_ADDR_LOG));\n\tdelmode = msg & APIC_DELMODE_MASK;\n\tvec = msg & 0xff;\n\n\tVM_CTR3(vm, \"lapic MSI %s dest %#x, vec %d\",\n\t    phys ? \"physical\" : \"logical\", dest, vec);\n\n\tvlapic_deliver_intr(vm, LAPIC_TRIG_EDGE, dest, phys, delmode, vec);\n\treturn (0);\n}\n\nstatic bool\nx2apic_msr(u_int msr)\n{\n\tif (msr >= 0x800 && msr <= 0xBFF)\n\t\treturn (TRUE);\n\telse\n\t\treturn (FALSE);\n}\n\nstatic u_int\nx2apic_msr_to_regoff(u_int msr)\n{\n\n\treturn ((msr - 0x800) << 4);\n}\n\nbool\nlapic_msr(u_int msr)\n{\n\n\tif (x2apic_msr(msr) || (msr == MSR_APICBASE))\n\t\treturn (TRUE);\n\telse\n\t\treturn (FALSE);\n}\n\nint\nlapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval, bool *retu)\n{\n\tint error;\n\tu_int offset;\n\tstruct vlapic *vlapic;\n\n\tvlapic = vm_lapic(vm, cpu);\n\n\tif (msr == MSR_APICBASE) {\n\t\t*rval = vlapic_get_apicbase(vlapic);\n\t\terror = 0;\n\t} else {\n\t\toffset = x2apic_msr_to_regoff(msr);\n\t\terror = vlapic_read(vlapic, 0, offset, rval, retu);\n\t}\n\n\treturn (error);\n}\n\nint\nlapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val, bool *retu)\n{\n\tint error;\n\tu_int offset;\n\tstruct vlapic *vlapic;\n\n\tvlapic = vm_lapic(vm, cpu);\n\n\tif (msr == MSR_APICBASE) {\n\t\terror = vlapic_set_apicbase(vlapic, val);\n\t} else {\n\t\toffset = x2apic_msr_to_regoff(msr);\n\t\terror = vlapic_write(vlapic, 0, offset, val, retu);\n\t}\n\n\treturn (error);\n}\n\nint\nlapic_mmio_write(void *vm, int cpu, uint64_t gpa, uint64_t wval, int size,\n\t\t void *arg)\n{\n\tint error;\n\tuint64_t off;\n\tstruct vlapic *vlapic;\n//printf(\"lapic_mmio_write 0x%016llx 0x%016llx\\n\", gpa, wval);\n\toff = gpa - DEFAULT_APIC_BASE;\n\n\t/*\n\t * Memory mapped local apic accesses must be 4 bytes wide and\n\t * aligned on a 16-byte boundary.\n\t */\n\tif (size != 4 || off & 0xf)\n\t\treturn (EINVAL);\n\n\tvlapic = vm_lapic(vm, cpu);\n\terror = vlapic_write(vlapic, 1, off, wval, arg);\n\treturn (error);\n}\n\nint\nlapic_mmio_read(void *vm, int cpu, uint64_t gpa, uint64_t *rval,\n\tUNUSED int size, void *arg)\n{\n\tint error;\n\tuint64_t off;\n\tstruct vlapic *vlapic;\n\n\toff = gpa - DEFAULT_APIC_BASE;\n\n\t/*\n\t * Memory mapped local apic accesses should be aligned on a\n\t * 16-byte boundary.  They are also suggested to be 4 bytes\n\t * wide, alas not all OSes follow suggestions.\n\t */\n\toff &= ~((uint64_t) 3);\n\tif (off & 0xf)\n\t\treturn (EINVAL);\n\n\tvlapic = vm_lapic(vm, cpu);\n\terror = vlapic_read(vlapic, 1, off, rval, arg);\n\t//printf(\"lapic_mmio_read 0x%016llx (0x%016llx)\\n\", gpa, *rval);\n\treturn (error);\n}\n"
  },
  {
    "path": "src/vmm/vmm_mem.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdlib.h>\n#include <Hypervisor/hv.h>\n#include <Hypervisor/hv_vmx.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm_mem.h>\n\nint\nvmm_mem_init(void)\n{\n\treturn (0);\n}\n\nvoid *\nvmm_mem_alloc(uint64_t gpa, size_t size, uint64_t prot)\n{\n\tvoid *object;\n    hv_memory_flags_t hvProt;\n\n\tobject = valloc(size);\n\n\tif (!object) {\n\t\txhyve_abort(\"vmm_mem_alloc failed\\n\");\n\t}\n\n    hvProt = (prot & XHYVE_PROT_READ) ? HV_MEMORY_READ : 0;\n    hvProt |= (prot & XHYVE_PROT_WRITE) ? HV_MEMORY_WRITE : 0;\n    hvProt |= (prot & XHYVE_PROT_EXECUTE) ? HV_MEMORY_EXEC : 0;\n\n\tif (hv_vm_map(object, gpa, size, hvProt))\n\t{\n\t\txhyve_abort(\"hv_vm_map failed\\n\");\n\t}\n\n\treturn object;\n}\n\nvoid\nvmm_mem_free(uint64_t gpa, size_t size, void *object)\n{\n\thv_vm_unmap(gpa, size);\n\tfree(object);\n}\n"
  },
  {
    "path": "src/vmm/vmm_stat.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <errno.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_util.h>\n#include <xhyve/vmm/vmm_stat.h>\n\n/*\n * 'vst_num_elems' is the total number of addressable statistic elements\n * 'vst_num_types' is the number of unique statistic types\n *\n * It is always true that 'vst_num_elems' is greater than or equal to\n * 'vst_num_types'. This is because a stat type may represent more than\n * one element (for e.g. VMM_STAT_ARRAY).\n */\nstatic int vst_num_elems, vst_num_types;\nstatic struct vmm_stat_type *vsttab[MAX_VMM_STAT_ELEMS];\n\n#define\tvst_size\t((size_t)vst_num_elems * sizeof(uint64_t))\n\nvoid\nvmm_stat_register(void *arg)\n{\n\tstruct vmm_stat_type *vst = arg;\n\n\t/* We require all stats to identify themselves with a description */\n\tif (vst->desc == NULL)\n\t\treturn;\n\n\tif (vst_num_elems + vst->nelems >= MAX_VMM_STAT_ELEMS) {\n\t\tprintf(\"Cannot accomodate vmm stat type \\\"%s\\\"!\\n\", vst->desc);\n\t\treturn;\n\t}\n\n\tvst->index = vst_num_elems;\n\tvst_num_elems += vst->nelems;\n\n\tvsttab[vst_num_types++] = vst;\n}\n\nint\nvmm_stat_copy(struct vm *vm, int vcpu, int *num_stats, uint64_t *buf)\n{\n\tstruct vmm_stat_type *vst;\n\tuint64_t *stats;\n\tint i;\n\n\tif (vcpu < 0 || vcpu >= VM_MAXCPU)\n\t\treturn (EINVAL);\n\n\t/* Let stats functions update their counters */\n\tfor (i = 0; i < vst_num_types; i++) {\n\t\tvst = vsttab[i];\n\t\tif (vst->func != NULL)\n\t\t\t(*vst->func)(vm, vcpu, vst);\n\t}\n\n\t/* Copy over the stats */\n\tstats = vcpu_stats(vm, vcpu);\n\tfor (i = 0; i < vst_num_elems; i++)\n\t\tbuf[i] = stats[i];\n\t*num_stats = vst_num_elems;\n\treturn (0);\n}\n\nvoid *\nvmm_stat_alloc(void)\n{\n\n\treturn (malloc(vst_size));\n}\n\nvoid\nvmm_stat_init(void *vp)\n{\n\n\tbzero(vp, vst_size);\n}\n\nvoid\nvmm_stat_free(void *vp)\n{\n\tfree(vp);\n}\n\nint\nvmm_stat_desc_copy(int index, char *buf, size_t bufsize)\n{\n\tint i;\n\tstruct vmm_stat_type *vst;\n\n\tfor (i = 0; i < vst_num_types; i++) {\n\t\tvst = vsttab[i];\n\t\tif (index >= vst->index && index < vst->index + vst->nelems) {\n\t\t\tif (vst->nelems > 1) {\n\t\t\t\tsnprintf(buf, bufsize, \"%s[%d]\",\n\t\t\t\t\t vst->desc, index - vst->index);\n\t\t\t} else {\n\t\t\t\tstrlcpy(buf, vst->desc, bufsize);\n\t\t\t}\n\t\t\treturn (0);\t/* found it */\n\t\t}\n\t}\n\n\treturn (EINVAL);\n}\n\n/* global statistics */\nVMM_STAT(VCPU_MIGRATIONS, \"vcpu migration across host cpus\");\nVMM_STAT(VMEXIT_COUNT, \"total number of vm exits\");\nVMM_STAT(VMEXIT_EXTINT, \"vm exits due to external interrupt\");\nVMM_STAT(VMEXIT_HLT, \"number of times hlt was intercepted\");\nVMM_STAT(VMEXIT_CR_ACCESS, \"number of times %cr access was intercepted\");\nVMM_STAT(VMEXIT_RDMSR, \"number of times rdmsr was intercepted\");\nVMM_STAT(VMEXIT_WRMSR, \"number of times wrmsr was intercepted\");\nVMM_STAT(VMEXIT_MTRAP, \"number of monitor trap exits\");\nVMM_STAT(VMEXIT_PAUSE, \"number of times pause was intercepted\");\nVMM_STAT(VMEXIT_INTR_WINDOW, \"vm exits due to interrupt window opening\");\nVMM_STAT(VMEXIT_NMI_WINDOW, \"vm exits due to nmi window opening\");\nVMM_STAT(VMEXIT_INOUT, \"number of times in/out was intercepted\");\nVMM_STAT(VMEXIT_CPUID, \"number of times cpuid was intercepted\");\nVMM_STAT(VMEXIT_NESTED_FAULT, \"vm exits due to nested page fault\");\nVMM_STAT(VMEXIT_INST_EMUL, \"vm exits for instruction emulation\");\nVMM_STAT(VMEXIT_UNKNOWN, \"number of vm exits for unknown reason\");\nVMM_STAT(VMEXIT_ASTPENDING, \"number of times astpending at exit\");\nVMM_STAT(VMEXIT_USERSPACE, \"number of vm exits handled in userspace\");\nVMM_STAT(VMEXIT_RENDEZVOUS, \"number of times rendezvous pending at exit\");\nVMM_STAT(VMEXIT_EXCEPTION, \"number of vm exits due to exceptions\");\n"
  },
  {
    "path": "src/vmm/vmm_util.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdio.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/vmm/vmm_util.h>\n\nstruct trapframe {\n\tregister_t\ttf_rdi;\n\tregister_t\ttf_rsi;\n\tregister_t\ttf_rdx;\n\tregister_t\ttf_rcx;\n\tregister_t\ttf_r8;\n\tregister_t\ttf_r9;\n\tregister_t\ttf_rax;\n\tregister_t\ttf_rbx;\n\tregister_t\ttf_rbp;\n\tregister_t\ttf_r10;\n\tregister_t\ttf_r11;\n\tregister_t\ttf_r12;\n\tregister_t\ttf_r13;\n\tregister_t\ttf_r14;\n\tregister_t\ttf_r15;\n\tuint32_t\ttf_trapno;\n\tuint16_t\ttf_fs;\n\tuint16_t\ttf_gs;\n\tregister_t\ttf_addr;\n\tuint32_t\ttf_flags;\n\tuint16_t\ttf_es;\n\tuint16_t\ttf_ds;\n\t/* below portion defined in hardware */\n\tregister_t\ttf_err;\n\tregister_t\ttf_rip;\n\tregister_t\ttf_cs;\n\tregister_t\ttf_rflags;\n\tregister_t\ttf_rsp;\n\tregister_t\ttf_ss;\n};\n\n#define\tDUMP_REG(x)\tprintf(#x \"\\t\\t0x%016lx\\n\", (long)(tf->tf_ ## x))\n#define\tDUMP_SEG(x)\tprintf(#x \"\\t\\t0x%04x\\n\", (unsigned)(tf->tf_ ## x))\nvoid\ndump_trapframe(struct trapframe *tf)\n{\n\tDUMP_REG(rdi);\n\tDUMP_REG(rsi);\n\tDUMP_REG(rdx);\n\tDUMP_REG(rcx);\n\tDUMP_REG(r8);\n\tDUMP_REG(r9);\n\tDUMP_REG(rax);\n\tDUMP_REG(rbx);\n\tDUMP_REG(rbp);\n\tDUMP_REG(r10);\n\tDUMP_REG(r11);\n\tDUMP_REG(r12);\n\tDUMP_REG(r13);\n\tDUMP_REG(r14);\n\tDUMP_REG(r15);\n\tDUMP_REG(trapno);\n\tDUMP_REG(addr);\n\tDUMP_REG(flags);\n\tDUMP_REG(err);\n\tDUMP_REG(rip);\n\tDUMP_REG(rflags);\n\tDUMP_REG(rsp);\n\tDUMP_SEG(cs);\n\tDUMP_SEG(ss);\n\tDUMP_SEG(fs);\n\tDUMP_SEG(gs);\n\tDUMP_SEG(es);\n\tDUMP_SEG(ds);\n}\n"
  },
  {
    "path": "src/vmm/x86.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <strings.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm.h>\n#include <xhyve/vmm/vmm_host.h>\n#include <xhyve/vmm/vmm_ktr.h>\n#include <xhyve/vmm/x86.h>\n\n#define\tCPUID_VM_HIGH\t\t0x40000000\n\nstatic const char bhyve_id[12] = \"bhyve bhyve \";\n\nstatic volatile u_long bhyve_xcpuids;\n\n/*\n * The default CPU topology is a single thread per package.\n */\nstatic u_int threads_per_core = 1;\nstatic u_int cores_per_package = 1;\nstatic int cpuid_leaf_b = 1;\n\n/*\n * Round up to the next power of two, if necessary, and then take log2.\n * Returns -1 if argument is zero.\n */\nstatic __inline int\nlog2(u_int x)\n{\n\n\treturn (fls((int) (x << (1 - powerof2(x)))) - 1);\n}\n\nint\nx86_emulate_cpuid(struct vm *vm, int vcpu_id,\n\t\t  uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)\n{\n\tconst struct xsave_limits *limits;\n\tuint64_t cr4;\n\tint error, level, width, x2apic_id;\n\tunsigned int func, regs[4], logical_cpus;\n\tu_int cpu_feature, amd_feature, amd_feature2, cpu_high, cpu_exthigh;\n\tu_int tsc_is_invariant, smp_tsc;\n\tenum x2apic_state x2apic_state;\n\n\tVCPU_CTR2(vm, vcpu_id, \"cpuid %#x,%#x\", *eax, *ecx);\n\n\ttsc_is_invariant = 1;\n\tsmp_tsc = 1;\n\tdo_cpuid(0, regs);\n\tcpu_high = regs[0];\n\tdo_cpuid(1, regs);\n\tcpu_feature = regs[3];\n\tdo_cpuid(0x80000000, regs);\n\tcpu_exthigh = regs[0];\n\tdo_cpuid(0x80000001, regs);\n\tamd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff);\n\tamd_feature2 = regs[2];\n\n\t/*\n\t * Requests for invalid CPUID levels should map to the highest\n\t * available level instead.\n\t */\n\tif (cpu_exthigh != 0 && *eax >= 0x80000000) {\n\t\tif (*eax > cpu_exthigh)\n\t\t\t*eax = cpu_exthigh;\n\t} else if (*eax >= 0x40000000) {\n\t\tif (*eax > CPUID_VM_HIGH)\n\t\t\t*eax = CPUID_VM_HIGH;\n\t} else if (*eax > cpu_high) {\n\t\t*eax = cpu_high;\n\t}\n\n\tfunc = *eax;\n\n\t/*\n\t * In general the approach used for CPU topology is to\n\t * advertise a flat topology where all CPUs are packages with\n\t * no multi-core or SMT.\n\t */\n\tswitch (func) {\n\t\t/*\n\t\t * Pass these through to the guest\n\t\t */\n\t\tcase CPUID_0000_0000:\n\t\tcase CPUID_0000_0002:\n\t\tcase CPUID_0000_0003:\n\t\tcase CPUID_8000_0000:\n\t\tcase CPUID_8000_0002:\n\t\tcase CPUID_8000_0003:\n\t\tcase CPUID_8000_0004:\n\t\tcase CPUID_8000_0006:\n\t\t\tcpuid_count(*eax, *ecx, regs);\n\t\t\tbreak;\n\t\tcase CPUID_8000_0008:\n\t\t\tcpuid_count(*eax, *ecx, regs);\n\t\t\tbreak;\n\t\tcase CPUID_8000_0001:\n\t\t\tcpuid_count(*eax, *ecx, regs);\n\n\t\t\t/*\n\t\t\t * Hide SVM and Topology Extension features from guest.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) (AMDID2_SVM | AMDID2_TOPOLOGY));\n\n\t\t\t/*\n\t\t\t * Don't advertise extended performance counter MSRs\n\t\t\t * to the guest.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) AMDID2_PCXC);\n\t\t\tregs[2] &= ~((unsigned) AMDID2_PNXC);\n\t\t\tregs[2] &= ~((unsigned) AMDID2_PTSCEL2I);\n\n\t\t\t/*\n\t\t\t * Don't advertise Instruction Based Sampling feature.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) AMDID2_IBS);\n\n\t\t\t/* NodeID MSR not available */\n\t\t\tregs[2] &= ~((unsigned) AMDID2_NODE_ID);\n\n\t\t\t/* Don't advertise the OS visible workaround feature */\n\t\t\tregs[2] &= ~((unsigned) AMDID2_OSVW);\n\n\t\t\t/*\n\t\t\t * Hide rdtscp/ia32_tsc_aux until we know how\n\t\t\t * to deal with them.\n\t\t\t */\n\t\t\tregs[3] &= ~((unsigned) AMDID_RDTSCP);\n\t\t\tbreak;\n\n\t\tcase CPUID_8000_0007:\n\t\t\t/*\n\t\t\t * AMD uses this leaf to advertise the processor's\n\t\t\t * power monitoring and RAS capabilities. These\n\t\t\t * features are hardware-specific and exposing\n\t\t\t * them to a guest doesn't make a lot of sense.\n\t\t\t *\n\t\t\t * Intel uses this leaf only to advertise the\n\t\t\t * \"Invariant TSC\" feature with all other bits\n\t\t\t * being reserved (set to zero).\n\t\t\t */\n\t\t\tregs[0] = 0;\n\t\t\tregs[1] = 0;\n\t\t\tregs[2] = 0;\n\t\t\tregs[3] = 0;\n\n\t\t\t/*\n\t\t\t * \"Invariant TSC\" can be advertised to the guest if:\n\t\t\t * - host TSC frequency is invariant\n\t\t\t * - host TSCs are synchronized across physical cpus\n\t\t\t *\n\t\t\t * XXX This still falls short because the vcpu\n\t\t\t * can observe the TSC moving backwards as it\n\t\t\t * migrates across physical cpus. But at least\n\t\t\t * it should discourage the guest from using the\n\t\t\t * TSC to keep track of time.\n\t\t\t */\n\t\t\tif (tsc_is_invariant && smp_tsc)\n\t\t\t\tregs[3] |= AMDPM_TSC_INVARIANT;\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_0001:\n\t\t\tdo_cpuid(1, regs);\n\n\t\t\terror = vm_get_x2apic_state(vm, vcpu_id, &x2apic_state);\n\t\t\tif (error) {\n\t\t\t\txhyve_abort(\"x86_emulate_cpuid: error %d \"\n\t\t\t\t\t\"fetching x2apic state\\n\", error);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Override the APIC ID only in ebx\n\t\t\t */\n\t\t\tregs[1] &= ~((unsigned) CPUID_LOCAL_APIC_ID);\n\t\t\tregs[1] |= (((unsigned) vcpu_id) << CPUID_0000_0001_APICID_SHIFT);\n\n\t\t\t/*\n\t\t\t * Don't expose VMX, SpeedStep, TME or SMX capability.\n\t\t\t * Advertise x2APIC capability and Hypervisor guest.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) (CPUID2_VMX | CPUID2_EST | CPUID2_TM2));\n\t\t\tregs[2] &= ~((unsigned) CPUID2_SMX);\n\n\t\t\tregs[2] |= (unsigned) CPUID2_HV;\n\n\t\t\tif (x2apic_state != ((unsigned) X2APIC_DISABLED))\n\t\t\t\tregs[2] |= ((unsigned) CPUID2_X2APIC);\n\t\t\telse\n\t\t\t\tregs[2] &= ~((unsigned) CPUID2_X2APIC);\n\n\t\t\t/*\n\t\t\t * Only advertise CPUID2_XSAVE in the guest if\n\t\t\t * the host is using XSAVE.\n\t\t\t */\n\t\t\tif (!(regs[2] & ((unsigned) CPUID2_OSXSAVE)))\n\t\t\t\tregs[2] &= ~((unsigned) CPUID2_XSAVE);\n\n\t\t\t/*\n\t\t\t * If CPUID2_XSAVE is being advertised and the\n\t\t\t * guest has set CR4_XSAVE, set\n\t\t\t * CPUID2_OSXSAVE.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) CPUID2_OSXSAVE);\n\t\t\tif (regs[2] & ((unsigned) CPUID2_XSAVE)) {\n\t\t\t\terror = vm_get_register(vm, vcpu_id, VM_REG_GUEST_CR4, &cr4);\n\t\t\t\tif (error)\n\t\t\t\t\txhyve_abort(\"x86_emulate_cpuid: error %d \"\n\t\t\t\t\t      \"fetching %%cr4\\n\", error);\n\t\t\t\tif (cr4 & CR4_XSAVE)\n\t\t\t\t\tregs[2] |= ((unsigned) CPUID2_OSXSAVE);\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Hide monitor/mwait until we know how to deal with\n\t\t\t * these instructions.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) CPUID2_MON);\n\n                        /*\n\t\t\t * Hide the performance and debug features.\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) CPUID2_PDCM);\n\n\t\t\t/*\n\t\t\t * No TSC deadline support in the APIC yet\n\t\t\t */\n\t\t\tregs[2] &= ~((unsigned) CPUID2_TSCDLT);\n\n\t\t\t/*\n\t\t\t * Hide thermal monitoring\n\t\t\t */\n\t\t\tregs[3] &= ~((unsigned) (CPUID_ACPI | CPUID_TM));\n\n\t\t\t/*\n\t\t\t * Hide the debug store capability.\n\t\t\t */\n\t\t\tregs[3] &= ~((unsigned) CPUID_DS);\n\n\t\t\t/*\n\t\t\t * Advertise the Machine Check and MTRR capability.\n\t\t\t *\n\t\t\t * Some guest OSes (e.g. Windows) will not boot if\n\t\t\t * these features are absent.\n\t\t\t */\n\t\t\tregs[3] |= (unsigned) (CPUID_MCA | CPUID_MCE | CPUID_MTRR);\n\n\t\t\tlogical_cpus = threads_per_core * cores_per_package;\n\t\t\tregs[1] &= ~((unsigned) CPUID_HTT_CORES);\n\t\t\tregs[1] |= (logical_cpus & 0xff) << 16;\n\t\t\tregs[3] |= (unsigned) CPUID_HTT;\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_0004:\n\t\t\tcpuid_count(*eax, *ecx, regs);\n\n\t\t\tif (regs[0] || regs[1] || regs[2] || regs[3]) {\n\t\t\t\tregs[0] &= 0x3ff;\n\t\t\t\tregs[0] |= (cores_per_package - 1) << 26;\n\t\t\t\t/*\n\t\t\t\t * Cache topology:\n\t\t\t\t * - L1 and L2 are shared only by the logical\n\t\t\t\t *   processors in a single core.\n\t\t\t\t * - L3 and above are shared by all logical\n\t\t\t\t *   processors in the package.\n\t\t\t\t */\n\t\t\t\tlogical_cpus = threads_per_core;\n\t\t\t\tlevel = (regs[0] >> 5) & 0x7;\n\t\t\t\tif (level >= 3)\n\t\t\t\t\tlogical_cpus *= cores_per_package;\n\t\t\t\tregs[0] |= (logical_cpus - 1) << 14;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_0007:\n\t\t\tregs[0] = 0;\n\t\t\tregs[1] = 0;\n\t\t\tregs[2] = 0;\n\t\t\tregs[3] = 0;\n\n\t\t\t/* leaf 0 */\n\t\t\tif (*ecx == 0) {\n\t\t\t\tcpuid_count(*eax, *ecx, regs);\n\n\t\t\t\t/* Only leaf 0 is supported */\n\t\t\t\tregs[0] = 0;\n\n\t\t\t\t/*\n\t\t\t\t * Expose known-safe features.\n\t\t\t\t */\n\t\t\t\tregs[1] &= (CPUID_STDEXT_FSGSBASE |\n\t\t\t\t    CPUID_STDEXT_BMI1 | CPUID_STDEXT_HLE |\n\t\t\t\t    CPUID_STDEXT_AVX2 | CPUID_STDEXT_BMI2 |\n\t\t\t\t    CPUID_STDEXT_ERMS | CPUID_STDEXT_RTM |\n\t\t\t\t    CPUID_STDEXT_AVX512F |\n\t\t\t\t    CPUID_STDEXT_AVX512PF |\n\t\t\t\t    CPUID_STDEXT_AVX512ER |\n\t\t\t\t    CPUID_STDEXT_AVX512CD);\n\t\t\t\tregs[2] = 0;\n\t\t\t\tregs[3] = 0;\n\t\t\t\t/* FIXME */\n\t\t\t\t// regs[1] |= CPUID_STDEXT_INVPCID;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_0006:\n\t\t\tregs[0] = CPUTPM1_ARAT;\n\t\t\tregs[1] = 0;\n\t\t\tregs[2] = 0;\n\t\t\tregs[3] = 0;\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_000A:\n\t\t\t/*\n\t\t\t * Handle the access, but report 0 for\n\t\t\t * all options\n\t\t\t */\n\t\t\tregs[0] = 0;\n\t\t\tregs[1] = 0;\n\t\t\tregs[2] = 0;\n\t\t\tregs[3] = 0;\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_000B:\n\t\t\t/*\n\t\t\t * Processor topology enumeration\n\t\t\t */\n\t\t\tlogical_cpus = 0;\n\t\t\twidth = 0;\n\t\t\tlevel = 0;\n\t\t\tx2apic_id = 0;\n\n\t\t\tif (*ecx == 0) {\n\t\t\t\tlogical_cpus = threads_per_core;\n\t\t\t\twidth = log2(logical_cpus);\n\t\t\t\tlevel = CPUID_TYPE_SMT;\n\t\t\t\tx2apic_id = vcpu_id;\n\t\t\t}\n\n\t\t\tif (*ecx == 1) {\n\t\t\t\tlogical_cpus = threads_per_core *\n\t\t\t\t    cores_per_package;\n\t\t\t\twidth = log2(logical_cpus);\n\t\t\t\tlevel = CPUID_TYPE_CORE;\n\t\t\t\tx2apic_id = vcpu_id;\n\t\t\t}\n\n\t\t\tif (!cpuid_leaf_b || *ecx >= 2) {\n\t\t\t\twidth = 0;\n\t\t\t\tlogical_cpus = 0;\n\t\t\t\tlevel = 0;\n\t\t\t\tx2apic_id = 0;\n\t\t\t}\n\n\t\t\tregs[0] = width & 0x1f;\n\t\t\tregs[1] = logical_cpus & 0xffff;\n\t\t\tregs[2] = (((unsigned) level) << 8) | (*ecx & 0xff);\n\t\t\tregs[3] = (unsigned) x2apic_id;\n\t\t\tbreak;\n\n\t\tcase CPUID_0000_000D:\n\t\t\tlimits = vmm_get_xsave_limits();\n\t\t\tif (!limits->xsave_enabled) {\n\t\t\t\tregs[0] = 0;\n\t\t\t\tregs[1] = 0;\n\t\t\t\tregs[2] = 0;\n\t\t\t\tregs[3] = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcpuid_count(*eax, *ecx, regs);\n\t\t\tswitch (*ecx) {\n\t\t\tcase 0:\n\t\t\t\t/*\n\t\t\t\t * Only permit the guest to use bits\n\t\t\t\t * that are active in the host in\n\t\t\t\t * %xcr0.  Also, claim that the\n\t\t\t\t * maximum save area size is\n\t\t\t\t * equivalent to the host's current\n\t\t\t\t * save area size.  Since this runs\n\t\t\t\t * \"inside\" of vmrun(), it runs with\n\t\t\t\t * the guest's xcr0, so the current\n\t\t\t\t * save area size is correct as-is.\n\t\t\t\t */\n\t\t\t\tregs[0] &= limits->xcr0_allowed;\n\t\t\t\tregs[2] = limits->xsave_max_size;\n\t\t\t\tregs[3] &= (limits->xcr0_allowed >> 32);\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\t/* Only permit XSAVEOPT. */\n\t\t\t\tregs[0] &= CPUID_EXTSTATE_XSAVEOPT;\n\t\t\t\tregs[1] = 0;\n\t\t\t\tregs[2] = 0;\n\t\t\t\tregs[3] = 0;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t/*\n\t\t\t\t * If the leaf is for a permitted feature,\n\t\t\t\t * pass through as-is, otherwise return\n\t\t\t\t * all zeroes.\n\t\t\t\t */\n\t\t\t\tif (!(limits->xcr0_allowed & (1ul << *ecx))) {\n\t\t\t\t\tregs[0] = 0;\n\t\t\t\t\tregs[1] = 0;\n\t\t\t\t\tregs[2] = 0;\n\t\t\t\t\tregs[3] = 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 0x40000000:\n\t\t\tregs[0] = CPUID_VM_HIGH;\n\t\t\tbcopy(bhyve_id, &regs[1], 4);\n\t\t\tbcopy(bhyve_id + 4, &regs[2], 4);\n\t\t\tbcopy(bhyve_id + 8, &regs[3], 4);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t/*\n\t\t\t * The leaf value has already been clamped so\n\t\t\t * simply pass this through, keeping count of\n\t\t\t * how many unhandled leaf values have been seen.\n\t\t\t */\n\t\t\tatomic_add_long(&bhyve_xcpuids, 1);\n\t\t\tcpuid_count(*eax, *ecx, regs);\n\t\t\tbreak;\n\t}\n\n\t*eax = regs[0];\n\t*ebx = regs[1];\n\t*ecx = regs[2];\n\t*edx = regs[3];\n\n\treturn (1);\n}\n"
  },
  {
    "path": "src/xhyve-Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>English</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "src/xhyve-entitlements.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.security.network.client</key>\n    <true/>\n    <key>com.apple.security.network.server</key>\n    <true/>\n    <key>com.apple.security.hypervisor</key>\n    <true/>\n    <key>com.apple.vm.networking</key>\n    <true/>\n    <key>com.apple.vm.hypervisor</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "src/xhyve.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <err.h>\n#include <fcntl.h>\n#include <libgen.h>\n#include <unistd.h>\n#include <assert.h>\n#include <errno.h>\n#include <pthread.h>\n#include <sysexits.h>\n#include <ctype.h>\n#include <inttypes.h>\n#include <sys/types.h>\n#include <sys/mman.h>\n#include <sys/time.h>\n#include <sys/param.h>\n\n#include <xhyve/support/misc.h>\n#include <xhyve/support/atomic.h>\n#include <xhyve/support/segments.h>\n#include <xhyve/support/cpuset.h>\n#include <xhyve/vmm/vmm_api.h>\n\n#include <xhyve/xhyve.h>\n#include <xhyve/acpi.h>\n#include <xhyve/atkbdc.h>\n#include <xhyve/inout.h>\n#include <xhyve/dbgport.h>\n#include <xhyve/ioapic.h>\n#include <xhyve/mem.h>\n#include <xhyve/mevent.h>\n#include <xhyve/mptbl.h>\n#include <xhyve/pci_emul.h>\n#include <xhyve/pci_irq.h>\n#include <xhyve/pci_lpc.h>\n#include <xhyve/smbiostbl.h>\n#include <xhyve/xmsr.h>\n#include <xhyve/rtc.h>\n\n#include <xhyve/firmware/kexec.h>\n#include <xhyve/firmware/fbsd.h>\n\n#define GUEST_NIO_PORT 0x488 /* guest upcalls via i/o port */\n\n#define MB (1024UL * 1024)\n\ntypedef int (*vmexit_handler_t)(struct vm_exit *, int *vcpu);\nextern int vmexit_task_switch(struct vm_exit *, int *vcpu);\n\nchar *vmname = \"vm\";\n\nint guest_ncpus;\nint print_mac;\nchar *guest_uuid_str;\nstatic char *pidfile;\n\nstatic int guest_vmexit_on_hlt, guest_vmexit_on_pause;\nstatic int virtio_msix = 1;\nstatic int x2apic_mode = 0;\t/* default is xAPIC */\n\nstatic int strictio;\nstatic int strictmsr = 1;\n\nstatic int acpi;\n\nstatic char *progname;\nstatic const int BSP = 0;\n\nstatic cpuset_t cpumask;\n\nstatic void vcpu_loop(int vcpu, uint64_t rip);\n\nstatic struct vm_exit vmexit[VM_MAXCPU];\n\nstatic struct bhyvestats {\n\tuint64_t vmexit_bogus;\n\tuint64_t vmexit_bogus_switch;\n\tuint64_t vmexit_hlt;\n\tuint64_t vmexit_pause;\n\tuint64_t vmexit_mtrap;\n\tuint64_t vmexit_inst_emul;\n\tuint64_t cpu_switch_rotate;\n\tuint64_t cpu_switch_direct;\n} stats;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wpadded\"\nstatic struct mt_vmm_info {\n\tpthread_t mt_thr;\n\tint mt_vcpu;\n} mt_vmm_info[VM_MAXCPU];\n#pragma clang diagnostic pop\n\nstatic uint64_t (*fw_func)(void);\n\n__attribute__ ((noreturn)) static void\nusage(int code)\n{\n\n        fprintf(stderr,\n                \"Usage: %s [-behuwxMACHPWY] [-c vcpus] [-F <pidfile>] [-g <gdb port>] [-l <lpc>]\\n\"\n\t\t\"       %*s [-m mem] [-p vcpu:hostcpu] [-s <pci>] [-U uuid] -f <fw>\\n\"\n\t\t\"       -A: create ACPI tables\\n\"\n\t\t\"       -c: # cpus (default 1)\\n\"\n\t\t\"       -C: include guest memory in core file\\n\"\n\t\t\"       -e: exit on unhandled I/O access\\n\"\n\t\t\"       -f: firmware\\n\"\n\t\t\"       -F: pidfile\\n\"\n\t\t\"       -g: gdb port\\n\"\n\t\t\"       -h: help\\n\"\n\t\t\"       -H: vmexit from the guest on hlt\\n\"\n\t\t\"       -l: LPC device configuration. Ex: -l com1,stdio -l com2,autopty -l com2,/dev/myownpty\\n\"\n\t\t\"       -m: memory size in MB, may be suffixed with one of K, M, G or T\\n\"\n\t\t\"       -M: print MAC address and exit if using vmnet\\n\"\n\t\t\"       -p: pin 'vcpu' to 'hostcpu'\\n\"\n\t\t\"       -P: vmexit from the guest on pause\\n\"\n\t\t\"       -s: <slot,driver,configinfo> PCI slot config\\n\"\n\t\t\"       -u: RTC keeps UTC time\\n\"\n\t\t\"       -U: uuid\\n\"\n\t\t\"       -v: show build version\\n\"\n\t\t\"       -w: ignore unimplemented MSRs\\n\"\n\t\t\"       -W: force virtio to use single-vector MSI\\n\"\n\t\t\"       -x: local apic is in x2APIC mode\\n\"\n\t\t\"       -Y: disable MPtable generation\\n\",\n\t\tprogname, (int)strlen(progname), \"\");\n\n\texit(code);\n}\n\n__attribute__ ((noreturn)) static void\nshow_version()\n{\n        fprintf(stderr, \"%s: %s\\n\\n%s\\n\",progname, VERSION,\n\t\t\"xhyve is a port of FreeBSD's bhyve hypervisor to OS X that\\n\"\n\t\t\"works entirely in userspace and has no other dependencies.\\n\\n\"\n\t\t\"Homepage: http://www.xhyve.xyz\\n\"\n\t\t\"License: BSD\\n\");\n\t\texit(0);\n}\n\nvoid\nxh_vm_inject_fault(int vcpu, int vector, int errcode_valid,\n    uint32_t errcode)\n{\n\tint error, restart_instruction;\n\n\trestart_instruction = 1;\n\n\terror = xh_vm_inject_exception(vcpu, vector, errcode_valid, errcode,\n\t    restart_instruction);\n\tassert(error == 0);\n}\n\nvoid *\npaddr_guest2host(uintptr_t gaddr, size_t len)\n{\n\treturn (xh_vm_map_gpa(gaddr, len));\n}\n\nint\nfbsdrun_vmexit_on_pause(void)\n{\n\treturn (guest_vmexit_on_pause);\n}\n\nint\nfbsdrun_vmexit_on_hlt(void)\n{\n\treturn (guest_vmexit_on_hlt);\n}\n\nint\nfbsdrun_virtio_msix(void)\n{\n\treturn (virtio_msix);\n}\n\nstatic void\nspinup_ap_realmode(int newcpu, uint64_t *rip)\n{\n\tint vector, error;\n\tuint16_t cs;\n\tuint64_t desc_base;\n\tuint32_t desc_limit, desc_access;\n\n\tvector = (int) (*rip >> XHYVE_PAGE_SHIFT);\n\t*rip = 0;\n\n\t/*\n\t * Update the %cs and %rip of the guest so that it starts\n\t * executing real mode code at at 'vector << 12'.\n\t */\n\terror = xh_vm_set_register(newcpu, VM_REG_GUEST_RIP, *rip);\n\tassert(error == 0);\n\n\terror = xh_vm_get_desc(newcpu, VM_REG_GUEST_CS, &desc_base, &desc_limit,\n\t\t&desc_access);\n\tassert(error == 0);\n\n\tdesc_base = (uint64_t) (vector << XHYVE_PAGE_SHIFT);\n\terror = xh_vm_set_desc(newcpu, VM_REG_GUEST_CS, desc_base, desc_limit,\n\t\tdesc_access);\n\tassert(error == 0);\n\n\tcs = (uint16_t) ((vector << XHYVE_PAGE_SHIFT) >> 4);\n\terror = xh_vm_set_register(newcpu, VM_REG_GUEST_CS, cs);\n\tassert(error == 0);\n}\n\nstatic void *\nvcpu_thread(void *param)\n{\n\tstruct mt_vmm_info *mtp;\n\tuint64_t rip_entry;\n\tint vcpu;\n\tint error;\n\n\tmtp = param;\n\tvcpu = mtp->mt_vcpu;\n\trip_entry = 0xfff0;\n\n\terror = xh_vcpu_create(vcpu);\n\tassert(error == 0);\n\n\tvcpu_set_capabilities(vcpu);\n\n\terror = xh_vcpu_reset(vcpu);\n\tassert(error == 0);\n\n\tif (vcpu == BSP) {\n        if (fw_func != NULL) {\n            rip_entry = fw_func();\n        } else {\n            rip_entry = 0xFFF0;\n        }\n\t} else {\n\t\trip_entry = vmexit[vcpu].rip;\n\t\tspinup_ap_realmode(vcpu, &rip_entry);\n\t}\n\n\tvmexit[vcpu].rip = rip_entry;\n\tvmexit[vcpu].inst_length = 0;\n\n\tvcpu_loop(vcpu, vmexit[vcpu].rip);\n\n\t/* not reached */\n\texit(1);\n\treturn (NULL);\n}\n\nvoid\nvcpu_add(int fromcpu, int newcpu, uint64_t rip)\n{\n\tint error;\n\n\tassert(fromcpu == BSP);\n\n\t/*\n\t * The 'newcpu' must be activated in the context of 'fromcpu'. If\n\t * vm_activate_cpu() is delayed until newcpu's pthread starts running\n\t * then vmm.ko is out-of-sync with bhyve and this can create a race\n\t * with vm_suspend().\n\t */\n\terror = xh_vm_activate_cpu(newcpu);\n\tassert(error == 0);\n\n\tCPU_SET_ATOMIC(((unsigned) newcpu), &cpumask);\n\n\tmt_vmm_info[newcpu].mt_vcpu = newcpu;\n\n\tvmexit[newcpu].rip = rip;\n\n\terror = pthread_create(&mt_vmm_info[newcpu].mt_thr, NULL, vcpu_thread,\n\t\t&mt_vmm_info[newcpu]);\n\n\tassert(error == 0);\n}\n\nstatic int\nvcpu_delete(int vcpu)\n{\n\tif (!CPU_ISSET(((unsigned) vcpu), &cpumask)) {\n\t\tfprintf(stderr, \"Attempting to delete unknown cpu %d\\n\", vcpu);\n\t\texit(1);\n\t}\n\n\tCPU_CLR_ATOMIC(((unsigned) vcpu), &cpumask);\n\treturn (CPU_EMPTY(&cpumask));\n}\n\nstatic int\nvmexit_handle_notify(UNUSED struct vm_exit *vme, UNUSED int *pvcpu,\n\tUNUSED uint32_t eax)\n{\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_inout(struct vm_exit *vme, int *pvcpu)\n{\n\tint error;\n\tint bytes, port, in, out, string;\n\tint vcpu;\n\n\tvcpu = *pvcpu;\n\n\tport = vme->u.inout.port;\n\tbytes = vme->u.inout.bytes;\n\tstring = vme->u.inout.string;\n\tin = vme->u.inout.in;\n\tout = !in;\n\n\t/* Extra-special case of host notifications */\n\tif (out && port == GUEST_NIO_PORT) {\n\t\terror = vmexit_handle_notify(vme, pvcpu, vme->u.inout.eax);\n\t\treturn (error);\n\t}\n\n\terror = emulate_inout(vcpu, vme, strictio);\n\tif (error) {\n\t\tfprintf(stderr, \"Unhandled %s%c 0x%04x at 0x%llx\\n\",\n\t\t\tin ? \"in\" : \"out\",\n\t\t\tbytes == 1 ? 'b' : (bytes == 2 ? 'w' : 'l'),\n\t\t\tport, vmexit->rip);\n\t\treturn (VMEXIT_ABORT);\n\t} else {\n\t\treturn (VMEXIT_CONTINUE);\n\t}\n}\n\nstatic int\nvmexit_rdmsr(struct vm_exit *vme, int *pvcpu)\n{\n\tuint64_t val;\n\tuint32_t eax, edx;\n\tint error;\n\n\tval = 0;\n\terror = emulate_rdmsr(*pvcpu, vme->u.msr.code, &val);\n\tif (error != 0) {\n\t\tfprintf(stderr, \"rdmsr to register %#x on vcpu %d\\n\",\n\t\t    vme->u.msr.code, *pvcpu);\n\t\tif (strictmsr) {\n\t\t\tvm_inject_gp(*pvcpu);\n\t\t\treturn (VMEXIT_CONTINUE);\n\t\t}\n\t}\n\n\teax = (uint32_t) val;\n\terror = xh_vm_set_register(*pvcpu, VM_REG_GUEST_RAX, eax);\n\tassert(error == 0);\n\n\tedx = val >> 32;\n\terror = xh_vm_set_register(*pvcpu, VM_REG_GUEST_RDX, edx);\n\tassert(error == 0);\n\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_wrmsr(struct vm_exit *vme, int *pvcpu)\n{\n\tint error;\n\n\terror = emulate_wrmsr(*pvcpu, vme->u.msr.code, vme->u.msr.wval);\n\tif (error != 0) {\n\t\tfprintf(stderr, \"wrmsr to register %#x(%#llx) on vcpu %d\\n\",\n\t\t    vme->u.msr.code, vme->u.msr.wval, *pvcpu);\n\t\tif (strictmsr) {\n\t\t\tvm_inject_gp(*pvcpu);\n\t\t\treturn (VMEXIT_CONTINUE);\n\t\t}\n\t}\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_spinup_ap(struct vm_exit *vme, int *pvcpu)\n{\n\tassert(vme->u.spinup_ap.vcpu != 0);\n\tassert(vme->u.spinup_ap.vcpu < guest_ncpus);\n\n\tvcpu_add(*pvcpu, vme->u.spinup_ap.vcpu, vme->u.spinup_ap.rip);\n\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_vmx(struct vm_exit *vme, int *pvcpu)\n{\n\tfprintf(stderr, \"vm exit[%d]\\n\", *pvcpu);\n\tfprintf(stderr, \"\\treason\\t\\tVMX\\n\");\n\tfprintf(stderr, \"\\trip\\t\\t0x%016llx\\n\", vme->rip);\n\tfprintf(stderr, \"\\tinst_length\\t%d\\n\", vme->inst_length);\n\tfprintf(stderr, \"\\tstatus\\t\\t%d\\n\", vme->u.vmx.status);\n\tfprintf(stderr, \"\\texit_reason\\t%u\\n\", vme->u.vmx.exit_reason);\n\tfprintf(stderr, \"\\tqualification\\t0x%016llx\\n\",\n\t    vme->u.vmx.exit_qualification);\n\tfprintf(stderr, \"\\tinst_type\\t\\t%d\\n\", vme->u.vmx.inst_type);\n\tfprintf(stderr, \"\\tinst_error\\t\\t%d\\n\", vme->u.vmx.inst_error);\n\treturn (VMEXIT_ABORT);\n}\n\nstatic int\nvmexit_bogus(struct vm_exit *vme, UNUSED int *pvcpu)\n{\n\tassert(vme->inst_length == 0);\n\n\tstats.vmexit_bogus++;\n\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_hlt(UNUSED struct vm_exit *vme, UNUSED int *pvcpu)\n{\n\tstats.vmexit_hlt++;\n\n\t/*\n\t * Just continue execution with the next instruction. We use\n\t * the HLT VM exit as a way to be friendly with the host\n\t * scheduler.\n\t */\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_pause(UNUSED struct vm_exit *vme, UNUSED int *pvcpu)\n{\n\tstats.vmexit_pause++;\n\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_mtrap(struct vm_exit *vme, UNUSED int *pvcpu)\n{\n\tassert(vme->inst_length == 0);\n\n\tstats.vmexit_mtrap++;\n\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic int\nvmexit_inst_emul(struct vm_exit *vme, int *pvcpu)\n{\n\tint err, i;\n\tstruct vie *vie;\n\n\tstats.vmexit_inst_emul++;\n\n\tvie = &vme->u.inst_emul.vie;\n\terr = emulate_mem(*pvcpu, vme->u.inst_emul.gpa, vie,\n\t\t&vme->u.inst_emul.paging);\n\n\tif (err) {\n\t\tif (err == ESRCH) {\n\t\t\tfprintf(stderr, \"Unhandled memory access to 0x%llx\\n\",\n\t\t\t    vme->u.inst_emul.gpa);\n\t\t}\n\n\t\tfprintf(stderr, \"Failed to emulate instruction [\");\n\t\tfor (i = 0; i < vie->num_valid; i++) {\n\t\t\tfprintf(stderr, \"0x%02x%s\", vie->inst[i],\n\t\t\t    i != (vie->num_valid - 1) ? \" \" : \"\");\n\t\t}\n\t\tfprintf(stderr, \"] at 0x%llx\\n\", vme->rip);\n\t\treturn (VMEXIT_ABORT);\n\t}\n\n\treturn (VMEXIT_CONTINUE);\n}\n\nstatic pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;\nstatic pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;\n\nstatic int\nvmexit_suspend(struct vm_exit *vme, int *pvcpu)\n{\n\tenum vm_suspend_how how;\n\n\thow = vme->u.suspended.how;\n\n\tvcpu_delete(*pvcpu);\n\n\tif (*pvcpu != BSP) {\n\t\tpthread_mutex_lock(&resetcpu_mtx);\n\t\tpthread_cond_signal(&resetcpu_cond);\n\t\tpthread_mutex_unlock(&resetcpu_mtx);\n\t\tpthread_exit(NULL);\n\t}\n\n\tpthread_mutex_lock(&resetcpu_mtx);\n\twhile (!CPU_EMPTY(&cpumask)) {\n\t\tpthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);\n\t}\n\tpthread_mutex_unlock(&resetcpu_mtx);\n\n\tswitch ((int) (how)) {\n\tcase VM_SUSPEND_RESET:\n\t\texit(0);\n\tcase VM_SUSPEND_POWEROFF:\n\t\texit(1);\n\tcase VM_SUSPEND_HALT:\n\t\texit(2);\n\tcase VM_SUSPEND_TRIPLEFAULT:\n\t\texit(3);\n\tdefault:\n\t\tfprintf(stderr, \"vmexit_suspend: invalid reason %d\\n\", how);\n\t\texit(100);\n\t}\n}\n\nstatic vmexit_handler_t handler[VM_EXITCODE_MAX] = {\n\t[VM_EXITCODE_INOUT] = vmexit_inout,\n\t[VM_EXITCODE_INOUT_STR] = vmexit_inout,\n\t[VM_EXITCODE_VMX] = vmexit_vmx,\n\t[VM_EXITCODE_BOGUS] = vmexit_bogus,\n\t[VM_EXITCODE_RDMSR] = vmexit_rdmsr,\n\t[VM_EXITCODE_WRMSR] = vmexit_wrmsr,\n\t[VM_EXITCODE_MTRAP] = vmexit_mtrap,\n\t[VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,\n\t[VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,\n\t[VM_EXITCODE_SUSPENDED] = vmexit_suspend,\n\t[VM_EXITCODE_TASK_SWITCH] = vmexit_task_switch,\n};\n\nvoid\nvcpu_set_capabilities(int cpu)\n{\n\tint err, tmp;\n\n\tif (fbsdrun_vmexit_on_hlt()) {\n\t\terr = xh_vm_get_capability(cpu, VM_CAP_HALT_EXIT, &tmp);\n\t\tif (err < 0) {\n\t\t\tfprintf(stderr, \"VM exit on HLT not supported\\n\");\n\t\t\texit(1);\n\t\t}\n\t\txh_vm_set_capability(cpu, VM_CAP_HALT_EXIT, 1);\n\t\tif (cpu == BSP)\n\t\t\thandler[VM_EXITCODE_HLT] = vmexit_hlt;\n\t}\n\n        if (fbsdrun_vmexit_on_pause()) {\n\t\t/*\n\t\t * pause exit support required for this mode\n\t\t */\n\t\terr = xh_vm_get_capability(cpu, VM_CAP_PAUSE_EXIT, &tmp);\n\t\tif (err < 0) {\n\t\t\tfprintf(stderr,\n\t\t\t    \"SMP mux requested, no pause support\\n\");\n\t\t\texit(1);\n\t\t}\n\t\txh_vm_set_capability(cpu, VM_CAP_PAUSE_EXIT, 1);\n\t\tif (cpu == BSP)\n\t\t\thandler[VM_EXITCODE_PAUSE] = vmexit_pause;\n        }\n\n\tif (x2apic_mode)\n\t\terr = xh_vm_set_x2apic_state(cpu, X2APIC_ENABLED);\n\telse\n\t\terr = xh_vm_set_x2apic_state(cpu, X2APIC_DISABLED);\n\n\tif (err) {\n\t\tfprintf(stderr, \"Unable to set x2apic state (%d)\\n\", err);\n\t\texit(1);\n\t}\n}\n\nstatic void\nvcpu_loop(int vcpu, uint64_t startrip)\n{\n\tint error, rc, prevcpu;\n\tenum vm_exitcode exitcode;\n\tcpuset_t active_cpus;\n\n\terror = xh_vm_active_cpus(&active_cpus);\n\tassert(CPU_ISSET(((unsigned) vcpu), &active_cpus));\n\n\terror = xh_vm_set_register(vcpu, VM_REG_GUEST_RIP, startrip);\n\tassert(error == 0);\n\n\twhile (1) {\n\t\terror = xh_vm_run(vcpu, &vmexit[vcpu]);\n\t\tif (error != 0)\n\t\t\tbreak;\n\n\t\tprevcpu = vcpu;\n\n\t\texitcode = vmexit[vcpu].exitcode;\n\t\tif (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) {\n\t\t\tfprintf(stderr, \"vcpu_loop: unexpected exitcode 0x%x\\n\",\n\t\t\t    exitcode);\n\t\t\texit(1);\n\t\t}\n\n                rc = (*handler[exitcode])(&vmexit[vcpu], &vcpu);\n\n\t\tswitch (rc) {\n\t\tcase VMEXIT_CONTINUE:\n\t\t\tbreak;\n\t\tcase VMEXIT_ABORT:\n\t\t\tabort();\n\t\tdefault:\n\t\t\texit(1);\n\t\t}\n\t}\n\tfprintf(stderr, \"vm_run error %d, errno %d\\n\", error, errno);\n}\n\nstatic int\nnum_vcpus_allowed(void)\n{\n\treturn (VM_MAXCPU);\n}\n\nstatic int\nexpand_number(const char *buf, uint64_t *num)\n{\n\tchar *endptr;\n\tuintmax_t umaxval;\n\tuint64_t number;\n\tunsigned shift;\n\tint serrno;\n\n\tserrno = errno;\n\terrno = 0;\n\tumaxval = strtoumax(buf, &endptr, 0);\n\tif (umaxval > UINT64_MAX)\n\t\terrno = ERANGE;\n\tif (errno != 0)\n\t\treturn (-1);\n\terrno = serrno;\n\tnumber = umaxval;\n\n\tswitch (tolower((unsigned char)*endptr)) {\n\tcase 'e':\n\t\tshift = 60;\n\t\tbreak;\n\tcase 'p':\n\t\tshift = 50;\n\t\tbreak;\n\tcase 't':\n\t\tshift = 40;\n\t\tbreak;\n\tcase 'g':\n\t\tshift = 30;\n\t\tbreak;\n\tcase 'm':\n\t\tshift = 20;\n\t\tbreak;\n\tcase 'k':\n\t\tshift = 10;\n\t\tbreak;\n\tcase 'b':\n\tcase '\\0': /* No unit. */\n\t\t*num = number;\n\t\treturn (0);\n\tdefault:\n\t\t/* Unrecognized unit. */\n\t\terrno = EINVAL;\n\t\treturn (-1);\n\t}\n\n\tif ((number << shift) >> shift != number) {\n\t\t/* Overflow */\n\t\terrno = ERANGE;\n\t\treturn (-1);\n\t}\n\t*num = number << shift;\n\treturn (0);\n}\n\nstatic int\nparse_memsize(const char *opt, size_t *ret_memsize)\n{\n\tchar *endptr;\n\tsize_t optval;\n\tint error;\n\n\toptval = strtoul(opt, &endptr, 0);\n\tif (*opt != '\\0' && *endptr == '\\0') {\n\t\t/*\n\t\t * For the sake of backward compatibility if the memory size\n\t\t * specified on the command line is less than a megabyte then\n\t\t * it is interpreted as being in units of MB.\n\t\t */\n\t\tif (optval < MB)\n\t\t\toptval *= MB;\n\t\t*ret_memsize = optval;\n\t\terror = 0;\n\t} else\n\t\terror = expand_number(opt, ((uint64_t *) ret_memsize));\n\n\treturn (error);\n}\n\nstatic int\nfirmware_parse(const char *opt) {\n\tchar *fw, *opt1, *opt2, *opt3, *cp;\n\n\tfw = strdup(opt);\n\n\tif (strncmp(fw, \"kexec\", strlen(\"kexec\")) == 0) {\n\t\tfw_func = kexec;\n\t} else if (strncmp(fw, \"fbsd\", strlen(\"fbsd\")) == 0) {\n\t\tfw_func = fbsd_load;\n\t} else {\n\t\tgoto fail;\n\t}\n\n\t\tif ((cp = strchr(fw, ',')) != NULL) {\n\t\t\t*cp = '\\0';\n\t\t\topt1 = cp + 1;\n\t\t} else {\n\t\t\tgoto fail;\n\t\t}\n\n\t\tif ((cp = strchr(opt1, ',')) != NULL) {\n\t\t\t*cp = '\\0';\n\t\t\topt2 = cp + 1;\n\t\t} else {\n\t\t\tgoto fail;\n\t\t}\n\n\t\tif ((cp = strchr(opt2, ',')) != NULL) {\n\t\t\t*cp = '\\0';\n\t\t\topt3 = cp + 1;\n\t\t} else {\n\t\t\tgoto fail;\n\t\t}\n\n\t\topt2 = strlen(opt2) ? opt2 : NULL;\n\t\topt3 = strlen(opt3) ? opt3 : NULL;\n\n\tif (fw_func == kexec) {\n\t\tkexec_init(opt1, opt2, opt3);\n\t} else if (fw_func == fbsd_load) {\n\t\t/* FIXME: let user set boot-loader serial device */\n\t\tfbsd_init(opt1, opt2, opt3, NULL);\n\t} else {\n\t\tgoto fail;\n\t}\n\n\treturn 0;\n\nfail:\n\tfprintf(stderr, \"Invalid firmware argument\\n\"\n\t\t\"    -f kexec,'kernel','initrd','\\\"cmdline\\\"'\\n\"\n\t\t\"    -f fbsd,'userboot','boot volume','\\\"kernel env\\\"'\\n\");\n\n\treturn -1;\n}\n\nstatic void\nremove_pidfile()\n{\n\tint error;\n\n\tif (pidfile == NULL)\n\t\treturn;\n\n\terror = unlink(pidfile);\n\tif (error < 0)\n\t\tfprintf(stderr, \"Failed to remove pidfile\\n\");\n}\n\nstatic int\nsetup_pidfile()\n{\n\tint f, error, pid;\n\tchar pid_str[21];\n\n\tif (pidfile == NULL)\n\t\treturn 0;\n\n\tpid = getpid();\n\n\terror = sprintf(pid_str, \"%d\", pid);\n\tif (error < 0)\n\t\tgoto fail;\n\n\tf = open(pidfile, O_CREAT|O_EXCL|O_WRONLY, 0644);\n\tif (f < 0)\n\t\tgoto fail;\n\n\terror = atexit(remove_pidfile);\n\tif (error < 0) {\n\t\tclose(f);\n\t\tremove_pidfile();\n\t\tgoto fail;\n\t}\n\n\tif (0 > (write(f, (void*)pid_str, strlen(pid_str)))) {\n\t\tclose(f);\n\t\tgoto fail;\n\t}\n\n\terror = close(f);\n\tif (error < 0)\n\t\tgoto fail;\n\n\treturn 0;\n\nfail:\n\tfprintf(stderr, \"Failed to set up pidfile\\n\");\n\treturn -1;\n}\n\nint\nmain(int argc, char *argv[])\n{\n\tint c, error, gdb_port, bvmcons, fw;\n\tint dump_guest_memory, max_vcpus, mptgen;\n\tint rtc_localtime;\n\tuint64_t rip;\n\tsize_t memsize;\n\n\tbvmcons = 0;\n\tdump_guest_memory = 0;\n\tprogname = basename(argv[0]);\n\tgdb_port = 0;\n\tguest_ncpus = 1;\n\tprint_mac = 0;\n\tmemsize = 256 * MB;\n\tmptgen = 1;\n\trtc_localtime = 1;\n\tfw = 0;\n\n\twhile ((c = getopt(argc, argv, \"behvuwxMACHPWY:f:F:g:c:s:m:l:U:\")) != -1) {\n\t\tswitch (c) {\n\t\tcase 'A':\n\t\t\tacpi = 1;\n\t\t\tbreak;\n\t\tcase 'b':\n\t\t\tbvmcons = 1;\n\t\t\tbreak;\n\t\tcase 'c':\n\t\t\tguest_ncpus = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'C':\n\t\t\tdump_guest_memory = 1;\n\t\t\tbreak;\n\t\tcase 'f':\n\t\t\tif (firmware_parse(optarg) != 0) {\n\t\t\t\texit (1);\n\t\t\t} else {\n\t\t\t\tfw = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase 'F':\n\t\t\tpidfile = optarg;\n\t\t\tbreak;\n\t\tcase 'g':\n\t\t\tgdb_port = atoi(optarg);\n\t\t\tbreak;\n\t\tcase 'l':\n\t\t\tif (lpc_device_parse(optarg) != 0) {\n\t\t\t\terrx(EX_USAGE, \"invalid lpc device \"\n\t\t\t\t    \"configuration '%s'\", optarg);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 's':\n\t\t\tif (pci_parse_slot(optarg) != 0)\n\t\t\t\texit(1);\n\t\t\telse\n\t\t\t\tbreak;\n\t\tcase 'm':\n\t\t\terror = parse_memsize(optarg, &memsize);\n\t\t\tif (error)\n\t\t\t\terrx(EX_USAGE, \"invalid memsize '%s'\", optarg);\n\t\t\tbreak;\n\t\tcase 'M':\n\t\t\tprint_mac = 1;\n\t\t\tbreak;\n\t\tcase 'H':\n\t\t\tguest_vmexit_on_hlt = 1;\n\t\t\tbreak;\n\t\tcase 'P':\n\t\t\tguest_vmexit_on_pause = 1;\n\t\t\tbreak;\n\t\tcase 'e':\n\t\t\tstrictio = 1;\n\t\t\tbreak;\n\t\tcase 'u':\n\t\t\trtc_localtime = 0;\n\t\t\tbreak;\n\t\tcase 'U':\n\t\t\tguest_uuid_str = optarg;\n\t\t\tbreak;\n\t\tcase 'w':\n\t\t\tstrictmsr = 0;\n\t\t\tbreak;\n\t\tcase 'W':\n\t\t\tvirtio_msix = 0;\n\t\t\tbreak;\n\t\tcase 'x':\n\t\t\tx2apic_mode = 1;\n\t\t\tbreak;\n\t\tcase 'Y':\n\t\t\tmptgen = 0;\n\t\t\tbreak;\n\t\tcase 'v':\n\t\t\tshow_version();\n\t\tcase 'h':\n\t\t\tusage(0);\n\t\tdefault:\n\t\t\tusage(1);\n\t\t}\n\t}\n\n\tif ((fw != 1) && (lpc_bootrom() == NULL))\n\t\tusage(1);\n\n\terror = xh_vm_create();\n\tif (error) {\n\t\tfprintf(stderr, \"Unable to create VM (%d)\\n\", error);\n\t\texit(1);\n\t}\n\n\tif (guest_ncpus < 1) {\n\t\tfprintf(stderr, \"Invalid guest vCPUs (%d)\\n\", guest_ncpus);\n\t\texit(1);\n\t}\n\n\tmax_vcpus = num_vcpus_allowed();\n\tif (guest_ncpus > max_vcpus) {\n\t\tfprintf(stderr, \"%d vCPUs requested but only %d available\\n\",\n\t\t\tguest_ncpus, max_vcpus);\n\t\texit(1);\n\t}\n\n\terror = xh_vm_setup_memory(memsize, VM_MMAP_ALL);\n\tif (error) {\n\t\tfprintf(stderr, \"Unable to setup memory (%d)\\n\", error);\n\t\texit(1);\n\t}\n\n\terror = init_msr();\n\tif (error) {\n\t\tfprintf(stderr, \"init_msr error %d\\n\", error);\n\t\texit(1);\n\t}\n\n\terror = setup_pidfile();\n\tif (error) {\n\t\tfprintf(stderr, \"pidfile error %d\\n\", error);\n\t\texit(1);\n\t}\n\n\tinit_mem();\n\tinit_inout();\n    atkbdc_init();\n\tpci_irq_init();\n\tioapic_init();\n\n\trtc_init(rtc_localtime);\n\tsci_init();\n\n\t/*\n\t * Exit if a device emulation finds an error in it's initilization\n\t */\n\tif (init_pci() != 0)\n\t\texit(1);\n\n\tif (gdb_port != 0)\n\t\tinit_dbgport(gdb_port);\n\n\tif (bvmcons)\n\t\tinit_bvmcons();\n\n\t/*\n\t * build the guest tables, MP etc.\n\t */\n\tif (mptgen) {\n\t\terror = mptable_build(guest_ncpus);\n\t\tif (error)\n\t\t\texit(1);\n\t}\n\n\terror = smbios_build();\n\tassert(error == 0);\n\n\tif (acpi) {\n\t\terror = acpi_build(guest_ncpus);\n\t\tassert(error == 0);\n\t}\n\n\trip = 0;\n\n\tvcpu_add(BSP, BSP, rip);\n\n\t/*\n\t * Head off to the main event dispatch loop\n\t */\n\tmevent_dispatch();\n\n\texit(1);\n}\n"
  },
  {
    "path": "src/xmsr.c",
    "content": "/*-\n * Copyright (c) 2011 NetApp, Inc.\n * Copyright (c) 2015 xhyve developers\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n * $FreeBSD$\n */\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <xhyve/support/misc.h>\n#include <xhyve/support/specialreg.h>\n#include <xhyve/vmm/vmm_api.h>\n#include <xhyve/xhyve.h>\n#include <xhyve/xmsr.h>\n\nint\nemulate_wrmsr(UNUSED int vcpu, uint32_t num, UNUSED uint64_t val)\n{\n\tswitch (num) {\n\tcase 0xd04: /* Sandy Bridge uncore PMCs */\n\tcase 0xc24:\n\t\treturn (0);\n\tcase MSR_BIOS_UPDT_TRIG:\n\t\treturn (0);\n\tcase MSR_BIOS_SIGN:\n\t\treturn (0);\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn (-1);\n}\n\nint\nemulate_rdmsr(UNUSED int vcpu, uint32_t num, uint64_t *val)\n{\n\tint error = 0;\n\n\tswitch (num) {\n\tcase MSR_BIOS_SIGN:\n\tcase MSR_IA32_PLATFORM_ID:\n\tcase MSR_PKG_ENERGY_STATUS:\n\tcase MSR_PP0_ENERGY_STATUS:\n\tcase MSR_PP1_ENERGY_STATUS:\n\tcase MSR_DRAM_ENERGY_STATUS:\n\t\t*val = 0;\n\t\tbreak;\n\tcase MSR_RAPL_POWER_UNIT:\n\t\t/*\n\t\t * Use the default value documented in section\n\t\t * \"RAPL Interfaces\" in Intel SDM vol3.\n\t\t */\n\t\t*val = 0x000a1003;\n\t\tbreak;\n\tdefault:\n\t\terror = -1;\n\t\tbreak;\n\t}\n\n\treturn (error);\n}\n\nint\ninit_msr(void)\n{\n\tu_int regs[4];\n\tu_int cpu_vendor[4];\n\n\tdo_cpuid(0, regs);\n\tcpu_vendor[0] = regs[1];\n\tcpu_vendor[1] = regs[3];\n\tcpu_vendor[2] = regs[2];\n\tcpu_vendor[3] = 0;\n\n\tif (strcmp(((char *) cpu_vendor), \"GenuineIntel\") == 0) {\n\t\treturn 0;\n\t} else {\n\t\tfprintf(stderr, \"Unknown cpu vendor \\\"%s\\\"\\n\", ((char *) cpu_vendor));\n\t\treturn (-1);\n\t}\n}\n"
  },
  {
    "path": "test/tinycore.txt",
    "content": "These are binaries from\n    http://tinycorelinux.net\nwith the following patch applied:\n\nmkdir initrd\n( cd initrd ; zcat ../initrd.gz | sudo cpio -idm )\nsudo sed -i '/^# ttyS0$/s#^..##' initrd/etc/securetty \nsudo sed -i '/^tty1:/s#tty1#ttyS0#g' initrd/etc/inittab\n( cd initrd ; find | sudo cpio -o -H newc ) | gzip -c > initrd.gz\n"
  },
  {
    "path": "test/userboot.txt",
    "content": "userboot.so is the FreeBSD user-mode bootloader\n\nSo, this is a bit horrible but it works:\n\n  - userboot is compiled on FreeBSD with '-target x86_64-apple-darwin14' CFLAGS\n  - same for the dependencies of userboot (stand, ficl, zfs)\n  - you have to use the MachO linker set header (include/xhyve/support/linker_set.h)\n  - the resulting object files are linked on OS X with 'clang -dead_strip -shared -o userboot.so *.o *.So'\n"
  },
  {
    "path": "xcconfigs/common.xcconfig",
    "content": "MACOSX_DEPLOYMENT_TARGET = 10.10\nCURRENT_PROJECT_VERSION = 0.2.0\n\nINSTALL_PREFIX = /opt/xhyve\n\nCODE_SIGN_IDENTITY = -\n\nVERSIONING_SYSTEM = apple-generic\n\nDEBUG_INFORMATION_FORMAT = dwarf-with-dsym\nPREBINDING = NO\n\nENABLE_STRICT_OBJC_MSGSEND = YES\nCLANG_ENABLE_OBJC_ARC = YES\nCLANG_ENABLE_MODULES = YES\n\nGCC_C_LANGUAGE_STANDARD = gnu11\nGCC_NO_COMMON_BLOCKS = YES\nGCC_OPTIMIZATION_LEVEL = s\n\nOTHER_CFLAGS_common = -fstrict-aliasing\nOTHER_CFLAGS = $(inherited) $(OTHER_CFLAGS_common)\nOTHER_LDFLAGS_common =\nOTHER_LDFLAGS = $(inherited) $(OTHER_LDFLAGS_common)\nGCC_PREPROCESSOR_DEFINITIONS_common =\nGCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(GCC_PREPROCESSOR_DEFINITIONS_common)\n\nHEADER_SEARCH_PATHS = $(SRCROOT)/include $(inherited)\n\nWARNING_CFLAGS = -Weverything -Wall -Wno-error=deprecated -Wno-unknown-warning-option -Wno-reserved-id-macro -Wno-missing-variable-declarations -pedantic\nGCC_TREAT_WARNINGS_AS_ERRORS = YES\nCLANG_WARN_BOOL_CONVERSION = YES\nCLANG_WARN_CONSTANT_CONVERSION = YES\nCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES\nCLANG_WARN_EMPTY_BODY = YES\nCLANG_WARN_ENUM_CONVERSION = YES\nCLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES\nCLANG_WARN_INT_CONVERSION = YES\nCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\nGCC_WARN_64_TO_32_BIT_CONVERSION = YES\nGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR\nGCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES\nGCC_WARN_UNDECLARED_SELECTOR = YES\nGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE\nGCC_WARN_UNUSED_FUNCTION = YES\nGCC_WARN_UNUSED_LABEL = YES\nGCC_WARN_UNUSED_PARAMETER = YES\nGCC_WARN_UNUSED_VARIABLE = YES\nCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\nCLANG_WARN_COMMA = YES;\nCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\nCLANG_WARN_INFINITE_RECURSION = YES;\nCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\nCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\nCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\nCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\nCLANG_WARN_STRICT_PROTOTYPES = YES;\nCLANG_WARN_SUSPICIOUS_MOVE = YES;\nCLANG_WARN_UNREACHABLE_CODE = YES;\n\nLLVM_LTO = YES\n"
  },
  {
    "path": "xcconfigs/common_asan.xcconfig",
    "content": "#include \"common_debug.xcconfig\"\n\nOTHER_CFLAGS_asan = $(OTHER_CFLAGS_common) -fsanitize=address\nOTHER_CFLAGS = $(inherited) $(OTHER_CFLAGS_asan)\n\nOTHER_LDFLAGS_asan = $(OTHER_LDFLAGS_debug) -fsanitize=address\nOTHER_LDFLAGS = $(inherited) $(OTHER_LDFLAGS_asan)\n\nGCC_PREPROCESSOR_DEFINITIONS_asan = $(GCC_PREPROCESSOR_DEFINITIONS_debug)\nGCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(GCC_PREPROCESSOR_DEFINITIONS_asan)\n"
  },
  {
    "path": "xcconfigs/common_debug.xcconfig",
    "content": "#include \"common.xcconfig\"\n\nCOPY_PHASE_STRIP = NO\nSTRIP_INSTALLED_PRODUCT = NO\n\nGCC_OPTIMIZATION_LEVEL = 0\nLLVM_LTO = NO\n\nOTHER_CFLAGS_debug = $(OTHER_CFLAGS_common) -fno-inline\nOTHER_CFLAGS = $(inherited) $(OTHER_CFLAGS_debug)\n\nOTHER_LDFLAGS_debug = $(OTHER_LDFLAGS_common)\nOTHER_LDFLAGS = $(inherited) $(OTHER_LDFLAGS_debug)\n\nGCC_PREPROCESSOR_DEFINITIONS_asan = $(GCC_PREPROCESSOR_DEFINITIONS_common) XHYVE_CONFIG_ASSERT\nGCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(GCC_PREPROCESSOR_DEFINITIONS_common)\n\nENABLE_TESTABILITY = YES;\nONLY_ACTIVE_ARCH = YES;\n"
  },
  {
    "path": "xcconfigs/xhyve.xcconfig",
    "content": "ARCHS = x86_64;\n\nCODE_SIGN_ENTITLEMENTS = src/xhyve-entitlements.plist\nOTHER_CODE_SIGN_FLAGS = -o library\n\nPRODUCT_BUNDLE_IDENTIFIER = xyz.xhyve.xhyve\n\nINFOPLIST_FILE = src/xhyve-Info.plist\nCREATE_INFOPLIST_SECTION_IN_BINARY = YES\n\nOTHER_CFLAGS = $(inherited) -include xhyve-version.h -fvisibility=hidden\n\nINSTALL_PATH = $(INSTALL_PREFIX)/bin\nMAN_INSTALL_PATH = $(INSTALL_PREFIX)/share/man\n"
  },
  {
    "path": "xcscripts/version.sh",
    "content": "#!/bin/bash\n\nset -e -x\n\nif [[ -d \"${SRCROOT}/.git\" ]] ; then\n    VERSION=$(GIT_DIR=\"${SRCROOT}\"/.git git describe --abbrev=6 --dirty --always --tags)\nelse\n    VERSION=\"v${CURRENT_PROJECT_VERSION}\"\nfi\n\nmkdir -p \"${DERIVED_FILE_DIR}\"\necho \"#define VERSION \\\"${VERSION}\\\"\" > \"${DERIVED_FILE_DIR}/xhyve-version.h\"\n"
  },
  {
    "path": "xhyve.1",
    "content": ".\\\" Copyright (c) 2013 Peter Grehan\n.\\\" Copyright (c) 2015 xhyve developers\n.\\\" All rights reserved.\n.\\\"\n.\\\" Redistribution and use in source and binary forms, with or without\n.\\\" modification, are permitted provided that the following conditions\n.\\\" are met:\n.\\\" 1. Redistributions of source code must retain the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer.\n.\\\" 2. Redistributions in binary form must reproduce the above copyright\n.\\\"    notice, this list of conditions and the following disclaimer in the\n.\\\"    documentation and/or other materials provided with the distribution.\n.\\\"\n.\\\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND\n.\\\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n.\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n.\\\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE\n.\\\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n.\\\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n.\\\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n.\\\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n.\\\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n.\\\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n.\\\" SUCH DAMAGE.\n.\\\"\n.Dd September 11, 2015\n.Dt XHYVE 1\n.Os\n.Sh NAME\n.Nm xhyve\n.Nd \"run a guest operating system inside a virtual machine\"\n.Sh SYNOPSIS\n.Nm\n.Op Fl behuwxACHPWY\n.Op Fl c Ar numcpus\n.Op Fl g Ar gdbport\n.Op Fl l Ar lpcdev Ns Op , Ns Ar conf\n.Op Fl m Ar size Ns Op Ar K|k|M|m|G|g|T|t\n.Op Fl p Ar vcpu:hostcpu\n.Op Fl s Ar slot,emulation Ns Op , Ns Ar conf\n.Op Fl U Ar uuid\n.Op Fl f Ar firmware\n.Sh DESCRIPTION\n.Nm\nis a hypervisor that runs guest operating systems inside a\nvirtual machine.\n.Pp\nParameters such as the number of virtual CPUs, amount of guest memory, and\nI/O connectivity can be specified with command-line parameters.\n.Pp\n.Nm\nruns until the guest operating system reboots or an unhandled hypervisor\nexit is detected.\n.Sh OPTIONS\n.Bl -tag -width 10n\n.It Fl A\nGenerate ACPI tables.\nRequired for\n.Fx Ns /amd64\nguests.\n.It Fl b\nEnable a low-level console device supported by\n.Fx\nkernels compiled with\n.Cd \"device bvmconsole\" .\nThis option will be deprecated in a future version.\n.It Fl c Ar numcpus\nNumber of guest virtual CPUs.\nThe default is 1 and the maximum is 16.\n.It Fl C\nInclude guest memory in core file.\n.It Fl e\nForce\n.Nm\nto exit when a guest issues an access to an I/O port that is not emulated.\nThis is intended for debug purposes.\n.It Fl g Ar gdbport\nFor\n.Fx\nkernels compiled with\n.Cd \"device bvmdebug\" ,\nallow a remote kernel kgdb to be relayed to the guest kernel gdb stub\nvia a local IPv4 address and this port.\nThis option will be deprecated in a future version.\n.It Fl h\nPrint help message and exit.\n.It Fl H\nYield the virtual CPU thread when a HLT instruction is detected.\nIf this option is not specified, virtual CPUs will use 100% of a host CPU.\n.It Fl l Ar lpcdev Ns Op , Ns Ar conf\nAllow devices behind the LPC PCI-ISA bridge to be configured.\nThe only supported devices are the TTY-class devices\n.Ar com1\nand\n.Ar com2\nand the boot ROM device\n.Ar bootrom .\n.It Fl m Ar size Ns Op Ar K|k|M|m|G|g|T|t\nGuest physical memory size in bytes.\n.Pp\nThe size argument may be suffixed with one of K, M, G or T (either upper\nor lower case) to indicate a multiple of kilobytes, megabytes, gigabytes,\nor terabytes.\nIf no suffix is given, the value is assumed to be in megabytes.\n.It Fl p Ar vcpu:hostcpu\nPin guest's virtual CPU\n.Em vcpu\nto\n.Em hostcpu .\n.It Fl P\nForce the guest virtual CPU to exit when a PAUSE instruction is detected.\n.It Fl s Ar slot,emulation Ns Op , Ns Ar conf\nConfigure a virtual PCI slot and function.\n.Pp\n.Nm\nprovides PCI bus emulation and virtual devices that can be attached to\nslots on the bus.\nThere are 32 available slots, with the option of providing up to 8 functions\nper slot.\n.Bl -tag -width 10n\n.It Ar slot\n.Ar pcislot[:function]\n.Ar bus:pcislot:function\n.Pp\nThe\n.Ar pcislot\nvalue is 0 to 31.\nThe optional\n.Ar function\nvalue is 0 to 7.\nThe optional\n.Ar bus\nvalue is 0 to 255.\nIf not specified, the\n.Ar function\nvalue defaults to 0.\nIf not specified, the\n.Ar bus\nvalue defaults to 0.\n.It Ar emulation\n.Bl -tag -width 10n\n.It Li hostbridge | Li amd_hostbridge\n.Pp\nProvide a simple host bridge.\nThis is usually configured at slot 0, and is required by most guest\noperating systems.\nThe\n.Li amd_hostbridge\nemulation is identical but uses a PCI vendor ID of\n.Li AMD .\n.It Li passthru\nPCI pass-through device.\n.It Li virtio-net\nVirtio network interface.\n.It Li virtio-blk\nVirtio block storage interface.\n.It Li virtio-rnd\nVirtio RNG interface.\n.It Li ahci-cd\nAHCI controller attached to an ATAPI CD/DVD.\n.It Li ahci-hd\nAHCI controller attached to a SATA hard-drive.\n.It Li uart\nPCI 16550 serial device.\n.It Li lpc\nLPC PCI-ISA bridge with COM1 and COM2 16550 serial ports and a boot ROM.\nThe LPC bridge emulation can only be configured on bus 0.\n.El\n.It Op Ar conf\nThis optional parameter describes the backend for device emulations.\nIf\n.Ar conf\nis not specified, the device emulation has no backend and can be\nconsidered unconnected.\n.Pp\nNetwork devices:\n.Bl -tag -width 10n\n.It Ar tapN Ns Op , Ns Ar mac=xx:xx:xx:xx:xx:xx\n.It Ar vmnetN Ns Op , Ns Ar mac=xx:xx:xx:xx:xx:xx\n.Pp\nIf\n.Ar mac\nis not specified, the MAC address is derived from a fixed OUI and the\nremaining bytes from an MD5 hash of the slot and function numbers and\nthe device name.\n.Pp\nThe MAC address is an ASCII string in\n.Xr ethers 5\nformat.\n.El\n.Pp\nBlock storage devices:\n.Bl -tag -width 10n\n.It Pa /filename Ns Oo , Ns Ar block-device-options Oc\n.It Pa /dev/xxx Ns Oo , Ns Ar block-device-options Oc\n.El\n.Pp\nThe\n.Ar block-device-options\nare:\n.Bl -tag -width 8n\n.It Li nocache\nOpen the file with\n.Dv O_DIRECT .\n.It Li direct\nOpen the file using\n.Dv O_SYNC .\n.It Li ro\nForce the file to be opened read-only.\n.It Li sectorsize= Ns Ar logical Ns Oo / Ns Ar physical Oc\nSpecify the logical and physical sector sizes of the emulated disk.\nThe physical sector size is optional and is equal to the logical sector size\nif not explicitly specified.\n.El\n.Pp\nTTY devices:\n.Bl -tag -width 10n\n.It Li stdio\nConnect the serial port to the standard input and output of\nthe\n.Nm\nprocess.\n.It Pa /dev/xxx\nUse the host TTY device for serial port I/O.\n.El\n.Pp\nBoot ROM device:\n.Bl -tag -width 10n\n.It Pa romfile\nMap\n.Ar romfile\nin the guest address space reserved for boot firmware.\n.El\n.Pp\nPass-through devices:\n.Bl -tag -width 10n\n.It Ns Ar slot Ns / Ns Ar bus Ns / Ns Ar function\nConnect to a PCI device on the host at the selector described by\n.Ar slot ,\n.Ar bus ,\nand\n.Ar function\nnumbers.\n.El\n.Pp\nThe host device must have been reserved at boot-time using the\n.Va pptdev\nloader variable as described in\n.Xr vmm 4 .\n.El\n.It Fl u\nRTC keeps UTC time.\n.It Fl U Ar uuid\nSet the universally unique identifier\n.Pq UUID\nin the guest's System Management BIOS System Information structure.\nBy default a UUID is generated from the host's hostname and\n.Ar vmname .\n.It Fl w\nIgnore accesses to unimplemented Model Specific Registers (MSRs).\nThis is intended for debug purposes.\n.It Fl W\nForce virtio PCI device emulations to use MSI interrupts instead of MSI-X\ninterrupts.\n.It Fl x\nThe guest's local APIC is configured in x2APIC mode.\n.It Fl Y\nDisable MPtable generation.\n.It Fl f Ar firmware\nTODO Explain this!\n.El\n.Sh EXAMPLES\nTo run a virtual machine with 1GB of memory, two virtual CPUs, a virtio\nblock device backed by the\n.Pa /my/image\nfilesystem image, and a serial port for the console:\n.Bd -literal -offset indent\nxhyve -c 2 -s 0,hostbridge -s 1,lpc -s 2,virtio-blk,/my/image \\\\\n  -l com1,stdio -A -H -P -m 1G \\\\\n  -f kexec,vmlinuz,initrd.gz,\"earlyprintk=serial console=ttyS0\"\n.Ed\n.Pp\nRun a 24GB single-CPU virtual machine with three network ports, one of which\nhas a MAC address specified:\n.Bd -literal -offset indent\nxhyve -s 0,hostbridge -s 1,lpc -s 2:0,virtio-net,tap0 \\\\\n  -s 2:1,virtio-net,tap1 \\\\\n  -s 2:2,virtio-net,tap2,mac=00:be:fa:76:45:00 \\\\\n  -s 3,virtio-blk,/my/image -l com1,stdio \\\\\n  -A -H -P -m 24G -f fbsd,userboot.so,bootvolume.img,\"\" \\\\\n.Ed\n.Pp\nRun an 8GB quad-CPU virtual machine with 8 AHCI SATA disks, an AHCI ATAPI\nCD-ROM, a single virtio network port, an AMD hostbridge, and the console\nport connected to an\n.Xr nmdm 4\nnull-modem device.\n.Bd -literal -offset indent\nxhyve -c 4 \\\\\n  -s 0,amd_hostbridge -s 1,lpc \\\\\n  -s 1:0,ahci-hd,/images/disk.1 \\\\\n  -s 1:1,ahci-hd,/images/disk.2 \\\\\n  -s 1:2,ahci-hd,/images/disk.3 \\\\\n  -s 1:3,ahci-hd,/images/disk.4 \\\\\n  -s 1:4,ahci-hd,/images/disk.5 \\\\\n  -s 1:5,ahci-hd,/images/disk.6 \\\\\n  -s 1:6,ahci-hd,/images/disk.7 \\\\\n  -s 1:7,ahci-hd,/images/disk.8 \\\\\n  -s 2,ahci-cd,/images/install.iso \\\\\n  -s 3,virtio-net,tap0 \\\\\n  -l com1,/dev/nmdm0A \\\\\n  -A -H -P -m 8G \\\\\n  -f kexec,vmlinuz,initrd.gz,\"earlyprintk=serial console=ttyS0\"\n\n.Ed\n.Sh HISTORY\n.Nm\nis a port of FreeBSD's bhyve hypervisor to OS X that\nworks entirely in userspace and has no other dependencies.\n.Sh AUTHORS\n.An Michael Steil Aq Mt mist64@mac.com\n"
  },
  {
    "path": "xhyve.xcodeproj/.gitignore",
    "content": "project.xcworkspace\nxcuserdata\n"
  },
  {
    "path": "xhyve.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 52;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t005C8E61208536B9009B0C6B /* pci_e82545.c in Sources */ = {isa = PBXBuildFile; fileRef = 005C8E60208536B9009B0C6B /* pci_e82545.c */; };\n\t\t00D3D5A6207C662200DDCDF6 /* bootrom.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5A5207C662200DDCDF6 /* bootrom.c */; };\n\t\t00D3D5AD207C828900DDCDF6 /* bhyvegc.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5AC207C828900DDCDF6 /* bhyvegc.c */; };\n\t\t00D3D5AF207C829600DDCDF6 /* console.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5AE207C829600DDCDF6 /* console.c */; };\n\t\t00D3D5B1207C82A200DDCDF6 /* pci_fbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5B0207C82A200DDCDF6 /* pci_fbuf.c */; };\n\t\t00D3D5B3207C82AB00DDCDF6 /* rfb.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5B2207C82AB00DDCDF6 /* rfb.c */; };\n\t\t00D3D5B5207C82B300DDCDF6 /* vga.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5B4207C82B200DDCDF6 /* vga.c */; };\n\t\t00D3D5B8207EAFF900DDCDF6 /* sockstream.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5B7207EAFF900DDCDF6 /* sockstream.c */; };\n\t\t00D3D5BB2080044200DDCDF6 /* ps2kbd.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5B92080044100DDCDF6 /* ps2kbd.c */; };\n\t\t00D3D5BC2080044200DDCDF6 /* ps2mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = 00D3D5BA2080044200DDCDF6 /* ps2mouse.c */; };\n\t\t3F3FF9E91BF7C63A004C89A1 /* Hypervisor.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F3FF9E81BF7C63A004C89A1 /* Hypervisor.framework */; };\n\t\t3F3FFA5D1BF7C6A7004C89A1 /* acpitbl.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA1F1BF7C6A7004C89A1 /* acpitbl.c */; };\n\t\t3F3FFA5E1BF7C6A7004C89A1 /* atkbdc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA201BF7C6A7004C89A1 /* atkbdc.c */; };\n\t\t3F3FFA5F1BF7C6A7004C89A1 /* block_if.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA211BF7C6A7004C89A1 /* block_if.c */; };\n\t\t3F3FFA601BF7C6A7004C89A1 /* consport.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA221BF7C6A7004C89A1 /* consport.c */; };\n\t\t3F3FFA611BF7C6A7004C89A1 /* dbgport.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA231BF7C6A7004C89A1 /* dbgport.c */; };\n\t\t3F3FFA621BF7C6A7004C89A1 /* fbsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA261BF7C6A7004C89A1 /* fbsd.c */; };\n\t\t3F3FFA631BF7C6A7004C89A1 /* kexec.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA271BF7C6A7004C89A1 /* kexec.c */; };\n\t\t3F3FFA641BF7C6A7004C89A1 /* inout.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA281BF7C6A7004C89A1 /* inout.c */; };\n\t\t3F3FFA651BF7C6A7004C89A1 /* ioapic.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA291BF7C6A7004C89A1 /* ioapic.c */; };\n\t\t3F3FFA671BF7C6A7004C89A1 /* mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA2B1BF7C6A7004C89A1 /* mem.c */; };\n\t\t3F3FFA681BF7C6A7004C89A1 /* mevent.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA2C1BF7C6A7004C89A1 /* mevent.c */; };\n\t\t3F3FFA6A1BF7C6A7004C89A1 /* mptbl.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA2E1BF7C6A7004C89A1 /* mptbl.c */; };\n\t\t3F3FFA6B1BF7C6A7004C89A1 /* pci_ahci.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA2F1BF7C6A7004C89A1 /* pci_ahci.c */; };\n\t\t3F3FFA6C1BF7C6A7004C89A1 /* pci_emul.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA301BF7C6A7004C89A1 /* pci_emul.c */; };\n\t\t3F3FFA6D1BF7C6A7004C89A1 /* pci_hostbridge.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA311BF7C6A7004C89A1 /* pci_hostbridge.c */; };\n\t\t3F3FFA6E1BF7C6A7004C89A1 /* pci_irq.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA321BF7C6A7004C89A1 /* pci_irq.c */; };\n\t\t3F3FFA6F1BF7C6A7004C89A1 /* pci_lpc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA331BF7C6A7004C89A1 /* pci_lpc.c */; };\n\t\t3F3FFA701BF7C6A7004C89A1 /* pci_uart.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA341BF7C6A7004C89A1 /* pci_uart.c */; };\n\t\t3F3FFA711BF7C6A7004C89A1 /* pci_virtio_block.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA351BF7C6A7004C89A1 /* pci_virtio_block.c */; };\n\t\t3F3FFA721BF7C6A7004C89A1 /* pci_virtio_net_tap.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA361BF7C6A7004C89A1 /* pci_virtio_net_tap.c */; };\n\t\t3F3FFA731BF7C6A7004C89A1 /* pci_virtio_net_vmnet.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA371BF7C6A7004C89A1 /* pci_virtio_net_vmnet.c */; };\n\t\t3F3FFA741BF7C6A7004C89A1 /* pci_virtio_rnd.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA381BF7C6A7004C89A1 /* pci_virtio_rnd.c */; };\n\t\t3F3FFA751BF7C6A7004C89A1 /* pm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA391BF7C6A7004C89A1 /* pm.c */; };\n\t\t3F3FFA761BF7C6A7004C89A1 /* post.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA3A1BF7C6A7004C89A1 /* post.c */; };\n\t\t3F3FFA771BF7C6A7004C89A1 /* rtc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA3B1BF7C6A7004C89A1 /* rtc.c */; };\n\t\t3F3FFA781BF7C6A7004C89A1 /* smbiostbl.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA3C1BF7C6A7004C89A1 /* smbiostbl.c */; };\n\t\t3F3FFA791BF7C6A7004C89A1 /* task_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA3D1BF7C6A7004C89A1 /* task_switch.c */; };\n\t\t3F3FFA7A1BF7C6A7004C89A1 /* uart_emul.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA3E1BF7C6A7004C89A1 /* uart_emul.c */; };\n\t\t3F3FFA7B1BF7C6A7004C89A1 /* virtio.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA3F1BF7C6A7004C89A1 /* virtio.c */; };\n\t\t3F3FFA7C1BF7C6A7004C89A1 /* vmcs.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA421BF7C6A7004C89A1 /* vmcs.c */; };\n\t\t3F3FFA7D1BF7C6A7004C89A1 /* vmx.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA431BF7C6A7004C89A1 /* vmx.c */; };\n\t\t3F3FFA7E1BF7C6A7004C89A1 /* vmx_msr.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA441BF7C6A7004C89A1 /* vmx_msr.c */; };\n\t\t3F3FFA7F1BF7C6A7004C89A1 /* vatpic.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA461BF7C6A7004C89A1 /* vatpic.c */; };\n\t\t3F3FFA801BF7C6A7004C89A1 /* vatpit.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA471BF7C6A7004C89A1 /* vatpit.c */; };\n\t\t3F3FFA811BF7C6A7004C89A1 /* vhpet.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA481BF7C6A7004C89A1 /* vhpet.c */; };\n\t\t3F3FFA821BF7C6A7004C89A1 /* vioapic.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA491BF7C6A7004C89A1 /* vioapic.c */; };\n\t\t3F3FFA831BF7C6A7004C89A1 /* vlapic.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA4A1BF7C6A7004C89A1 /* vlapic.c */; };\n\t\t3F3FFA841BF7C6A7004C89A1 /* vpmtmr.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA4B1BF7C6A7004C89A1 /* vpmtmr.c */; };\n\t\t3F3FFA851BF7C6A7004C89A1 /* vrtc.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA4C1BF7C6A7004C89A1 /* vrtc.c */; };\n\t\t3F3FFA861BF7C6A7004C89A1 /* vmm.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA4D1BF7C6A7004C89A1 /* vmm.c */; };\n\t\t3F3FFA871BF7C6A7004C89A1 /* vmm_api.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA4E1BF7C6A7004C89A1 /* vmm_api.c */; };\n\t\t3F3FFA881BF7C6A7004C89A1 /* vmm_callout.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA4F1BF7C6A7004C89A1 /* vmm_callout.c */; };\n\t\t3F3FFA891BF7C6A7004C89A1 /* vmm_host.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA501BF7C6A7004C89A1 /* vmm_host.c */; };\n\t\t3F3FFA8A1BF7C6A7004C89A1 /* vmm_instruction_emul.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA511BF7C6A7004C89A1 /* vmm_instruction_emul.c */; };\n\t\t3F3FFA8B1BF7C6A7004C89A1 /* vmm_ioport.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA521BF7C6A7004C89A1 /* vmm_ioport.c */; };\n\t\t3F3FFA8C1BF7C6A7004C89A1 /* vmm_lapic.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA531BF7C6A7004C89A1 /* vmm_lapic.c */; };\n\t\t3F3FFA8D1BF7C6A7004C89A1 /* vmm_mem.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA541BF7C6A7004C89A1 /* vmm_mem.c */; };\n\t\t3F3FFA8E1BF7C6A7004C89A1 /* vmm_stat.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA551BF7C6A7004C89A1 /* vmm_stat.c */; };\n\t\t3F3FFA8F1BF7C6A7004C89A1 /* vmm_util.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA561BF7C6A7004C89A1 /* vmm_util.c */; };\n\t\t3F3FFA901BF7C6A7004C89A1 /* x86.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA571BF7C6A7004C89A1 /* x86.c */; };\n\t\t3F3FFA911BF7C6A7004C89A1 /* xhyve.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA5A1BF7C6A7004C89A1 /* xhyve.c */; };\n\t\t3F3FFA921BF7C6A7004C89A1 /* xmsr.c in Sources */ = {isa = PBXBuildFile; fileRef = 3F3FFA5B1BF7C6A7004C89A1 /* xmsr.c */; };\n\t\t3F3FFA971BF7CC0E004C89A1 /* xhyve.1 in Install Man Pages */ = {isa = PBXBuildFile; fileRef = 3F3FF9E41BF7C5DC004C89A1 /* xhyve.1 */; };\n\t\tBEDAABE626FE9642003ACEFC /* libz.1.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE076A1426FE962A00C43411 /* libz.1.tbd */; platformFilter = maccatalyst; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t3F1934901BF7C0D40099CC46 /* Install Man Pages */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"$(MAN_INSTALL_PATH)/man1\";\n\t\t\tdstSubfolderSpec = 0;\n\t\t\tfiles = (\n\t\t\t\t3F3FFA971BF7CC0E004C89A1 /* xhyve.1 in Install Man Pages */,\n\t\t\t);\n\t\t\tname = \"Install Man Pages\";\n\t\t\trunOnlyForDeploymentPostprocessing = 1;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t005C8E60208536B9009B0C6B /* pci_e82545.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_e82545.c; sourceTree = \"<group>\"; };\n\t\t005C8E6220853BD8009B0C6B /* e1000_regs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = e1000_regs.h; sourceTree = \"<group>\"; };\n\t\t005C8E6320853BD8009B0C6B /* e1000_defines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = e1000_defines.h; sourceTree = \"<group>\"; };\n\t\t00D3D5A5207C662200DDCDF6 /* bootrom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bootrom.c; sourceTree = \"<group>\"; };\n\t\t00D3D5A7207C662E00DDCDF6 /* bootrom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bootrom.h; sourceTree = \"<group>\"; };\n\t\t00D3D5A8207C825800DDCDF6 /* bhyvegc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bhyvegc.h; sourceTree = \"<group>\"; };\n\t\t00D3D5A9207C826300DDCDF6 /* console.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = console.h; sourceTree = \"<group>\"; };\n\t\t00D3D5AA207C827000DDCDF6 /* rfb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rfb.h; sourceTree = \"<group>\"; };\n\t\t00D3D5AB207C827800DDCDF6 /* vga.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vga.h; sourceTree = \"<group>\"; };\n\t\t00D3D5AC207C828900DDCDF6 /* bhyvegc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bhyvegc.c; sourceTree = \"<group>\"; };\n\t\t00D3D5AE207C829600DDCDF6 /* console.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = console.c; sourceTree = \"<group>\"; };\n\t\t00D3D5B0207C82A200DDCDF6 /* pci_fbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_fbuf.c; sourceTree = \"<group>\"; };\n\t\t00D3D5B2207C82AB00DDCDF6 /* rfb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rfb.c; sourceTree = \"<group>\"; };\n\t\t00D3D5B4207C82B200DDCDF6 /* vga.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vga.c; sourceTree = \"<group>\"; };\n\t\t00D3D5B6207EAFE600DDCDF6 /* sockstream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sockstream.h; sourceTree = \"<group>\"; };\n\t\t00D3D5B7207EAFF900DDCDF6 /* sockstream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sockstream.c; sourceTree = \"<group>\"; };\n\t\t00D3D5B92080044100DDCDF6 /* ps2kbd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2kbd.c; sourceTree = \"<group>\"; };\n\t\t00D3D5BA2080044200DDCDF6 /* ps2mouse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps2mouse.c; sourceTree = \"<group>\"; };\n\t\t00D3D5BD2080046200DDCDF6 /* ps2mouse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ps2mouse.h; sourceTree = \"<group>\"; };\n\t\t00D3D5BE2080046200DDCDF6 /* ps2kbd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ps2kbd.h; sourceTree = \"<group>\"; };\n\t\t00D3D5BF208004CB00DDCDF6 /* atkbdc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = atkbdc.h; sourceTree = \"<group>\"; };\n\t\t3F1934921BF7C0D40099CC46 /* xhyve */ = {isa = PBXFileReference; explicitFileType = \"compiled.mach-o.executable\"; includeInIndex = 0; path = xhyve; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t3F3FF9E01BF7C5D5004C89A1 /* common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = \"<group>\"; };\n\t\t3F3FF9E11BF7C5D5004C89A1 /* common_asan.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = common_asan.xcconfig; sourceTree = \"<group>\"; };\n\t\t3F3FF9E21BF7C5D5004C89A1 /* common_debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = common_debug.xcconfig; sourceTree = \"<group>\"; };\n\t\t3F3FF9E31BF7C5D5004C89A1 /* xhyve.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = xhyve.xcconfig; sourceTree = \"<group>\"; };\n\t\t3F3FF9E41BF7C5DC004C89A1 /* xhyve.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = xhyve.1; sourceTree = SOURCE_ROOT; };\n\t\t3F3FF9E61BF7C5F9004C89A1 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\t3F3FF9E81BF7C63A004C89A1 /* Hypervisor.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Hypervisor.framework; path = /System/Library/Frameworks/Hypervisor.framework; sourceTree = SDKROOT; };\n\t\t3F3FFA1E1BF7C6A7004C89A1 /* acpi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acpi.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA1F1BF7C6A7004C89A1 /* acpitbl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = acpitbl.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA201BF7C6A7004C89A1 /* atkbdc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atkbdc.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA211BF7C6A7004C89A1 /* block_if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = block_if.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA221BF7C6A7004C89A1 /* consport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = consport.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA231BF7C6A7004C89A1 /* dbgport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dbgport.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA241BF7C6A7004C89A1 /* dsdt.asl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsdt.asl; sourceTree = \"<group>\"; };\n\t\t3F3FFA261BF7C6A7004C89A1 /* fbsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fbsd.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA271BF7C6A7004C89A1 /* kexec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kexec.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA281BF7C6A7004C89A1 /* inout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inout.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA291BF7C6A7004C89A1 /* ioapic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapic.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA2B1BF7C6A7004C89A1 /* mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mem.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA2C1BF7C6A7004C89A1 /* mevent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mevent.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA2D1BF7C6A7004C89A1 /* mevent_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mevent_test.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA2E1BF7C6A7004C89A1 /* mptbl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mptbl.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA2F1BF7C6A7004C89A1 /* pci_ahci.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_ahci.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA301BF7C6A7004C89A1 /* pci_emul.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_emul.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA311BF7C6A7004C89A1 /* pci_hostbridge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_hostbridge.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA321BF7C6A7004C89A1 /* pci_irq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_irq.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA331BF7C6A7004C89A1 /* pci_lpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_lpc.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA341BF7C6A7004C89A1 /* pci_uart.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_uart.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA351BF7C6A7004C89A1 /* pci_virtio_block.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_virtio_block.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA361BF7C6A7004C89A1 /* pci_virtio_net_tap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_virtio_net_tap.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA371BF7C6A7004C89A1 /* pci_virtio_net_vmnet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_virtio_net_vmnet.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA381BF7C6A7004C89A1 /* pci_virtio_rnd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pci_virtio_rnd.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA391BF7C6A7004C89A1 /* pm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pm.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA3A1BF7C6A7004C89A1 /* post.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = post.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA3B1BF7C6A7004C89A1 /* rtc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtc.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA3C1BF7C6A7004C89A1 /* smbiostbl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = smbiostbl.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA3D1BF7C6A7004C89A1 /* task_switch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = task_switch.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA3E1BF7C6A7004C89A1 /* uart_emul.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uart_emul.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA3F1BF7C6A7004C89A1 /* virtio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = virtio.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA421BF7C6A7004C89A1 /* vmcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmcs.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA431BF7C6A7004C89A1 /* vmx.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmx.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA441BF7C6A7004C89A1 /* vmx_msr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmx_msr.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA461BF7C6A7004C89A1 /* vatpic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vatpic.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA471BF7C6A7004C89A1 /* vatpit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vatpit.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA481BF7C6A7004C89A1 /* vhpet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vhpet.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA491BF7C6A7004C89A1 /* vioapic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vioapic.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA4A1BF7C6A7004C89A1 /* vlapic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vlapic.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA4B1BF7C6A7004C89A1 /* vpmtmr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vpmtmr.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA4C1BF7C6A7004C89A1 /* vrtc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vrtc.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA4D1BF7C6A7004C89A1 /* vmm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA4E1BF7C6A7004C89A1 /* vmm_api.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_api.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA4F1BF7C6A7004C89A1 /* vmm_callout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_callout.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA501BF7C6A7004C89A1 /* vmm_host.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_host.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA511BF7C6A7004C89A1 /* vmm_instruction_emul.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_instruction_emul.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA521BF7C6A7004C89A1 /* vmm_ioport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_ioport.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA531BF7C6A7004C89A1 /* vmm_lapic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_lapic.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA541BF7C6A7004C89A1 /* vmm_mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_mem.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA551BF7C6A7004C89A1 /* vmm_stat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_stat.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA561BF7C6A7004C89A1 /* vmm_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vmm_util.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA571BF7C6A7004C89A1 /* x86.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x86.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA581BF7C6A7004C89A1 /* xhyve-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = \"xhyve-entitlements.plist\"; path = \"src/xhyve-entitlements.plist\"; sourceTree = \"<group>\"; };\n\t\t3F3FFA591BF7C6A7004C89A1 /* xhyve-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = \"xhyve-Info.plist\"; path = \"src/xhyve-Info.plist\"; sourceTree = \"<group>\"; };\n\t\t3F3FFA5A1BF7C6A7004C89A1 /* xhyve.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xhyve.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA5B1BF7C6A7004C89A1 /* xmsr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xmsr.c; sourceTree = \"<group>\"; };\n\t\t3F3FFA961BF7CBFF004C89A1 /* version.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = version.sh; sourceTree = \"<group>\"; };\n\t\t3FB6515C1BF7CD4500ED886F /* acpi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = acpi.h; sourceTree = \"<group>\"; };\n\t\t3FB6515D1BF7CD4500ED886F /* ahci.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ahci.h; sourceTree = \"<group>\"; };\n\t\t3FB6515E1BF7CD4500ED886F /* block_if.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = block_if.h; sourceTree = \"<group>\"; };\n\t\t3FB6515F1BF7CD4500ED886F /* dbgport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dbgport.h; sourceTree = \"<group>\"; };\n\t\t3FB651611BF7CD4500ED886F /* fbsd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fbsd.h; sourceTree = \"<group>\"; };\n\t\t3FB651621BF7CD4500ED886F /* kexec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kexec.h; sourceTree = \"<group>\"; };\n\t\t3FB651631BF7CD4500ED886F /* inout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = inout.h; sourceTree = \"<group>\"; };\n\t\t3FB651641BF7CD4500ED886F /* ioapic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ioapic.h; sourceTree = \"<group>\"; };\n\t\t3FB651651BF7CD4500ED886F /* mem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mem.h; sourceTree = \"<group>\"; };\n\t\t3FB651661BF7CD4500ED886F /* mevent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mevent.h; sourceTree = \"<group>\"; };\n\t\t3FB651671BF7CD4500ED886F /* mptbl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mptbl.h; sourceTree = \"<group>\"; };\n\t\t3FB651681BF7CD4500ED886F /* pci_emul.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pci_emul.h; sourceTree = \"<group>\"; };\n\t\t3FB651691BF7CD4500ED886F /* pci_irq.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pci_irq.h; sourceTree = \"<group>\"; };\n\t\t3FB6516A1BF7CD4500ED886F /* pci_lpc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pci_lpc.h; sourceTree = \"<group>\"; };\n\t\t3FB6516B1BF7CD4500ED886F /* rtc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rtc.h; sourceTree = \"<group>\"; };\n\t\t3FB6516C1BF7CD4500ED886F /* smbiostbl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = smbiostbl.h; sourceTree = \"<group>\"; };\n\t\t3FB6516E1BF7CD4500ED886F /* acpi_hpet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = acpi_hpet.h; sourceTree = \"<group>\"; };\n\t\t3FB6516F1BF7CD4500ED886F /* apicreg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = apicreg.h; sourceTree = \"<group>\"; };\n\t\t3FB651701BF7CD4500ED886F /* ata.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ata.h; sourceTree = \"<group>\"; };\n\t\t3FB651711BF7CD4500ED886F /* atomic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = atomic.h; sourceTree = \"<group>\"; };\n\t\t3FB651721BF7CD4500ED886F /* bitset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bitset.h; sourceTree = \"<group>\"; };\n\t\t3FB651731BF7CD4500ED886F /* cpuset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cpuset.h; sourceTree = \"<group>\"; };\n\t\t3FB651741BF7CD4500ED886F /* i8253reg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = i8253reg.h; sourceTree = \"<group>\"; };\n\t\t3FB651751BF7CD4500ED886F /* i8259.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = i8259.h; sourceTree = \"<group>\"; };\n\t\t3FB651761BF7CD4500ED886F /* linker_set.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = linker_set.h; sourceTree = \"<group>\"; };\n\t\t3FB651781BF7CD4500ED886F /* misc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = \"<group>\"; };\n\t\t3FB651791BF7CD4500ED886F /* mptable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mptable.h; sourceTree = \"<group>\"; };\n\t\t3FB6517A1BF7CD4500ED886F /* ns16550.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ns16550.h; sourceTree = \"<group>\"; };\n\t\t3FB6517B1BF7CD4500ED886F /* pcireg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pcireg.h; sourceTree = \"<group>\"; };\n\t\t3FB6517C1BF7CD4500ED886F /* psl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = psl.h; sourceTree = \"<group>\"; };\n\t\t3FB6517D1BF7CD4500ED886F /* rtc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = rtc.h; sourceTree = \"<group>\"; };\n\t\t3FB6517E1BF7CD4500ED886F /* segments.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = segments.h; sourceTree = \"<group>\"; };\n\t\t3FB6517F1BF7CD4500ED886F /* specialreg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = specialreg.h; sourceTree = \"<group>\"; };\n\t\t3FB651801BF7CD4500ED886F /* timerreg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = timerreg.h; sourceTree = \"<group>\"; };\n\t\t3FB651811BF7CD4500ED886F /* tree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = \"<group>\"; };\n\t\t3FB651821BF7CD4500ED886F /* uuid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = uuid.h; sourceTree = \"<group>\"; };\n\t\t3FB651831BF7CD4500ED886F /* uart_emul.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = uart_emul.h; sourceTree = \"<group>\"; };\n\t\t3FB651841BF7CD4500ED886F /* virtio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = virtio.h; sourceTree = \"<group>\"; };\n\t\t3FB651871BF7CD4500ED886F /* vmcs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmcs.h; sourceTree = \"<group>\"; };\n\t\t3FB651881BF7CD4500ED886F /* vmx.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmx.h; sourceTree = \"<group>\"; };\n\t\t3FB651891BF7CD4500ED886F /* vmx_controls.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmx_controls.h; sourceTree = \"<group>\"; };\n\t\t3FB6518A1BF7CD4500ED886F /* vmx_msr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmx_msr.h; sourceTree = \"<group>\"; };\n\t\t3FB6518C1BF7CD4500ED886F /* vatpic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vatpic.h; sourceTree = \"<group>\"; };\n\t\t3FB6518D1BF7CD4500ED886F /* vatpit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vatpit.h; sourceTree = \"<group>\"; };\n\t\t3FB6518E1BF7CD4500ED886F /* vhpet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vhpet.h; sourceTree = \"<group>\"; };\n\t\t3FB6518F1BF7CD4500ED886F /* vioapic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vioapic.h; sourceTree = \"<group>\"; };\n\t\t3FB651901BF7CD4500ED886F /* vlapic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vlapic.h; sourceTree = \"<group>\"; };\n\t\t3FB651911BF7CD4500ED886F /* vlapic_priv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vlapic_priv.h; sourceTree = \"<group>\"; };\n\t\t3FB651921BF7CD4500ED886F /* vpmtmr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vpmtmr.h; sourceTree = \"<group>\"; };\n\t\t3FB651931BF7CD4500ED886F /* vrtc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vrtc.h; sourceTree = \"<group>\"; };\n\t\t3FB651941BF7CD4500ED886F /* vmm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm.h; sourceTree = \"<group>\"; };\n\t\t3FB651951BF7CD4500ED886F /* vmm_api.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_api.h; sourceTree = \"<group>\"; };\n\t\t3FB651961BF7CD4500ED886F /* vmm_callout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_callout.h; sourceTree = \"<group>\"; };\n\t\t3FB651971BF7CD4500ED886F /* vmm_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_common.h; sourceTree = \"<group>\"; };\n\t\t3FB651981BF7CD4500ED886F /* vmm_host.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_host.h; sourceTree = \"<group>\"; };\n\t\t3FB651991BF7CD4500ED886F /* vmm_instruction_emul.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_instruction_emul.h; sourceTree = \"<group>\"; };\n\t\t3FB6519A1BF7CD4500ED886F /* vmm_ioport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_ioport.h; sourceTree = \"<group>\"; };\n\t\t3FB6519B1BF7CD4500ED886F /* vmm_ktr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_ktr.h; sourceTree = \"<group>\"; };\n\t\t3FB6519C1BF7CD4500ED886F /* vmm_lapic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_lapic.h; sourceTree = \"<group>\"; };\n\t\t3FB6519D1BF7CD4500ED886F /* vmm_mem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_mem.h; sourceTree = \"<group>\"; };\n\t\t3FB6519E1BF7CD4500ED886F /* vmm_stat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_stat.h; sourceTree = \"<group>\"; };\n\t\t3FB6519F1BF7CD4500ED886F /* vmm_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vmm_util.h; sourceTree = \"<group>\"; };\n\t\t3FB651A01BF7CD4500ED886F /* x86.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = x86.h; sourceTree = \"<group>\"; };\n\t\t3FB651A11BF7CD4500ED886F /* xhyve.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xhyve.h; sourceTree = \"<group>\"; };\n\t\t3FB651A21BF7CD4500ED886F /* xmsr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xmsr.h; sourceTree = \"<group>\"; };\n\t\tBE076A1426FE962A00C43411 /* libz.1.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libz.1.tbd; path = usr/lib/libz.1.tbd; sourceTree = SDKROOT; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t3F19348F1BF7C0D40099CC46 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tBEDAABE626FE9642003ACEFC /* libz.1.tbd in Frameworks */,\n\t\t\t\t3F3FF9E91BF7C63A004C89A1 /* Hypervisor.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t3F1934891BF7C0D40099CC46 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB6515A1BF7CD4500ED886F /* include */,\n\t\t\t\t3F3FFA1D1BF7C6A7004C89A1 /* src */,\n\t\t\t\t3F3FF9E51BF7C5ED004C89A1 /* Documentation */,\n\t\t\t\t3F3FF9E71BF7C5FF004C89A1 /* Build Support */,\n\t\t\t\t3F1934931BF7C0D40099CC46 /* Products */,\n\t\t\t\tBE076A1326FE962A00C43411 /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t\tusesTabs = 1;\n\t\t};\n\t\t3F1934931BF7C0D40099CC46 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F1934921BF7C0D40099CC46 /* xhyve */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FF9DF1BF7C5D5004C89A1 /* xcconfigs */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA951BF7CBFF004C89A1 /* xcscripts */,\n\t\t\t\t3F3FF9E01BF7C5D5004C89A1 /* common.xcconfig */,\n\t\t\t\t3F3FF9E11BF7C5D5004C89A1 /* common_asan.xcconfig */,\n\t\t\t\t3F3FF9E21BF7C5D5004C89A1 /* common_debug.xcconfig */,\n\t\t\t\t3F3FF9E31BF7C5D5004C89A1 /* xhyve.xcconfig */,\n\t\t\t);\n\t\t\tpath = xcconfigs;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FF9E51BF7C5ED004C89A1 /* Documentation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FF9E61BF7C5F9004C89A1 /* README.md */,\n\t\t\t\t3F3FF9E41BF7C5DC004C89A1 /* xhyve.1 */,\n\t\t\t);\n\t\t\tname = Documentation;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FF9E71BF7C5FF004C89A1 /* Build Support */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA581BF7C6A7004C89A1 /* xhyve-entitlements.plist */,\n\t\t\t\t3F3FFA591BF7C6A7004C89A1 /* xhyve-Info.plist */,\n\t\t\t\t3F3FF9EA1BF7C64C004C89A1 /* Linked Frameworks */,\n\t\t\t\t3F3FF9DF1BF7C5D5004C89A1 /* xcconfigs */,\n\t\t\t);\n\t\t\tname = \"Build Support\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FF9EA1BF7C64C004C89A1 /* Linked Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FF9E81BF7C63A004C89A1 /* Hypervisor.framework */,\n\t\t\t);\n\t\t\tname = \"Linked Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FFA1D1BF7C6A7004C89A1 /* src */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA251BF7C6A7004C89A1 /* firmware */,\n\t\t\t\t3F3FFA401BF7C6A7004C89A1 /* vmm */,\n\t\t\t\t3F3FFA1E1BF7C6A7004C89A1 /* acpi.c */,\n\t\t\t\t3F3FFA1F1BF7C6A7004C89A1 /* acpitbl.c */,\n\t\t\t\t3F3FFA201BF7C6A7004C89A1 /* atkbdc.c */,\n\t\t\t\t00D3D5AC207C828900DDCDF6 /* bhyvegc.c */,\n\t\t\t\t3F3FFA211BF7C6A7004C89A1 /* block_if.c */,\n\t\t\t\t00D3D5A5207C662200DDCDF6 /* bootrom.c */,\n\t\t\t\t00D3D5AE207C829600DDCDF6 /* console.c */,\n\t\t\t\t3F3FFA221BF7C6A7004C89A1 /* consport.c */,\n\t\t\t\t3F3FFA231BF7C6A7004C89A1 /* dbgport.c */,\n\t\t\t\t3F3FFA241BF7C6A7004C89A1 /* dsdt.asl */,\n\t\t\t\t3F3FFA281BF7C6A7004C89A1 /* inout.c */,\n\t\t\t\t3F3FFA291BF7C6A7004C89A1 /* ioapic.c */,\n\t\t\t\t3F3FFA2B1BF7C6A7004C89A1 /* mem.c */,\n\t\t\t\t3F3FFA2C1BF7C6A7004C89A1 /* mevent.c */,\n\t\t\t\t3F3FFA2D1BF7C6A7004C89A1 /* mevent_test.c */,\n\t\t\t\t3F3FFA2E1BF7C6A7004C89A1 /* mptbl.c */,\n\t\t\t\t3F3FFA2F1BF7C6A7004C89A1 /* pci_ahci.c */,\n\t\t\t\t005C8E60208536B9009B0C6B /* pci_e82545.c */,\n\t\t\t\t3F3FFA301BF7C6A7004C89A1 /* pci_emul.c */,\n\t\t\t\t00D3D5B0207C82A200DDCDF6 /* pci_fbuf.c */,\n\t\t\t\t3F3FFA311BF7C6A7004C89A1 /* pci_hostbridge.c */,\n\t\t\t\t3F3FFA321BF7C6A7004C89A1 /* pci_irq.c */,\n\t\t\t\t3F3FFA331BF7C6A7004C89A1 /* pci_lpc.c */,\n\t\t\t\t3F3FFA341BF7C6A7004C89A1 /* pci_uart.c */,\n\t\t\t\t3F3FFA351BF7C6A7004C89A1 /* pci_virtio_block.c */,\n\t\t\t\t3F3FFA361BF7C6A7004C89A1 /* pci_virtio_net_tap.c */,\n\t\t\t\t3F3FFA371BF7C6A7004C89A1 /* pci_virtio_net_vmnet.c */,\n\t\t\t\t3F3FFA381BF7C6A7004C89A1 /* pci_virtio_rnd.c */,\n\t\t\t\t3F3FFA391BF7C6A7004C89A1 /* pm.c */,\n\t\t\t\t3F3FFA3A1BF7C6A7004C89A1 /* post.c */,\n\t\t\t\t00D3D5B92080044100DDCDF6 /* ps2kbd.c */,\n\t\t\t\t00D3D5BA2080044200DDCDF6 /* ps2mouse.c */,\n\t\t\t\t00D3D5B2207C82AB00DDCDF6 /* rfb.c */,\n\t\t\t\t3F3FFA3B1BF7C6A7004C89A1 /* rtc.c */,\n\t\t\t\t3F3FFA3C1BF7C6A7004C89A1 /* smbiostbl.c */,\n\t\t\t\t00D3D5B7207EAFF900DDCDF6 /* sockstream.c */,\n\t\t\t\t3F3FFA3D1BF7C6A7004C89A1 /* task_switch.c */,\n\t\t\t\t3F3FFA3E1BF7C6A7004C89A1 /* uart_emul.c */,\n\t\t\t\t00D3D5B4207C82B200DDCDF6 /* vga.c */,\n\t\t\t\t3F3FFA3F1BF7C6A7004C89A1 /* virtio.c */,\n\t\t\t\t3F3FFA5A1BF7C6A7004C89A1 /* xhyve.c */,\n\t\t\t\t3F3FFA5B1BF7C6A7004C89A1 /* xmsr.c */,\n\t\t\t);\n\t\t\tpath = src;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FFA251BF7C6A7004C89A1 /* firmware */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA261BF7C6A7004C89A1 /* fbsd.c */,\n\t\t\t\t3F3FFA271BF7C6A7004C89A1 /* kexec.c */,\n\t\t\t);\n\t\t\tpath = firmware;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FFA401BF7C6A7004C89A1 /* vmm */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA411BF7C6A7004C89A1 /* intel */,\n\t\t\t\t3F3FFA451BF7C6A7004C89A1 /* io */,\n\t\t\t\t3F3FFA4D1BF7C6A7004C89A1 /* vmm.c */,\n\t\t\t\t3F3FFA4E1BF7C6A7004C89A1 /* vmm_api.c */,\n\t\t\t\t3F3FFA4F1BF7C6A7004C89A1 /* vmm_callout.c */,\n\t\t\t\t3F3FFA501BF7C6A7004C89A1 /* vmm_host.c */,\n\t\t\t\t3F3FFA511BF7C6A7004C89A1 /* vmm_instruction_emul.c */,\n\t\t\t\t3F3FFA521BF7C6A7004C89A1 /* vmm_ioport.c */,\n\t\t\t\t3F3FFA531BF7C6A7004C89A1 /* vmm_lapic.c */,\n\t\t\t\t3F3FFA541BF7C6A7004C89A1 /* vmm_mem.c */,\n\t\t\t\t3F3FFA551BF7C6A7004C89A1 /* vmm_stat.c */,\n\t\t\t\t3F3FFA561BF7C6A7004C89A1 /* vmm_util.c */,\n\t\t\t\t3F3FFA571BF7C6A7004C89A1 /* x86.c */,\n\t\t\t);\n\t\t\tpath = vmm;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FFA411BF7C6A7004C89A1 /* intel */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA421BF7C6A7004C89A1 /* vmcs.c */,\n\t\t\t\t3F3FFA431BF7C6A7004C89A1 /* vmx.c */,\n\t\t\t\t3F3FFA441BF7C6A7004C89A1 /* vmx_msr.c */,\n\t\t\t);\n\t\t\tpath = intel;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FFA451BF7C6A7004C89A1 /* io */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA461BF7C6A7004C89A1 /* vatpic.c */,\n\t\t\t\t3F3FFA471BF7C6A7004C89A1 /* vatpit.c */,\n\t\t\t\t3F3FFA481BF7C6A7004C89A1 /* vhpet.c */,\n\t\t\t\t3F3FFA491BF7C6A7004C89A1 /* vioapic.c */,\n\t\t\t\t3F3FFA4A1BF7C6A7004C89A1 /* vlapic.c */,\n\t\t\t\t3F3FFA4B1BF7C6A7004C89A1 /* vpmtmr.c */,\n\t\t\t\t3F3FFA4C1BF7C6A7004C89A1 /* vrtc.c */,\n\t\t\t);\n\t\t\tpath = io;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3F3FFA951BF7CBFF004C89A1 /* xcscripts */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3F3FFA961BF7CBFF004C89A1 /* version.sh */,\n\t\t\t);\n\t\t\tpath = xcscripts;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t3FB6515A1BF7CD4500ED886F /* include */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB6515B1BF7CD4500ED886F /* xhyve */,\n\t\t\t);\n\t\t\tpath = include;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FB6515B1BF7CD4500ED886F /* xhyve */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB6515C1BF7CD4500ED886F /* acpi.h */,\n\t\t\t\t3FB6515D1BF7CD4500ED886F /* ahci.h */,\n\t\t\t\t00D3D5BF208004CB00DDCDF6 /* atkbdc.h */,\n\t\t\t\t00D3D5A8207C825800DDCDF6 /* bhyvegc.h */,\n\t\t\t\t3FB6515E1BF7CD4500ED886F /* block_if.h */,\n\t\t\t\t00D3D5A7207C662E00DDCDF6 /* bootrom.h */,\n\t\t\t\t00D3D5A9207C826300DDCDF6 /* console.h */,\n\t\t\t\t3FB6515F1BF7CD4500ED886F /* dbgport.h */,\n\t\t\t\t3FB651601BF7CD4500ED886F /* firmware */,\n\t\t\t\t3FB651631BF7CD4500ED886F /* inout.h */,\n\t\t\t\t3FB651641BF7CD4500ED886F /* ioapic.h */,\n\t\t\t\t3FB651651BF7CD4500ED886F /* mem.h */,\n\t\t\t\t3FB651661BF7CD4500ED886F /* mevent.h */,\n\t\t\t\t3FB651671BF7CD4500ED886F /* mptbl.h */,\n\t\t\t\t3FB651681BF7CD4500ED886F /* pci_emul.h */,\n\t\t\t\t3FB651691BF7CD4500ED886F /* pci_irq.h */,\n\t\t\t\t3FB6516A1BF7CD4500ED886F /* pci_lpc.h */,\n\t\t\t\t00D3D5BE2080046200DDCDF6 /* ps2kbd.h */,\n\t\t\t\t00D3D5BD2080046200DDCDF6 /* ps2mouse.h */,\n\t\t\t\t00D3D5AA207C827000DDCDF6 /* rfb.h */,\n\t\t\t\t3FB6516B1BF7CD4500ED886F /* rtc.h */,\n\t\t\t\t3FB6516C1BF7CD4500ED886F /* smbiostbl.h */,\n\t\t\t\t00D3D5B6207EAFE600DDCDF6 /* sockstream.h */,\n\t\t\t\t3FB6516D1BF7CD4500ED886F /* support */,\n\t\t\t\t3FB651831BF7CD4500ED886F /* uart_emul.h */,\n\t\t\t\t00D3D5AB207C827800DDCDF6 /* vga.h */,\n\t\t\t\t3FB651841BF7CD4500ED886F /* virtio.h */,\n\t\t\t\t3FB651851BF7CD4500ED886F /* vmm */,\n\t\t\t\t3FB651A11BF7CD4500ED886F /* xhyve.h */,\n\t\t\t\t3FB651A21BF7CD4500ED886F /* xmsr.h */,\n\t\t\t);\n\t\t\tpath = xhyve;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FB651601BF7CD4500ED886F /* firmware */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB651611BF7CD4500ED886F /* fbsd.h */,\n\t\t\t\t3FB651621BF7CD4500ED886F /* kexec.h */,\n\t\t\t);\n\t\t\tpath = firmware;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FB6516D1BF7CD4500ED886F /* support */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB6516E1BF7CD4500ED886F /* acpi_hpet.h */,\n\t\t\t\t3FB6516F1BF7CD4500ED886F /* apicreg.h */,\n\t\t\t\t3FB651701BF7CD4500ED886F /* ata.h */,\n\t\t\t\t3FB651711BF7CD4500ED886F /* atomic.h */,\n\t\t\t\t3FB651721BF7CD4500ED886F /* bitset.h */,\n\t\t\t\t3FB651731BF7CD4500ED886F /* cpuset.h */,\n\t\t\t\t005C8E6320853BD8009B0C6B /* e1000_defines.h */,\n\t\t\t\t005C8E6220853BD8009B0C6B /* e1000_regs.h */,\n\t\t\t\t3FB651741BF7CD4500ED886F /* i8253reg.h */,\n\t\t\t\t3FB651751BF7CD4500ED886F /* i8259.h */,\n\t\t\t\t3FB651761BF7CD4500ED886F /* linker_set.h */,\n\t\t\t\t3FB651781BF7CD4500ED886F /* misc.h */,\n\t\t\t\t3FB651791BF7CD4500ED886F /* mptable.h */,\n\t\t\t\t3FB6517A1BF7CD4500ED886F /* ns16550.h */,\n\t\t\t\t3FB6517B1BF7CD4500ED886F /* pcireg.h */,\n\t\t\t\t3FB6517C1BF7CD4500ED886F /* psl.h */,\n\t\t\t\t3FB6517D1BF7CD4500ED886F /* rtc.h */,\n\t\t\t\t3FB6517E1BF7CD4500ED886F /* segments.h */,\n\t\t\t\t3FB6517F1BF7CD4500ED886F /* specialreg.h */,\n\t\t\t\t3FB651801BF7CD4500ED886F /* timerreg.h */,\n\t\t\t\t3FB651811BF7CD4500ED886F /* tree.h */,\n\t\t\t\t3FB651821BF7CD4500ED886F /* uuid.h */,\n\t\t\t);\n\t\t\tpath = support;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FB651851BF7CD4500ED886F /* vmm */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB651861BF7CD4500ED886F /* intel */,\n\t\t\t\t3FB6518B1BF7CD4500ED886F /* io */,\n\t\t\t\t3FB651941BF7CD4500ED886F /* vmm.h */,\n\t\t\t\t3FB651951BF7CD4500ED886F /* vmm_api.h */,\n\t\t\t\t3FB651961BF7CD4500ED886F /* vmm_callout.h */,\n\t\t\t\t3FB651971BF7CD4500ED886F /* vmm_common.h */,\n\t\t\t\t3FB651981BF7CD4500ED886F /* vmm_host.h */,\n\t\t\t\t3FB651991BF7CD4500ED886F /* vmm_instruction_emul.h */,\n\t\t\t\t3FB6519A1BF7CD4500ED886F /* vmm_ioport.h */,\n\t\t\t\t3FB6519B1BF7CD4500ED886F /* vmm_ktr.h */,\n\t\t\t\t3FB6519C1BF7CD4500ED886F /* vmm_lapic.h */,\n\t\t\t\t3FB6519D1BF7CD4500ED886F /* vmm_mem.h */,\n\t\t\t\t3FB6519E1BF7CD4500ED886F /* vmm_stat.h */,\n\t\t\t\t3FB6519F1BF7CD4500ED886F /* vmm_util.h */,\n\t\t\t\t3FB651A01BF7CD4500ED886F /* x86.h */,\n\t\t\t);\n\t\t\tpath = vmm;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FB651861BF7CD4500ED886F /* intel */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB651871BF7CD4500ED886F /* vmcs.h */,\n\t\t\t\t3FB651881BF7CD4500ED886F /* vmx.h */,\n\t\t\t\t3FB651891BF7CD4500ED886F /* vmx_controls.h */,\n\t\t\t\t3FB6518A1BF7CD4500ED886F /* vmx_msr.h */,\n\t\t\t);\n\t\t\tpath = intel;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t3FB6518B1BF7CD4500ED886F /* io */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t3FB6518C1BF7CD4500ED886F /* vatpic.h */,\n\t\t\t\t3FB6518D1BF7CD4500ED886F /* vatpit.h */,\n\t\t\t\t3FB6518E1BF7CD4500ED886F /* vhpet.h */,\n\t\t\t\t3FB6518F1BF7CD4500ED886F /* vioapic.h */,\n\t\t\t\t3FB651901BF7CD4500ED886F /* vlapic.h */,\n\t\t\t\t3FB651911BF7CD4500ED886F /* vlapic_priv.h */,\n\t\t\t\t3FB651921BF7CD4500ED886F /* vpmtmr.h */,\n\t\t\t\t3FB651931BF7CD4500ED886F /* vrtc.h */,\n\t\t\t);\n\t\t\tpath = io;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tBE076A1326FE962A00C43411 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tBE076A1426FE962A00C43411 /* libz.1.tbd */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t3F1934911BF7C0D40099CC46 /* xhyve */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 3F1934991BF7C0D40099CC46 /* Build configuration list for PBXNativeTarget \"xhyve\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t3F3FFA981BF7CC1F004C89A1 /* xhyve-version.h */,\n\t\t\t\t3F19348E1BF7C0D40099CC46 /* Sources */,\n\t\t\t\t3F19348F1BF7C0D40099CC46 /* Frameworks */,\n\t\t\t\t3F1934901BF7C0D40099CC46 /* Install Man Pages */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = xhyve;\n\t\t\tproductName = xhyve;\n\t\t\tproductReference = 3F1934921BF7C0D40099CC46 /* xhyve */;\n\t\t\tproductType = \"com.apple.product-type.tool\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t3F19348A1BF7C0D40099CC46 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tDefaultBuildSystemTypeForWorkspace = Latest;\n\t\t\t\tLastUpgradeCheck = 1000;\n\t\t\t\tORGANIZATIONNAME = xhyve;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t3F1934911BF7C0D40099CC46 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.3;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 3F19348D1BF7C0D40099CC46 /* Build configuration list for PBXProject \"xhyve\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\ten,\n\t\t\t);\n\t\t\tmainGroup = 3F1934891BF7C0D40099CC46;\n\t\t\tproductRefGroup = 3F1934931BF7C0D40099CC46 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t3F1934911BF7C0D40099CC46 /* xhyve */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t3F3FFA981BF7CC1F004C89A1 /* xhyve-version.h */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"xhyve-version.h\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/bash;\n\t\t\tshellScript = \"${SRCROOT}/xcscripts/version.sh\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t3F19348E1BF7C0D40099CC46 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t3F3FFA751BF7C6A7004C89A1 /* pm.c in Sources */,\n\t\t\t\t3F3FFA721BF7C6A7004C89A1 /* pci_virtio_net_tap.c in Sources */,\n\t\t\t\t3F3FFA6F1BF7C6A7004C89A1 /* pci_lpc.c in Sources */,\n\t\t\t\t00D3D5BB2080044200DDCDF6 /* ps2kbd.c in Sources */,\n\t\t\t\t3F3FFA7C1BF7C6A7004C89A1 /* vmcs.c in Sources */,\n\t\t\t\t3F3FFA851BF7C6A7004C89A1 /* vrtc.c in Sources */,\n\t\t\t\t3F3FFA921BF7C6A7004C89A1 /* xmsr.c in Sources */,\n\t\t\t\t3F3FFA7A1BF7C6A7004C89A1 /* uart_emul.c in Sources */,\n\t\t\t\t3F3FFA8A1BF7C6A7004C89A1 /* vmm_instruction_emul.c in Sources */,\n\t\t\t\t3F3FFA841BF7C6A7004C89A1 /* vpmtmr.c in Sources */,\n\t\t\t\t3F3FFA801BF7C6A7004C89A1 /* vatpit.c in Sources */,\n\t\t\t\t3F3FFA901BF7C6A7004C89A1 /* x86.c in Sources */,\n\t\t\t\t3F3FFA631BF7C6A7004C89A1 /* kexec.c in Sources */,\n\t\t\t\t3F3FFA5F1BF7C6A7004C89A1 /* block_if.c in Sources */,\n\t\t\t\t00D3D5AF207C829600DDCDF6 /* console.c in Sources */,\n\t\t\t\t3F3FFA8E1BF7C6A7004C89A1 /* vmm_stat.c in Sources */,\n\t\t\t\t3F3FFA7F1BF7C6A7004C89A1 /* vatpic.c in Sources */,\n\t\t\t\t3F3FFA651BF7C6A7004C89A1 /* ioapic.c in Sources */,\n\t\t\t\t3F3FFA781BF7C6A7004C89A1 /* smbiostbl.c in Sources */,\n\t\t\t\t3F3FFA621BF7C6A7004C89A1 /* fbsd.c in Sources */,\n\t\t\t\t3F3FFA5E1BF7C6A7004C89A1 /* atkbdc.c in Sources */,\n\t\t\t\t3F3FFA6C1BF7C6A7004C89A1 /* pci_emul.c in Sources */,\n\t\t\t\t3F3FFA701BF7C6A7004C89A1 /* pci_uart.c in Sources */,\n\t\t\t\t3F3FFA7E1BF7C6A7004C89A1 /* vmx_msr.c in Sources */,\n\t\t\t\t3F3FFA5D1BF7C6A7004C89A1 /* acpitbl.c in Sources */,\n\t\t\t\t00D3D5B1207C82A200DDCDF6 /* pci_fbuf.c in Sources */,\n\t\t\t\t00D3D5B8207EAFF900DDCDF6 /* sockstream.c in Sources */,\n\t\t\t\t3F3FFA641BF7C6A7004C89A1 /* inout.c in Sources */,\n\t\t\t\t3F3FFA771BF7C6A7004C89A1 /* rtc.c in Sources */,\n\t\t\t\t3F3FFA8B1BF7C6A7004C89A1 /* vmm_ioport.c in Sources */,\n\t\t\t\t3F3FFA671BF7C6A7004C89A1 /* mem.c in Sources */,\n\t\t\t\t005C8E61208536B9009B0C6B /* pci_e82545.c in Sources */,\n\t\t\t\t3F3FFA8F1BF7C6A7004C89A1 /* vmm_util.c in Sources */,\n\t\t\t\t3F3FFA791BF7C6A7004C89A1 /* task_switch.c in Sources */,\n\t\t\t\t3F3FFA6B1BF7C6A7004C89A1 /* pci_ahci.c in Sources */,\n\t\t\t\t3F3FFA6E1BF7C6A7004C89A1 /* pci_irq.c in Sources */,\n\t\t\t\t3F3FFA8D1BF7C6A7004C89A1 /* vmm_mem.c in Sources */,\n\t\t\t\t3F3FFA7D1BF7C6A7004C89A1 /* vmx.c in Sources */,\n\t\t\t\t3F3FFA7B1BF7C6A7004C89A1 /* virtio.c in Sources */,\n\t\t\t\t3F3FFA611BF7C6A7004C89A1 /* dbgport.c in Sources */,\n\t\t\t\t00D3D5AD207C828900DDCDF6 /* bhyvegc.c in Sources */,\n\t\t\t\t3F3FFA6A1BF7C6A7004C89A1 /* mptbl.c in Sources */,\n\t\t\t\t3F3FFA6D1BF7C6A7004C89A1 /* pci_hostbridge.c in Sources */,\n\t\t\t\t00D3D5A6207C662200DDCDF6 /* bootrom.c in Sources */,\n\t\t\t\t3F3FFA881BF7C6A7004C89A1 /* vmm_callout.c in Sources */,\n\t\t\t\t3F3FFA811BF7C6A7004C89A1 /* vhpet.c in Sources */,\n\t\t\t\t3F3FFA861BF7C6A7004C89A1 /* vmm.c in Sources */,\n\t\t\t\t3F3FFA911BF7C6A7004C89A1 /* xhyve.c in Sources */,\n\t\t\t\t3F3FFA831BF7C6A7004C89A1 /* vlapic.c in Sources */,\n\t\t\t\t3F3FFA741BF7C6A7004C89A1 /* pci_virtio_rnd.c in Sources */,\n\t\t\t\t3F3FFA761BF7C6A7004C89A1 /* post.c in Sources */,\n\t\t\t\t00D3D5B5207C82B300DDCDF6 /* vga.c in Sources */,\n\t\t\t\t3F3FFA601BF7C6A7004C89A1 /* consport.c in Sources */,\n\t\t\t\t3F3FFA681BF7C6A7004C89A1 /* mevent.c in Sources */,\n\t\t\t\t00D3D5BC2080044200DDCDF6 /* ps2mouse.c in Sources */,\n\t\t\t\t3F3FFA8C1BF7C6A7004C89A1 /* vmm_lapic.c in Sources */,\n\t\t\t\t3F3FFA731BF7C6A7004C89A1 /* pci_virtio_net_vmnet.c in Sources */,\n\t\t\t\t3F3FFA891BF7C6A7004C89A1 /* vmm_host.c in Sources */,\n\t\t\t\t3F3FFA821BF7C6A7004C89A1 /* vioapic.c in Sources */,\n\t\t\t\t00D3D5B3207C82AB00DDCDF6 /* rfb.c in Sources */,\n\t\t\t\t3F3FFA711BF7C6A7004C89A1 /* pci_virtio_block.c in Sources */,\n\t\t\t\t3F3FFA871BF7C6A7004C89A1 /* vmm_api.c in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t3F1934971BF7C0D40099CC46 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3F3FF9E21BF7C5D5004C89A1 /* common_debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3F1934981BF7C0D40099CC46 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3F3FF9E01BF7C5D5004C89A1 /* common.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3F19349A1BF7C0D40099CC46 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3F3FF9E31BF7C5D5004C89A1 /* xhyve.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t3F19349B1BF7C0D40099CC46 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3F3FF9E31BF7C5D5004C89A1 /* xhyve.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t3F3FFA931BF7C7B1004C89A1 /* ASan */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3F3FF9E11BF7C5D5004C89A1 /* common_asan.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = ASan;\n\t\t};\n\t\t3F3FFA941BF7C7B1004C89A1 /* ASan */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 3F3FF9E31BF7C5D5004C89A1 /* xhyve.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = ASan;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t3F19348D1BF7C0D40099CC46 /* Build configuration list for PBXProject \"xhyve\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3F1934971BF7C0D40099CC46 /* Debug */,\n\t\t\t\t3F3FFA931BF7C7B1004C89A1 /* ASan */,\n\t\t\t\t3F1934981BF7C0D40099CC46 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t3F1934991BF7C0D40099CC46 /* Build configuration list for PBXNativeTarget \"xhyve\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t3F19349A1BF7C0D40099CC46 /* Debug */,\n\t\t\t\t3F3FFA941BF7C7B1004C89A1 /* ASan */,\n\t\t\t\t3F19349B1BF7C0D40099CC46 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 3F19348A1BF7C0D40099CC46 /* Project object */;\n}\n"
  },
  {
    "path": "xhyverun-freebsd.sh",
    "content": "#!/bin/sh\n\nBOOTVOLUME=\"<path of FreeBSD iso>\"\nIMG=\"<path of disk image for FreeBSD>\"\n\nPATH=\"build/Release:build:$PATH\"\n\nxhyve \\\n    -A \\\n    -m 2G \\\n    -c 2 \\\n    -s 0:0,hostbridge \\\n    -s 2:0,virtio-net \\\n    -s 3:0,ahci-cd,$BOOTVOLUME \\\n    -s 4:0,virtio-blk,$IMG \\\n    -s 31,lpc \\\n    -l com1,stdio \\\n    -f fbsd,test/userboot.so,$BOOTVOLUME,\"\"\n"
  },
  {
    "path": "xhyverun-tinycorelinux.sh",
    "content": "#!/bin/sh\n\nPATH=\"build/Release:build:$PATH\"\n\nxhyve \\\n    -A \\\n    -m 1G \\\n    -s 0:0,hostbridge \\\n    -s 31,lpc \\\n    -l com1,stdio \\\n    -f kexec,test/vmlinuz,test/initrd.gz,\"earlyprintk=serial console=ttyS0\"\n"
  },
  {
    "path": "xhyverun-windows.sh",
    "content": "#!/bin/sh\n\nBOOTVOLUME=\"<path of Windows iso>\"\nIMG=\"<path of disk image for Windows>\"\nFIRMWARE=\"<path of BHYVE_UEFI.fd>\"\n\nPATH=\"build/Release:build:$PATH\"\n\nxhyve \\\n    -w \\\n    -m 4G \\\n    -c 2 \\\n    -s 0:0,hostbridge \\\n    -s 3,ahci-cd,$BOOTVOLUME \\\n    -s 4,ahci-hd,$IMG \\\n   \t-s 5,e1000 \\\n    -s 29,fbuf,tcp=127.0.0.1:29000,w=1024,h=768,wait \\\n    -s 31,lpc -l com1,stdio \\\n    -l bootrom,$FIRMWARE\n\n"
  }
]